Let's Encrypt wildcard SSL certificate: getting one through DNS-01

7 min readUpdated

Let's Encrypt issues wildcard certificates, and only through the DNS-01 challenge [1]. A Let's Encrypt certificate for *.example.com is an ACME certificate like any other except for one step: your client proves control of the domain with a TXT record in its DNS, because HTTP-01 and TLS-ALPN-01 cannot validate a wildcard name [2]. So settle who can write to your DNS, and how, before you pick a client.

Challenge
DNS-01 only; HTTP-01 and TLS-ALPN-01 cannot be used for a wildcard [2]
Record
TXT at _acme-challenge.example.com [2][5]
Covers
one label below the domain, such as shop.example.com; not eu.shop.example.com [6]
Root domain
not covered by the wildcard; example.com goes in the same order as a second name [5][6]
DNS access
an API the client can call unattended, at issuance and at renewal [2]
With Certbot
a DNS plugin, installed separately, or the manual plugin [4]

Why only DNS-01 can validate a wildcard

The order carries the identifier *.example.com, and the authorization the server returns is for example.com, without the *., marked "wildcard": true, as defined in RFC 8555 §7.1.3 [5]. At Let's Encrypt the only challenge that can satisfy that authorization is DNS-01 [2].

DNS-01 runs in four steps, per RFC 8555 §8.4 [5]:

  1. The client builds a key authorization from the challenge token and its account key, and takes its SHA-256 digest.

  2. It publishes the base64url form of that digest as a TXT record at _acme-challenge.example.com.

  3. It tells the server it is ready by posting an empty JSON object, {}, to the challenge URL (§7.5.1).

  4. Let's Encrypt queries DNS for the record and checks that one of the TXT records at that name matches [2][5].

Ordering the wildcard and the root domain together

A wildcard does not cover its own base domain: *.example.com matches shop.example.com but not example.com, because, in the words of RFC 9525 §6.3, a wildcard "can only match one label" [6]. If the site also answers on the bare domain, the order lists two identifiers: example.com and *.example.com [5].

That order produces two authorizations for the same base name, example.com: one plain, one marked as a wildcard [5]. Each has its own challenge token, so with DNS-01 for both, two different TXT values sit at the same name, _acme-challenge.example.com, when both challenges are answered together. Let's Encrypt accepts several TXT records at one name and gives this case as its example: a wildcard and a non-wildcard certificate validated at the same time [2].

  1. Publish both values side by side. A client or script that overwrites the record with the second value before the first is validated breaks the first authorization, since the server looks for its own value among the TXT records at the name [5].

  2. Tell the server you are ready only after each authoritative server returns both values.

  3. Remove both after validation. Let's Encrypt asks for old TXT records to be cleaned up, because it starts rejecting the response once it gets too big [2].

Getting the wildcard with Certbot

Let's Encrypt recommends starting with Certbot [1], and Certbot covers a wildcard with its DNS plugins or with the manual plugin, both through DNS-01 [4]. The Certbot documentation calls DNS validation "the only way to obtain wildcard certificates from Let's Encrypt" [4].

  • A DNS plugin. The plugin proves control of the domain by modifying its DNS records for you. DNS plugins are not part of a default Certbot installation and are installed separately [4].

  • The manual plugin. certonly with --manual and --preferred-challenges dns prints the value of the TXT record for you to publish by hand [4].

certbot certonly --manual --preferred-challenges dns -d example.com -d '*.example.com'

Without --cert-name, Certbot names the certificate after the first domain given, and a wildcard in first place becomes example.com; the files go under /etc/letsencrypt/live/example.com/ unless a certificate of that name already exists [4]. Installing Certbot and the rest of its commands are a walkthrough of their own.

Keeping DNS credentials off the web server

Let's Encrypt recommends narrowly scoped credentials, or validation from a separate server that copies the certificate over [2]. Full DNS API credentials on a web server increase the impact if that server is hacked [2].

Delegation is the third way. Let's Encrypt follows CNAME and NS records when it looks up the TXT record, so _acme-challenge.example.com can point into a zone used only for validation [2]. The client then needs write access to that validation zone only, not to the zone that holds the site's records. The same trick helps when your DNS provider is slow to update: delegate to a server that updates faster [2].

Before telling Let's Encrypt to validate

Before you trigger validation, ask each authoritative server directly for the record. dig @server name type sends the query to the server you name, and +short prints a terse answer [7]:

dig +short NS example.com
dig +short TXT _acme-challenge.example.com @ns1.example.com

With the root domain in the order, the second command should print two quoted values on every server listed by the first. If _acme-challenge.example.com is delegated by CNAME or NS records, run the second command against the servers of the validation zone instead, because the values are checked there [2]. Validation also needs port 53 open, TCP and UDP, inbound to your authoritative DNS servers [3].

Most DNS providers have a propagation time, the delay before an update is available on all of their servers, and with anycast the server you reach may not be the one Let's Encrypt reaches [2]. Some DNS APIs report when an update has fully propagated; without that, the client has to wait long enough before it triggers validation [2].

Renewing a Let's Encrypt wildcard

Renewal repeats the issuance process [8], so the DNS step has to run without you. Let's Encrypt may skip validation while an authorization from an earlier issuance is still cached for your account [1]; when it does ask, the new challenge comes with a new token and a new TXT value [5].

That is where a manual setup stops. Without hooks, a --manual certificate does not renew automatically: each renewal needs new TXT records copied by hand, so it cannot run from a cron job [4]. A DNS plugin keeps renewal unattended, and so does --manual-auth-hook with a script that sets up the TXT record, paired with --manual-cleanup-hook to remove it afterwards [4].

FAQ

Does Let's Encrypt support wildcard certificates?

Yes. Let's Encrypt issues wildcard certificates, and wildcard issuance must use the DNS-01 challenge. [1]

Does a Let's Encrypt wildcard cover the root domain?

No. A wildcard certificate for *.example.com matches one label below example.com, such as shop.example.com, and not example.com itself, so put both names in the same order. [5][6]

Can I get a Let's Encrypt wildcard with HTTP validation?

No. HTTP-01 cannot be used to issue wildcard certificates, and TLS-ALPN-01 cannot validate wildcard domains either. [2]

Do I need a DNS provider with an API?

For unattended issuance and renewal, yes: Let's Encrypt says DNS-01 makes sense for automation only where the DNS provider has an API. Without one, _acme-challenge can be delegated with a CNAME to a zone that has one. [2]

Sources

  1. Let's Encrypt, FAQ: wildcard issuance through DNS-01, Certbot as the starting client, cached authorizations.

  2. Let's Encrypt, Challenge Types: HTTP-01, DNS-01, TLS-ALPN-01; DNS API, credentials, CNAME and NS delegation, propagation, several TXT records at one name.

  3. Let's Encrypt, Integration Guide: inbound port 53, TCP and UDP, to authoritative DNS servers.

  4. Certbot User Guide: DNS plugins, manual plugin, --preferred-challenges, hooks, certificate name.

  5. RFC 8555, Automatic Certificate Management Environment (ACME): §7.1.3, §7.5.1, §8.4.

  6. RFC 9525, Service Identity in TLS: §6.3.

  7. BIND 9 manual pages, dig: @server, query type, +short.

  8. Let's Encrypt, How It Works: renewal repeats the issuance process.