Traefik's Built-in Let's Encrypt: Picking the Right ACME Challenge for Your Network
Traefik can issue and renew Let's Encrypt certificates automatically, but the choice between HTTP-01 and DNS-01 challenges determines whether it works behind a firewall or in containers.
15 May 2026, 01:36 UTC

The problem: certificates expire, deployments stall
Every public HTTPS service needs a certificate, and every certificate expires. If you rotate them by hand, a routine deployment turns into a two-part job: publish the service, then remember to swap the certificate before browsers start throwing warnings. Traefik's built-in ACME support removes the second half of that job by requesting certificates from Let's Encrypt automatically. The engineering decision is not whether to automate, but which proof-of-ownership method your network can actually support.
How Traefik's ACME integration fits together
ACME (Automated Certificate Management Environment) is the protocol Let's Encrypt uses to verify that you control a domain before issuing a certificate. In Traefik, you enable it by defining a certResolver in the static configuration. The resolver holds the ACME account email, the storage path for certificates, and the challenge settings. Once the resolver exists, individual routers opt in by referencing its name—usually through a label such as traefik.http.routers.myapp.tls.certresolver=le.
Certificates and account keys are written to a JSON file, conventionally named acme.json. Traefik treats this file as sensitive state: it contains private keys, so it should be persisted to a volume and restricted to the proxy process.
HTTP-01: the default when Traefik owns port 80
The HTTP-01 challenge is the simplest to deploy. Let's Encrypt makes a plain HTTP request to http://your-domain/.well-known/acme-challenge/<token>, and Traefik answers it directly. The only hard requirement is that the Traefik instance is reachable from the public internet on port 80 for the domain in question. If Traefik sits behind a NAT, cloud load balancer, or corporate firewall that blocks inbound port 80, this challenge will fail.
Below is a minimal Docker Compose pattern that wires Traefik to a backend service using HTTP-01. Run it from a shell on a host where ports 80 and 443 are free; the user needs permission to bind those ports and to manage Docker containers.
# docker-compose.yml
services:
traefik:
image: traefik:<pinned-version>
command:
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.le.acme.httpchallenge=true"
- "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.le.acme.email=[contact removed]"
- "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
volumes:
- "./letsencrypt:/letsencrypt"
app:
image: traefik/whoami
labels:
- "traefik.http.routers.app.rule=Host(`app.example.com`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls.certresolver=le"
Replace <pinned-version> with a specific Traefik release tag rather than latest, and change app.example.com to a domain whose DNS A record already points at this host. After starting the stack, Traefik contacts Let's Encrypt, completes the challenge, and writes the certificate to ./letsencrypt/acme.json. The service should then be reachable over HTTPS.
DNS-01: when port 80 is not an option
If Traefik cannot receive inbound HTTP traffic—because it runs on a private network, behind a CDN, or inside a cluster without host networking—the DNS-01 challenge is the alternative. Instead of answering an HTTP request, Traefik creates a temporary TXT record in your domain's DNS zone through a provider API. Let's Encrypt queries that record to confirm control.
DNS-01 also supports wildcard certificates (for example, *.example.com), which HTTP-01 cannot issue. The trade-off is operational: you must supply API credentials with write access to your DNS zone. A leaked Cloudflare or Route 53 token can be used to hijack DNS, so those credentials belong in a secret manager or environment variable, never in a committed configuration file.
What Traefik handles automatically
Once a resolver is configured, Traefik manages the certificate lifecycle without operator intervention. It renews certificates well before expiration—commonly around 30 days ahead of the 90-day Let's Encrypt validity window—and swaps them into the TLS entrypoint without restarting the proxy. The integration also negotiates modern TLS versions, including TLS 1.3 where the client supports it, rather than relying on hand-tuned cipher lists.
Limits worth planning around
Let's Encrypt enforces issuance rate limits. Excessive failures or bulk domain requests can trigger a cooldown, so it pays to test configuration against the staging endpoint before pointing at production. For DNS-01, the credential risk described above is real: restrict the API token to the narrowest possible zone permissions.
Multi-instance deployments need extra care. If two Traefik instances both try to obtain a certificate for the same domain using separate storage files, they can race or exceed duplicate-certificate limits. Coordinating through a shared ACME account and distributed storage—or fronting the instances with a single certificate manager—avoids that class of problem.
A quick way to verify it is working
You do not need to wait 90 days to confirm the integration is healthy. Check that acme.json exists in the configured storage path and contains valid JSON. Then run curl -v https://app.example.com from an external machine; a successful response with a valid certificate chain means issuance and renewal plumbing are in place. Finally, scan Traefik's access and application logs for ACME-related entries—errors there usually indicate a blocked port 80, expired DNS credentials, or a rate-limit cooldown.
If the certificate file is missing or the HTTPS request fails, the fastest diagnostic is to confirm that port 80 is reachable from the internet (for HTTP-01) or that the DNS provider API is returning success (for DNS-01). Fix the underlying reachability problem, and Traefik will retry on its own.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.