DNS challenge (ACME DNS-01)
DNS-01 proves domain control by publishing a TXT record. The only ACME challenge that works for wildcard certs and on hosts not reachable on port 80.
The ACME DNS-01 challenge proves you control a domain by publishing a TXT record at _acme-challenge.<domain> containing a digest the certificate authority can recompute. It is the only ACME challenge that can issue wildcard certificates, and the only one that works before the host is reachable on port 80.
That last property is why every custom-domain platform uses it. You can have a valid certificate waiting before your customer's traffic ever arrives.
The exact record
Per RFC 8555 section 8.4, the value is not the token. It is:
base64url( SHA-256( token "." base64url(Thumbprint(accountKey)) ) )
which comes out as 43 unpadded base64url characters. Two consequences people trip on:
- The same token gives different TXT values for different ACME accounts. You cannot copy a challenge value between environments.
- The record is a TXT record, not a CNAME or a URL.
_acme-challengeis a label, not a real host, and nothing ever resolves it for traffic.
Check what is published with dig or the TXT record lookup:
dig +short TXT _acme-challenge.example.com
Why wildcards force DNS-01, and the two-record trap
HTTP-01 validates one exact hostname by serving a file on it. There is no file you can serve that proves control over *.example.com, so the CA will not accept it. DNS-01 asks the zone instead, and control of the zone is control of every name under it.
The trap: a certificate covering both example.com and *.example.com produces two separate challenges, both answered at the same name _acme-challenge.example.com. They need two TXT records coexisting at that label. Automation that "sets" the record instead of appending overwrites the first with the second, and the order fails half-validated. If you have ever seen a SAN certificate request stall on exactly one identifier, this is usually why.
CNAME delegation is the part that makes DNS-01 safe
Let's Encrypt is blunt about the downside of DNS-01: "putting your full DNS API credentials on your web server significantly increases the impact if that web server is hacked." A DNS API token that can write your zone can also rewrite your MX records and your A records.
The fix is delegation, and it is officially supported: you may use CNAME or NS records to point _acme-challenge at a zone you control separately.
_acme-challenge.example.com. IN CNAME example-com.acme.validation.net.
The resolver follows the CNAME, the CA reads the TXT at the target, and the credential that writes the actual challenge only ever has access to validation.net. Your production zone holds one static CNAME that never changes again.
This is also the mechanism behind every custom-domain product. When a platform asks your customer to add a _acme-challenge CNAME alongside their CNAME record, it is doing exactly this: taking over challenge answering so it can renew that customer's certificate forever without ever holding a credential to the customer's zone. The customer sets two records once. The platform handles provisioning and renewal after that.
One thing to watch: a delegated _acme-challenge CNAME pointing at a validation zone you have since torn down is a dangling DNS record. If someone else can claim that target, they can answer challenges for your hostname. Delete the CNAME when you stop using the platform, the same discipline that prevents subdomain takeover.
Pin the method with CAA, before you have to
CAA records already let you say which CAs may issue for your domain. RFC 8657 adds two parameters that most zones do not use yet:
accounturirestricts issuance to one specific ACME account.validationmethodsrestricts it to specific challenge types, for exampledns-01only.
example.com. IN CAA 0 issue "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/12345"
Together they mean a stolen web server cannot mint a certificate over HTTP-01, and an unrelated ACME account cannot issue at all. The CA/Browser Forum voted in May 2026 to make honouring these parameters mandatory for every CA from March 2027, so support is about to stop being best-effort.
For reference, here is what two real zones publish today, read straight out of DNS on 2026-08-19:
| Zone | CAA policy |
|---|---|
cloudflare.com | five CAs across issue and issuewild, several with cansignhttpexchanges=yes, plus an iodef mailto for violation reports |
github.com | four CAs for issue (Let's Encrypt, DigiCert, Sectigo, GlobalSign) but only three for issuewild, so GlobalSign may not issue its wildcards |
domainee.dev | none |
That last row is honest and common. Most zones, ours included, publish no CAA at all, which means any public CA may issue. A single issue record is the cheapest security control in DNS, and neither of the two useful RFC 8657 parameters appears in either of the real-world examples above yet.
Negative caching is why your first poll costs you an hour
The most common DNS-01 failure is not a wrong record. It is an ACME client that queried _acme-challenge before publishing it.
That query returns NXDOMAIN, and under RFC 2308 a resolver may cache that negative answer for the lesser of the SOA record's own TTL and its MINIMUM field. Publishing the TXT a second later does not clear it. The CA's resolver keeps saying "no such record" until the negative entry expires.
Measured against 1.1.1.1 on 2026-08-19:
| Zone | DNS host | SOA TTL | SOA MINIMUM | Effective negative cache |
|---|---|---|---|---|
cloudflare.com | Cloudflare | 300 | 300 | 300s |
shopify.com | Foundation DNS | 300 | 300 | 300s |
stripe.com | Route 53 | 900 | 3600 | 900s |
porkbun.com | Route 53 | 900 | 86400 | 900s |
domainee.dev | Cloudflare | 1786 | 1800 | ~1800s |
vercel.com | Vercel DNS | 3600 | 14400 | 3600s |
godaddy.com | GoDaddy | 3600 | 3600 | 3600s |
namecheap.com | Namecheap | 3600 | 3600 | 3600s |
Two things fall out of that. Route 53 zones look alarming if you only read MINIMUM (86400, a full day), but RFC 2308's "lesser of" rule caps them at the SOA's 900-second TTL, so the common warning about day-long Route 53 stalls is wrong. GoDaddy and Namecheap genuinely do sit at a full hour.
So the rule is simple: publish first, then poll, and never poll a name you have not written yet. Good clients wait for the record to be visible on the zone's own authoritative nameservers before telling the CA to validate, which sidesteps recursive resolver caching entirely. If you are debugging one that does not, the DNS propagation checker shows you which resolvers are still holding the stale answer.
Your record now has to be visible from several continents
Since 15 March 2025 the CA/Browser Forum Baseline Requirements have required Multi-Perspective Issuance Corroboration: CAs must confirm domain control from multiple network vantage points, not one. Since 15 September 2025 they must refuse to issue when those perspectives disagree.
For DNS-01 this changes the failure mode. A TXT record that is live on one nameserver but not the others, or a GeoDNS setup that answers differently by region, used to be a coin flip and now reliably fails. Validate against the zone globally, not from the box running the ACME client.
The rate limits that actually bind
Let's Encrypt's published limits, current as of August 2026:
| Limit | Value |
|---|---|
| Certificates per registered domain | 50 per 7 days |
| Duplicate certificates (identical name set) | 5 per 7 days |
| New orders per account | 300 per 3 hours |
| Failed validations per identifier per account | 5 per hour |
| Accounts per IP | 10 per 3 hours |
For a multi-tenant custom domains platform, the 50-per-registered-domain limit almost never bites, because each customer domain is its own registered domain with its own budget. It bites hard the moment you issue per-tenant certificates for subdomains of your domain: tenant1.app.com, tenant2.app.com and so on all draw from one bucket of 50 per week. The five-failed-validations-per-hour limit is the one that turns a misconfigured retry loop into an outage.
Where this sits in a custom-domain flow
The customer points a CNAME at your edge and adds the _acme-challenge delegation. Your platform answers the challenge in its own zone, receives the certificate, and the edge then selects it per connection by SNI. None of that requires access to the customer's DNS zone, which is the whole reason the delegation pattern exists.
Domainee is a custom domains API for SaaS with a native MCP server — 50 domains and 100 GB free. It runs the DNS-01 delegation and renewal loop above for every connected hostname. The Cloudflare SSL for SaaS setup guide walks the build-it-yourself version, and connecting custom domains to your SaaS covers the customer-facing flow.
FAQ
Does DNS-01 work for wildcard certificates?
Yes, and it is the only challenge that does. A CA will not accept HTTP-01 for *.example.com because no single hostname can demonstrate control of every name under the zone. DNS-01 queries the zone itself, which does.
What is the difference between DNS-01 and HTTP-01?
HTTP-01 serves a token file over port 80 on the exact hostname being validated. DNS-01 publishes a TXT record at _acme-challenge instead, so it works behind firewalls, before the host has any traffic, and for wildcards. The cost is that it needs write access to DNS, which is why delegation matters.
How long does DNS-01 validation take? Publishing is instant; the wait is DNS. Budget the record's TTL, and be aware that a premature lookup can pin a negative answer for the lesser of the zone's SOA TTL and MINIMUM, which we measured at 300 to 3,600 seconds across eight major DNS hosts. Well-behaved clients confirm the record on the authoritative nameservers before asking the CA to validate.
Can I do DNS-01 without giving an ACME client access to my DNS?
Yes. CNAME _acme-challenge.example.com to a label in a separate zone and let the client write there. Your production zone then holds one static record that never changes, and a compromised ACME client cannot touch your MX or A records. This is exactly what custom-domain platforms ask your customers to do.
Why does my wildcard order validate one name and fail the other?
A certificate covering both the apex and the wildcard needs two TXT records at the same _acme-challenge label at the same time. Automation that replaces rather than appends leaves only the second one, so the first identifier never validates.
Does a CAA record block DNS-01?
Not by itself, but it can be made to. RFC 8657 adds validationmethods and accounturi parameters to CAA, so you can permit dns-01 only, or restrict issuance to a single ACME account. The CA/Browser Forum has made honouring them mandatory for all CAs from March 2027.