Back to Blog

DNS-01 Challenge Deep Dive: How Let's Encrypt Validates Domain Ownership

A comprehensive guide to the DNS-01 ACME challenge — how it works, when to use it over HTTP-01, step-by-step setup with major DNS providers, and troubleshooting tips for wildcard certificates.

DNS-01ACME challengeLet's Encryptwildcard SSLDNS validationSSL certificatesHTTPS

If you've ever set up a wildcard SSL certificate with Let's Encrypt, you've encountered the DNS-01 challenge. It's the most powerful ACME validation method — and also the trickiest to get right. While HTTP-01 gets most of the attention (and works for 90% of use cases), DNS-01 unlocks capabilities that HTTP-01 simply can't provide.

This guide goes deep into how DNS-01 works, when you need it, how to set it up with popular DNS providers, and how to debug it when things go wrong.

What Is the DNS-01 ACME Challenge?

The DNS-01 challenge is one of three validation methods defined by the ACME (Automatic Certificate Management Environment) protocol, which Let's Encrypt uses to automate certificate issuance. To prove you control a domain, Let's Encrypt asks you to place a specific DNS TXT record at _acme-challenge.<your-domain>.

Here's the flow at a high level:

  1. Your ACME client (Certbot, acme.sh, or similar) generates a token and asks Let's Encrypt to challenge your domain
  2. The client creates a TXT record at _acme-challenge.example.com with a specific validation value
  3. Let's Encrypt queries the DNS system for that TXT record
  4. If the record matches what was expected, you've proven domain control
  5. Let's Encrypt issues the certificate

The critical difference from HTTP-01: DNS-01 works for domains that don't serve HTTP traffic, including wildcard domains, internal services, and load balancers.

DNS-01 vs HTTP-01: When to Use Each

Feature HTTP-01 DNS-01
Wildcard cert support ❌ No ✅ Yes (*.example.com)
Port 80 requirement ✅ Required ❌ Not needed
Public web server ✅ Required ❌ Not needed
Automation complexity 🔵 Simple 🔴 Moderate
Propagation delay None (instant) Minutes to hours (TTL-dependent)
Multi-domain certs ✅ Yes ✅ Yes
Internal/hidden services ❌ No ✅ Yes
DNS provider API needed ❌ No ✅ Yes

When to Use HTTP-01

HTTP-01 is the simplest option. It requires your web server to be publicly accessible on port 80. Let's Encrypt places a file at http://<domain>/.well-known/acme-challenge/<token> and requests it back. You should default to HTTP-01 unless you specifically need DNS-01 features.

When You Need DNS-01

DNS-01 is essential for these scenarios:

  • Wildcard certificates: Only DNS-01 can validate *.example.com because the challenge covers all subdomains at once
  • No public web server: Internal services, CI/CD runners, or servers behind firewalls that don't serve HTTP
  • Load balancers: When HTTPS terminates at a load balancer but you need to validate the origin domain
  • Multi-server setups: One DNS validation covers all servers, no need to copy challenge files

Step-by-Step: Setting Up DNS-01 with Let's Encrypt

Prerequisites

Before you begin, you need:

  • A domain where you control the DNS settings
  • API access to your DNS provider (or manual DNS record creation)
  • An ACME client installed (we'll use acme.sh and certbot)

Option 1: Using acme.sh (Recommended for Automation)

acme.sh supports 150+ DNS providers out of the box. Here's the workflow for Cloudflare (the most popular):

# Install acme.sh
curl https://get.acme.sh | sh

# Set Cloudflare API credentials
export CF_Token="your-cloudflare-api-token"
export CF_Zone_ID="your-zone-id"

# Issue a wildcard certificate
acme.sh --issue --dns dns_cf -d example.com -d '*.example.com'

# Install to your web server
acme.sh --install-cert -d example.com \
  --key-file /etc/ssl/example.com/key.pem \
  --fullchain-file /etc/ssl/example.com/fullchain.pem \
  --reloadcmd "systemctl reload nginx"

The --dns dns_cf flag tells acme.sh to use the Cloudflare DNS API. It automatically creates and removes the TXT record — no manual DNS changes needed.

Option 2: Using Certbot with DNS Plugins

Certbot offers DNS plugins for major providers. Install the plugin for your provider:

# For Cloudflare
sudo apt install python3-certbot-dns-cloudflare

# Create credentials file
sudo mkdir -p /etc/letsencrypt
sudo tee /etc/letsencrypt/cloudflare.ini > /dev/null << 'EOF'
dns_cloudflare_api_token = your-cloudflare-api-token
EOF
sudo chmod 600 /etc/letsencrypt/cloudflare.ini

# Issue certificate
sudo certbot certonly --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
  -d example.com -d '*.example.com'

Option 3: Manual DNS (for Testing or One-Off Use)

If you can't use an API, you can do it manually:

# Certbot shows you the TXT record value
certbot certonly --manual --preferred-challenges dns -d '*.example.com'

# It will prompt you to create a TXT record at:
# _acme-challenge.example.com with a specific value

Create the TXT record in your DNS provider's panel, wait for propagation, then press Enter to continue.

DNS Providers: API Setup Comparison

Provider ACME Client Support API Auth Method Propagation Time Notes
Cloudflare acme.sh, Certbot, Lego API Token 30-60s Fastest, best documentation
AWS Route53 acme.sh, Certbot, Lego IAM keys 60-120s Requires IAM permissions
Google Cloud DNS acme.sh, Certbot, Lego Service Account 60-180s Needs dns.changes.create permission
DigitalOcean acme.sh, Certbot API Token 60-120s Simple API, good for small setups
Namecheap acme.sh API Key 2-5 min Manual setup required in panel
GoDaddy acme.sh, Lego API Key + Secret 2-5 min Slower propagation
CloudNS / Custom acme.sh (generic) dns_myapi hook Varies DIY with API scripting

Pro tip: For production wildcard certificates, use a centralized certificate dashboard to track all your Let's Encrypt certs across multiple DNS providers in one place. No more logging into each DNS panel to check renewal status.

Troubleshooting Common DNS-01 Issues

Even with proper setup, DNS-01 can fail. Here are the most common issues and how to fix them.

TXT Record Not Found

Let's Encrypt's validation servers couldn't find your TXT record. Common causes:

# Debug: Check if the record propagated
dig _acme-challenge.example.com TXT +short

# Check from Let's Encrypt's perspective
dig @8.8.8.8 _acme-challenge.example.com TXT +short

Solutions: Wait for DNS propagation (especially with high TTLs), verify you created the record in the correct zone, or temporarily lower the TTL to 60 seconds before validation.

API Rate Limits

Let's Encrypt enforces rate limits: 50 certificates per registered domain per week, and 5 failed authorizations per account per hour per hostname. DNS-01 failures count against these limits.

Solutions: Use staging environment (--dry-run flag) for testing, cache successful validations, and spread renewals across different hours.

Permissions Errors with DNS Provider API

Your API token doesn't have the right permissions. Cloudflare tokens need Zone:DNS:Edit; AWS IAM needs route53:ChangeResourceRecordSets.

Solutions: Verify token permissions in your provider's dashboard. For Cloudflare, create a custom token scoped to specific zones with DNS Edit permission.

Propagation Delays

Some DNS providers take minutes to propagate changes globally. If your ACME client times out waiting, you'll see "failed to validate" errors.

Solutions: Use acme.sh which waits for propagation by default, or increase the sleep delay in your client:

# acme.sh: set custom propagation seconds
export ACME_DNS_SLEEP=120

Automation: DNS-01 + Cron = Set and Forget

The real power of DNS-01 is full automation. With API-based DNS validation, you can set up auto-renewal that never requires manual intervention:

# acme.sh auto-upgrade and auto-renew
acme.sh --upgrade --auto-upgrade
acme.sh --renew-all

# Add to cron (acme.sh does this automatically on install)
# 0 0 * * * /root/.acme.sh/acme.sh --renew-all --quiet > /dev/null

For wildcard certificates with automated DNS-01 renewal, pair your ACME client with a monitoring dashboard like CertPilot to get alerts if a renewal fails and visibility into all your certificates' expiry dates.

DNS-01 Security Considerations

DNS-01 is powerful, but it introduces security trade-offs:

  • API token exposure: Anyone with your DNS API token can issue certificates for your domains
  • Longer-lived validation: DNS records persist after validation unless cleaned up
  • DNS provider compromise: If your DNS provider is breached, an attacker can issue certs for your domains

Mitigation: Use scoped API tokens with minimal permissions (Zone:DNS:Edit only), rotate tokens regularly, enable the cleanup hook in your ACME client to remove TXT records, and monitor certificate issuance via Certificate Transparency logs. Most ACME clients handle cleanup automatically — just ensure the feature is enabled.

Summary

The DNS-01 challenge is the only ACME validation method that supports wildcard certificates, works without a public web server, and can be fully automated across hundreds of domains. While it requires more setup than HTTP-01 — you need DNS provider API access and need to handle propagation delays — the flexibility it provides is unmatched.

For most production setups, the sweet spot is using HTTP-01 for single-domain certificates (simpler, no API dependencies) and DNS-01 for wildcard certificates and internal services. With modern ACME clients like acme.sh or Certbot with DNS plugins, the setup is a one-time effort that pays off in hands-off renewal forever.


Want to see all your certificates in one place? CertPilot gives you a free dashboard to track expiry, manage renewals, and monitor free and paid certificates across all your domains. Also check out our guide on free vs paid SSL certificates to understand when each option makes sense.

Related Articles