Let's Encrypt DNS-01 Challenges with DNScale
Automate Let's Encrypt certificate issuance and renewal with DNS-01 challenges using DNScale. Works for wildcard certificates, edge-proxied origins, and servers with no public port 80.
TL;DR
ACME DNS-01 proves you control a domain by publishing a `_acme-challenge.<name>` TXT record that the CA verifies. Required for wildcard certificates (HTTP-01 can't validate wildcards), works for any server regardless of port-80 reachability, and integrates cleanly with private/internal hosts. Use a zone-scoped DNScale API token so the ACME client has minimum access. Common clients: certbot, lego, acme.sh, cert-manager — all have first-party DNScale plugins or use the standard provider interface.
What you'll learn
- Understand when DNS-01 is the right ACME challenge type and when HTTP-01 is simpler
- Set up Let's Encrypt with DNScale using certbot, lego, acme.sh, or cert-manager
- Scope API tokens correctly so ACME clients have the minimum access they need
- Avoid common pitfalls — propagation timeouts, CNAME delegation, CAA conflicts
Let's Encrypt supports three ACME challenge types: HTTP-01, TLS-ALPN-01, and DNS-01. For most public websites, HTTP-01 is the default because it's simple — a file on port 80 proves you control the domain. But when HTTP-01 doesn't fit, DNS-01 is the escape hatch: instead of proving control via HTTP, you prove it by placing a TXT record in DNS.
DNScale's API lets any ACME client automate DNS-01 challenges against your zones. This guide covers when to use DNS-01, and how to set it up with the four most common Let's Encrypt clients.
When to use DNS-01
HTTP-01 breaks in four common situations:
- Wildcard certificates (
*.example.com). Let's Encrypt does not support HTTP-01 for wildcards — DNS-01 is the only option. - Servers behind edge proxies or CDNs. If your origin sits behind a proxy (DNScale's Postscale edge network, Cloudflare, an ADC, etc.) the origin can't receive HTTP-01 validation traffic. DNS-01 bypasses the data plane entirely.
- No port 80 exposed. Firewalled origins, internal services, mail servers, and hosts behind strict NATs often have no public HTTP listener. DNS-01 needs no HTTP endpoint.
- Private or internal hostnames that still resolve publicly (split-horizon DNS, lab environments). HTTP-01 can't reach them; DNS-01 only needs DNS reachability for the ACME validator.
If none of those apply, HTTP-01 is usually simpler — fewer moving parts, no API token to manage. DNS-01 is worth the extra setup only when you need it.
Tip: DNS-01 plays nicely with CAA records. Set
0 issue "letsencrypt.org"on your zone, and Let's Encrypt will be the only CA that can issue for it regardless of challenge type.
How DNS-01 works
For each domain on a certificate request, Let's Encrypt asks the client to publish a TXT record at _acme-challenge.<domain> containing a specific value. The ACME validator then queries public DNS for that record. If the value matches, the challenge passes.
Your ACME client drives three steps on each issuance or renewal:
- Add — create the TXT record via the DNScale API
- Wait — give the record time to propagate across DNScale's authoritative nameservers
- Clean up — delete the TXT record after validation completes
All four clients covered below automate this flow end-to-end.
API token setup
Before any client can use DNS-01, create a DNScale API token:
- Sign in at app.dnscale.eu.
- Go to API Keys and create a new key.
- Grant the minimum scopes:
zones:read,records:read,records:write. - Scope the key to specific zones if you can — e.g. only
example.comif that's the only domain the client will renew.
Store the token as you would any other secret: a file with mode 600, a secret manager, or an environment variable in your CI/CD pipeline. Never check it into a public repository.
Tip: Separate tokens per client. If certbot and cert-manager both issue certs on different hosts, use two tokens so you can rotate one without disrupting the other.
Client: certbot
The certbot-dns-dnscale plugin is published on PyPI.
pip install certbot-dns-dnscaleCreate the credentials file:
# /etc/letsencrypt/dnscale.ini
dns_dnscale_api_token = <your-token>chmod 600 /etc/letsencrypt/dnscale.iniIssue a certificate:
certbot certonly \
--authenticator dns-dnscale \
--dns-dnscale-credentials /etc/letsencrypt/dnscale.ini \
--dns-dnscale-propagation-seconds 60 \
-d example.com \
-d "*.example.com"Subsequent renewals (certbot renew) automatically use the same authenticator — certbot stores the choice in /etc/letsencrypt/renewal/<name>.conf.
To convert an existing certificate from HTTP-01 to DNS-01, edit its renewal config:
[renewalparams]
authenticator = dns-dnscale
dns_dnscale_credentials = /etc/letsencrypt/dnscale.ini
dns_dnscale_propagation_seconds = 60Remove any webroot_path, standalone, or [[webroot_map]] leftover from the old authenticator.
Client: lego (including Caddy and Traefik)
Lego is the ACME library used by Caddy, Traefik, and the lego CLI. DNScale is available as a built-in DNS provider.
lego CLI:
DNSCALE_API_TOKEN=<your-token> lego \
--dns dnscale \
--domains example.com \
--domains "*.example.com" \
--email you@example.com \
runCaddy (Caddyfile):
example.com, *.example.com {
tls {
dns dnscale {env.DNSCALE_API_TOKEN}
}
reverse_proxy localhost:8080
}Set DNSCALE_API_TOKEN in Caddy's environment (systemd unit or container env).
Traefik (static config):
certificatesResolvers:
letsencrypt:
acme:
email: you@example.com
storage: /data/acme.json
dnsChallenge:
provider: dnscale
delayBeforeCheck: 60And set DNSCALE_API_TOKEN in Traefik's environment.
Client: acme.sh
The DNScale API plugin ships with acme.sh.
export DNSCALE_Token=<your-token>
acme.sh --issue --dns dns_dnscale -d example.com -d "*.example.com"acme.sh saves the token to ~/.acme.sh/account.conf on first use, so subsequent renewals don't need the env var. To rotate, edit that file or pass --renew-with-dnsapi dns_dnscale on the next renewal.
Client: cert-manager (Kubernetes)
For Kubernetes workloads, DNScale's cert-manager webhook plugs into cert-manager's external webhook interface.
-
Install the webhook via Helm:
helm install cert-manager-webhook-dnscale \ oci://ghcr.io/dnscaleou/charts/cert-manager-webhook-dnscale \ --namespace cert-manager -
Store the token as a Kubernetes secret:
apiVersion: v1 kind: Secret metadata: name: dnscale-api-token namespace: cert-manager stringData: api-token: <your-token> -
Define a ClusterIssuer referencing the webhook:
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-dnscale spec: acme: email: you@example.com server: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: name: letsencrypt-dnscale-account-key solvers: - dns01: webhook: groupName: acme.dnscale.eu solverName: dnscale config: apiTokenSecretRef: name: dnscale-api-token key: api-token -
Request a certificate as usual — cert-manager will drive DNS-01 through the webhook.
Common pitfalls
Propagation too short
ACME validators cache DNS. If your client's "wait for propagation" is shorter than the TTL of negative caches and nearby resolvers, validation will fail. Start at 60 seconds. If you see intermittent failures, raise to 120.
CNAME delegation
If _acme-challenge.example.com is a CNAME to another name (a common pattern for delegating DNS-01 to a separate zone), the ACME validator follows the CNAME — but your ACME client must publish the TXT at the target of the CNAME, not at _acme-challenge.example.com itself. All four clients above handle this automatically if configured with the correct zone.
CAA blocking Let's Encrypt
If your zone has a 0 issue "other-ca.com" CAA record and no entry for letsencrypt.org, Let's Encrypt will refuse to issue. Before moving a domain to DNS-01, confirm CAA allows the CA you're using:
dig CAA example.com +shortOrphan _acme-challenge.* TXT records
If cleanup fails silently (API error, plugin bug, client crash) the challenge TXT record may linger on your zone. These don't affect future issuance (every renewal uses a fresh random value), but they can clutter the zone over time. Periodically delete any _acme-challenge.* TXT records older than a few hours.
Rate limits
Let's Encrypt limits 50 certificates per registered domain per week and 5 duplicate certs per week. DNS-01 doesn't change these limits — but if your client is stuck in a retry loop (e.g. a misconfigured propagation wait causing repeated failures) you can burn through the duplicate cert limit quickly. Always run --dry-run first when changing client or zone setup.
Which client should you pick?
- Standalone host with a single cert — certbot. Familiar, well-documented, ships in every distro.
- Caddy or Traefik already in your stack — use the built-in lego integration. No extra daemon.
- Minimal, shell-only host — acme.sh. No Python, no compiled binary, just bash.
- Kubernetes — cert-manager with the DNScale webhook.
Any of them works end-to-end with DNScale. Pick by where the rest of your infrastructure already sits.
Frequently asked questions
- When should I use DNS-01 instead of HTTP-01?
- Three cases: (1) wildcard certificates — HTTP-01 can't validate wildcards, DNS-01 can; (2) internal hosts not reachable from the public internet — DNS-01 only needs DNS, not port 80; (3) a fleet of servers behind a load balancer where centralising cert issuance is easier than coordinating per-host HTTP-01 challenges. For a single public web server with port 80 available, HTTP-01 is simpler.
- Why do I need a CAA record alongside Let's Encrypt?
- Strictly, you don't — Let's Encrypt issues to any domain that passes ACME validation, with or without CAA. But CAA is a defence-in-depth: it constrains *which* CAs may issue for your domain, so a compromised CA elsewhere can't issue a rogue certificate. Add `0 issue "letsencrypt.org"` to authorize Let's Encrypt; combine with iodef for incident reporting.
- How do I scope a DNScale API token for ACME?
- Create a zone-scoped API key for the specific zone(s) the ACME client manages. The client only needs permission to create and delete TXT records under `_acme-challenge.*` — not to modify other records or manage other zones. Zone-scoping limits the blast radius if the token is leaked. See the DNScale dashboard's API-key creation flow.
- What happens if propagation is slow and the challenge times out?
- Some ACME clients add a configurable propagation wait before signalling 'ready' to the CA. lego: `--dns.propagation-wait 60s`; certbot's DNScale plugin has equivalent settings. If your TTL is reasonable (60–300s) and your DNS provider propagates promptly, defaults work. For very large or geographically-distributed setups, increase the wait.
- Can I delegate `_acme-challenge` to a separate provider?
- Yes — the CNAME-delegation pattern. Add a CNAME at `_acme-challenge.example.com` pointing to a name on a different zone (typically a dedicated `acme.example.com` subzone) where the ACME client has write access. Useful when your main zone is locked down or managed by a different team. Let's Encrypt and most ACME clients follow CNAMEs during validation.
Ready to manage your DNS with confidence?
DNScale provides anycast DNS hosting with a global network, real-time analytics, and an easy-to-use API.
Start free