Automating SSL Certificates with Traefik and Let's Encrypt
Learn how to configure Traefik to automatically handle SSL/TLS certificates using Let's Encrypt, including Docker Compose setup and ACME resolver verification.
29 Apr 2026, 03:35 UTC

The Problem: Manual Certificate Management
Managing SSL/TLS certificates manually often leads to service outages when certificates expire or configuration errors during manual renewals. For teams deploying multiple microservices, updating individual certificates across several containers is inefficient.
The solution is to use Traefik's built-in ACME (Automated Certificate Management Environment) provider. This allows Traefik to act as the TLS termination point, automatically requesting, renewing, and applying certificates from Let's Encrypt based on the routing rules of your services.
Prerequisites
- A server with a public IP address and Docker installed.
- A registered domain name with DNS records pointing to your server's public IP.
- Ports 80 (HTTP) and 443 (HTTPS) open on your firewall to allow the ACME HTTP-01 challenge.
- Traefik v2.x (this guide assumes v2.10 or compatible versions).
Step 1: Prepare the Certificate Store
Traefik stores certificates in a JSON file. Because this file contains private keys, it must have strict permissions (600) to prevent the ACME provider from rejecting it for security reasons.
# Run these commands on the host machine
touch acme.json
chmod 600 acme.json
Step 2: Configure the Static Configuration
The static configuration defines the entry points and the certificate resolver. You can do this via a traefik.yml file or command-line flags in Docker Compose. Using flags is often simpler for small to medium deployments.
In your docker-compose.yml, define the Traefik service with these specific arguments:
services:
traefik:
image: traefik:v2.10
command:
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
- "--certificatesresolvers.myresolver.acme.email=[contact removed]"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
ports:
- "80:80"
- "443:443"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./acme.json:/letsencrypt/acme.json"
Step 3: Apply TLS to a Backend Service
To trigger the certificate request, you must tell the router for a specific service to use the resolver defined in the static config (myresolver).
Add these labels to your application service in the docker-compose.yml:
services:
my-app:
image: nginx:alpine
labels:
- "traefik.enable=true"
- "traefik.http.routers.myapp.rule=Host(`app.example.com`)"
- "traefik.http.routers.myapp.entrypoints=websecure"
- "traefik.http.routers.myapp.tls.certresolver=myresolver"
- "traefik.http.services.myapp.loadbalancer.server.port=80"
Verification and Diagnostics
Once you run docker-compose up -d, Traefik will attempt to negotiate the TLS challenge with Let's Encrypt.
1. Log Inspection
Check the Traefik container logs for successful issuance. Run this on the host:
docker logs traefik | grep "Successfully obtained certificate"
2. Connection Test
Use curl to verify the certificate chain is valid and matches your domain:
curl -vI https://app.example.com
Look for SSL certificate verify ok in the output.
3. Storage Check
Inspect the acme.json file. If the file size is greater than 0 and contains a LastRenewal timestamp, the certificate is stored and will be automatically renewed before expiration.
Comparison: HTTP-01 vs TLS-ALPN-01
| Challenge Type | Requirement | Best Use Case |
|---|---|---|
| HTTP-01 | Port 80 must be open | Standard web servers |
| TLS-ALPN-01 | Port 443 must be open | Environments where port 80 is blocked |
Limitations and Risks
- Rate Limits: Let's Encrypt imposes strict limits on how many certificates can be issued per domain per week. Avoid frequent restarts or configuration changes in staging; use the Let's Encrypt staging server for testing.
- Persistence: If the
acme.jsonfile is deleted or the volume is not persisted, Traefik will request new certificates on every restart, quickly hitting rate limits.
Rollback Procedure
If the ACME configuration causes routing loops or failures, remove the TLS labels from the application service and the --certificatesresolvers flags from the Traefik command. Restart the containers to return to plain HTTP routing.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.