traefik/traefik
ACME provider
ACME (RFC 8555) is the protocol Let's Encrypt and other public CAs use to issue certificates. Traefik bundles an ACME client built on github.com/go-acme/lego/v4 and exposes it as a "certificate resolver" in static configuration.
Source
pkg/provider/acme/:
| File | Role |
|---|---|
provider.go |
The 40k-byte heart: state machine, domain extraction, renewal, message emission. |
account.go |
ACME account creation and persistence. |
challenge_http.go |
HTTP-01 challenge handler exposed at the acme-http@internal route. |
challenge_tls.go |
TLS-ALPN-01 challenge served via the TLS manager. |
local_store.go |
JSON-on-disk persistence of account and certificates. |
local_store_unix.go, local_store_windows.go |
Platform-specific file locking. |
store.go |
The interface implemented by local_store. |
provider_test.go |
Unit tests covering domain extraction and renewal logic. |
The DNS-01 challenge support is delegated to Lego, which ships providers for dozens of DNS APIs.
Configuration
certificatesResolvers:
letsencrypt:
acme:
email: ops@example.com
caServer: https://acme-v02.api.letsencrypt.org/directory
storage: /letsencrypt/acme.json
keyType: EC256
tlsChallenge: {}
# or:
httpChallenge:
entryPoint: web
# or:
dnsChallenge:
provider: route53
delayBeforeCheck: 0
resolvers: ['1.1.1.1:53']A router opts in by setting tls.certResolver: letsencrypt. The provider observes which domains are needed by inspecting active routers.
Lifecycle
graph TD
Static[static config] --> Provider[ACME Provider]
Watcher[Configuration watcher] -->|active routers + domains| Provider
Provider --> NeedsCert{certificate missing or expiring?}
NeedsCert -->|yes| Lego[lego client]
Lego -->|HTTP-01| HTTP[challenge_http.go]
Lego -->|TLS-ALPN-01| TLS[challenge_tls.go]
Lego -->|DNS-01| DNS[Lego DNS plugin]
HTTP --> Cert[certificate]
TLS --> Cert
DNS --> Cert
Cert --> Store[local_store.go]
Cert --> Emit[dynamic.Message<br/>tls.Certificates]
Emit --> Watcher
Watcher --> TLSManager[pkg/tls/tlsmanager.go]The provider is both a listener (it watches the configuration to know which domains it must serve) and a producer (it emits a dynamic.Configuration containing the resolved certificates).
Renewal
provider.go runs a periodic renewal job. A certificate is renewed when:
- It is within 30 days of expiry by default (configurable).
- The list of SANs has changed (i.e. a new domain became required and the cert needs to cover it).
Failed renewals are retried with exponential backoff. The previous certificate keeps serving until the renewal succeeds.
Storage
local_store.go writes one JSON file per resolver — typically /letsencrypt/acme.json. The file contains:
- The ACME account (private key + registration URL).
- The list of issued certificates (PEM-encoded private key and certificate, SANs, resolver name).
The file is read at startup and rewritten atomically (temp file + rename) on every change. Permissions are checked at startup; the file must be 0600 to avoid leaking the account key.
DNS-01
DNS-01 challenges are essential for wildcard certificates. Traefik supports them via Lego's plugin set: Route 53, Cloudflare, Gandi, GCP Cloud DNS, Azure DNS, DigitalOcean, Vultr, OVH, and many more — all selected by the resolver's dnsChallenge.provider value. Each plugin reads its credentials from environment variables documented in Lego's README.
DNS-01 has its own quirks:
delayBeforeCheck— wait this long before checking that the TXT record propagated.resolvers— explicit DNS resolvers to use for propagation checks.disablePropagationCheck— escape hatch for environments where the check fails for benign reasons.
HTTP-01 and the internal route
When the HTTP-01 challenge is enabled, the provider injects a router named acme-http@internal that intercepts /.well-known/acme-challenge/* on the configured entry point. The actual handler is in challenge_http.go. After a successful challenge, the router can be left in place — it returns 404 for non-challenge paths.
TLS-ALPN-01 and the TLS manager
The TLS-ALPN-01 challenge is served on port 443 via a special tls.Config returned by the TLS manager. challenge_tls.go registers a temporary certificate with the manager keyed by the challenge name; the manager hands it back during the handshake of the validating CA's connection.
Tests
pkg/provider/acme/provider_test.go— domain extraction, renewal-due logic, account handling.pkg/provider/acme/local_store_test.go— persistence and locking.integration/acme_test.go— end-to-end against a Pebble (Let's Encrypt staging) container.
Practical notes
- Always start against
caServer: https://acme-staging-v02.api.letsencrypt.org/directoryto avoid hitting Let's Encrypt's rate limits during development. - Storage is a single JSON file. For production, persist it on a volume that survives container restarts. Multiple Traefik instances must share the same file or use a key-value store via a separate persistence layer.
- HTTP-01 requires port 80 to be reachable from the CA. If you front Traefik with another load balancer, route
/.well-known/acme-challenge/*to Traefik. - TLS-ALPN-01 requires port 443. It does not interfere with normal TLS termination.
- For wildcard certificates, only DNS-01 is allowed by Let's Encrypt.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.