diff --git a/cmd/flags.go b/cmd/flags.go index 2322e4eb..902d3526 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -104,7 +104,8 @@ func CreateFlags(defaultPath string) []cli.Flag { }, &cli.StringSliceFlag{ Name: "dns.resolvers", - Usage: "Set the resolvers to use for performing recursive DNS queries." + + Usage: "Set the resolvers to use for performing (recursive) CNAME resolving and apex domain determination." + + " For DNS challenge verification, the authoritative DNS server is queried directly." + " Supported: host:port." + " The default is to use the system resolvers, or Google's DNS resolvers if the system's cannot be determined.", }, diff --git a/docs/content/usage/cli/Options.md b/docs/content/usage/cli/Options.md index bdc62ac2..8d7e105e 100644 --- a/docs/content/usage/cli/Options.md +++ b/docs/content/usage/cli/Options.md @@ -40,10 +40,48 @@ lego to listen on that interface:port for any incoming challenges. If you are using this option, make sure you proxy all of the following traffic to these ports. -**HTTP Port:** All plaintext HTTP requests to port **80** which begin with a request path of `/.well-known/acme-challenge/` for the HTTP challenge.[^header] +**HTTP Port:** All plaintext HTTP requests to port **80** which begin with a request path of `/.well-known/acme-challenge/` for the HTTP challenge[^header]. **TLS Port:** All TLS handshakes on port **443** for the TLS-ALPN challenge. This traffic redirection is only needed as long as lego solves challenges. As soon as you have received your certificates you can deactivate the forwarding. [^header]: You must ensure that incoming validation requests contains the correct value for the HTTP `Host` header. If you operate lego behind a non-transparent reverse proxy (such as Apache or NGINX), you might need to alter the header field using `--http.proxy-header X-Forwarded-Host`. + +## DNS Resolvers and Challenge Verification + +When using a DNS challenge provider (via `--dns `), Lego tries to ensure the ACME challenge token is properly setup before instructing the ACME provider to perform the validation. + +This involves a few DNS queries to different servers: + +1. Determining the DNS zone and resolving CNAMEs. + + The DNS zone for a given domain is determined by the SOA record, which contains the authoritative name server for the domain and all its subdomains. + For simple domains like `example.com`, this is usually `example.com` itself. + For other domains (like `fra.eu.cdn.example.com`), this can get complicated, as `cdn.example.com` may be delegated to the CDN provider, which means for `cdn.example.com` must exist a different SOA record. + + To find the correct zone, Lego requests the SOA record for each DNS label (starting on the leaf domain, i.e. the left-most DNS label). + If there is no SOA record, Lego requests the SOA record of the parent label, then for its parent, etc., until it reaches the apex domain[^apex]. + Should any DNS label on the way be a CNAME, it is resolved as per usual. + + In the default configuration, Lego uses the system name servers for this, and falls back to Google's DNS servers, should they be absent. + +2. Verifying the challenge token. + + The `_acme-challenge.` TXT record must be correctly installed. + Lego verifies this by directly querying the authoritative name server for this record (as detected in the previous step). + +Strictly speaking, this verification step is not necessary, but helps to protect your ACME account. +Remember that some ACME providers impose a rate limit on certain actions (at the time of writing, Let's Encrypt allows 300 new certificate orders per account per 3 hours). + +There are also situations, where this verification step doesn't work as expected: + +- A "split DNS" setup gives different answers to clients on the internal network (Lego) vs. on the public internet (Let's Encrypt). +- With "hidden master" setups, Lego may be able to directly talk to the primary DNS server, while the `_acme-challenge` record might not have fully propagate to the (public) secondary servers, yet. + +The effect is the same: Lego determined the challenge token to be installed correctly, while Let's Encrypt has a different view, and rejects the certificate order. + +In these cases, you can instruct Lego to use a different DNS resolver, using the `--dns.resolvers` flag. +You should prefer one on the public internet, otherwise you might be susceptible to the same problem. + +[^apex]: The apex domain is the domain you have registered with your domain registrar. For gTLDs (`.com`, `.fyi`) this is the 2nd level domain, but for ccTLDs, this can either be the 2nd level (`.de`) or 3rd level domain (`.co.uk`). diff --git a/docs/data/zz_cli_help.toml b/docs/data/zz_cli_help.toml index 87ced52f..c02f0739 100644 --- a/docs/data/zz_cli_help.toml +++ b/docs/data/zz_cli_help.toml @@ -25,7 +25,7 @@ GLOBAL OPTIONS: --dns value Solve a DNS challenge using the specified provider. Can be mixed with other types of challenges. Run 'lego dnshelp' for help on usage. --dns-timeout value Set the DNS timeout value to a specific value in seconds. Used only when performing authoritative name servers queries. (default: 10) --dns.disable-cp By setting this flag to true, disables the need to wait the propagation of the TXT record to all authoritative name servers. (default: false) - --dns.resolvers value [ --dns.resolvers value ] Set the resolvers to use for performing recursive DNS queries. Supported: host:port. The default is to use the system resolvers, or Google's DNS resolvers if the system's cannot be determined. + --dns.resolvers value [ --dns.resolvers value ] Set the resolvers to use for performing (recursive) CNAME resolving and apex domain determination. For DNS challenge verification, the authoritative DNS server is queried directly. Supported: host:port. The default is to use the system resolvers, or Google's DNS resolvers if the system's cannot be determined. --domains value, -d value [ --domains value, -d value ] Add a domain to the process. Can be specified multiple times. --eab Use External Account Binding for account registration. Requires --kid and --hmac. (default: false) --email value, -m value Email used for registration and recovery contact.