Choosing the Right ACME Challenge in Traefik Proxy
Traefik’s ACME resolver automates certificate handling, but choosing HTTP‑01, DNS‑01, or TLS‑ALPN‑01 is a critical decision. This guide explains the trade‑offs, shows a working HTTP‑01 example, and offers a checklist to avoid common pitfalls.
08 Jul 2025, 22:23 UTC

Problem: Which ACME challenge should I use?
Traefik’s built‑in ACME resolver automatically requests, serves, and renews Let’s Encrypt certificates. That convenience hides a core engineering decision: the challenge type you pick. Choosing HTTP‑01, DNS‑01, or TLS‑ALPN‑01 determines network requirements, the ability to issue wildcard certificates, and how your infrastructure must be configured.
Decision Factors
- Network visibility – HTTP‑01 requires that port 80 be publicly reachable to Traefik. TLS‑ALPN‑01 needs a clear 443 path that isn’t terminated before Traefik. DNS‑01 bypasses IP restrictions entirely.
- Certificate scope – Only DNS‑01 can issue wildcard certificates (e.g.,
*.example.com). HTTP‑01 and TLS‑ALPN‑01 issue per‑hostname certificates. - Operational complexity – HTTP‑01 is provider‑agnostic but may fail behind CDNs or firewalls. DNS‑01 requires a DNS provider that exposes an API and a secure token. TLS‑ALPN‑01 is rarely used because most setups terminate TLS before the proxy.
- Rate limits – Let’s Encrypt enforces strict limits per IP and per account. A misconfigured resolver that repeatedly attempts issuance can quickly exhaust your quota.
Concrete Example: HTTP‑01 with Docker‑Compose
Below is a minimal, reproducible setup that demonstrates how Traefik automatically completes the HTTP‑01 challenge and serves a valid certificate. Use the Let’s Encrypt staging CA to avoid hitting production limits during testing.
# traefik.yml – static configuration
entryPoints:
http:
address: :80
websecure:
address: :443
certificatesResolvers:
myresolver:
acme:
email: admin@
storage: /traefik/acme.json
caServer: https://acme-staging-v02.api.letsencrypt.org/directory
httpChallenge:
entryPoint: http
# docker-compose.yml – dynamic configuration via labels
services:
traefik:
image: traefik:v3.0
command: --providers.docker --entrypoints.http.address=:80 --entrypoints.websecure.address=:443
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./acme.json:/traefik/acme.json
restart: unless-stopped
app:
image: nginx:latest
labels:
- "traefik.http.routers.app.rule=Host(`app.`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls=true"
- "traefik.http.routers.app.tls.certResolver=myresolver"
restart: unless-stopped
Before running docker compose up -d make sure acme.json exists and has 0600 permissions:
touch acme.json
chmod 600 acme.json
After Traefik starts, it will request a certificate for app.. To verify:
openssl s_client -connect app.:443 -servername app. -showcerts | openssl x509 -noout -issuer -subject
The issuer should be Let's Encrypt Authority X3 (Staging) if you used the staging CA. Once the certificate is in place, subsequent restarts will load it from acme.json rather than re‑requesting.
Trade‑Offs and Limitations
- HTTP‑01: Simple, no secrets, but requires direct access to port 80. It cannot issue wildcards and will silently fail if a firewall or CDN blocks the challenge path.
- DNS‑01: The only method that supports wildcards and works when port 80 is closed. It demands a provider‑specific token with write access to DNS records, which must be stored securely (e.g., Kubernetes Secret or Vault). Propagation delays can add minutes to the issuance process.
- TLS‑ALPN‑01: Uses port 443 and is useful when you can’t expose 80 but can terminate TLS directly on Traefik. It’s rarely needed and not supported by all providers.
A common pitfall is mismatching the resolver name in the router label. If tls.certResolver refers to a non‑existent resolver, Traefik will simply never obtain a certificate, which looks like a network issue. Test this by intentionally using a wrong name and observing the dashboard logs.
Actionable Checklist
- Determine if port 80 can be exposed. If yes, start with HTTP‑01.
- For wildcard support or blocked 80, choose DNS‑01 and obtain a provider API token.
- Set
acme.json(or Kubernetes Secret) to0600and keep it in version control only if it’s encrypted. - Use the Let’s Encrypt staging CA during local or CI testing.
- Verify the certificate chain with
openssl s_clientbefore exposing the domain to users. - Monitor Traefik logs for “issued certificate” messages and for any repeated challenge failures.
By aligning the challenge type with your network topology and certificate needs, you avoid silent failures and keep your TLS configuration simple and maintainable.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.