Guide for setting up Traefik with AWS Route53 for automated TLS certificate management using DNS challenges. This minimal configuration eliminates the need for separate configuration as you can have all that in the compose file, apart for a volume and store of the acme.json which will store the saved generated certificates.
Requirements
Before starting, ensure you have:
- AWS account with Route53 access
- Domain managed in Route53
- Docker and Docker Compose installed
- Basic understanding of AWS IAM policies
AWS IAM Configuration
Create an IAM account called arn:aws:iam::123456789012:user/letsencrypt-dnsChallange and apply the policy arn:aws:iam::123456789012:policy/letsencrypt-dnsChallange to it.
Change 123456789012 to your account id obviously…
- Create an IAM user:
letsencrypt-dns-challenge - Generate access keys for programmatic access
- Attach the custom policy below
IAM Policy Configuration
Create a policy with these permissions (replace Z064682SAMPLEYS04I0D with your actual hosted zone ID):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:GetChange",
"route53:ListHostedZones",
"route53:ListHostedZonesByName"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"route53:ChangeResourceRecordSets",
"route53:ListResourceRecordSets"
],
"Resource": "arn:aws:route53:::hostedzone/Z064682SAMPLEYS04I0D",
"Condition": {
"ForAllValues:StringLike": {
"route53:ChangeResourceRecordSetsNormalizedRecordNames": [
"_acme-challenge.*"
],
"route53:ChangeResourceRecordSetsRecordTypes": [
"TXT"
],
"route53:ChangeResourceRecordSetsActions": [
"UPSERT",
"DELETE"
]
}
}
}
]
}
- Record Name Restriction: Only allows modifications to
_acme-challenge.*records, preventing changes to your main domain records - Record Type Limitation: Restricts operations to TXT records only, which are used for DNS challenges
- Action Limitation: Only permits UPSERT (create/update) and DELETE operations, blocking other potentially dangerous actions
- Principle of Least Privilege: Grants only the minimum permissions needed for Let’s Encrypt DNS challenges
This prevents potential security issues if your AWS credentials are compromised, as an attacker cannot modify your main domain records or create other types of DNS records.
Find your hosted zone ID in the Route53 console under your domain’s details.
Complete Docker Compose Configuration
This self-contained setup includes Traefik v3 with all configuration via command-line arguments:
networks:
traefik:
services:
traefik:
image: traefik:v3
container_name: traefik
security_opt:
- no-new-privileges:true
restart: always
networks:
- traefik
ports:
- 80:80
- 443:443
- 8443:8443 # Dashboard access
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /some_volume/traefik/acme:/etc/traefik/acme/
environment:
- TZ=Europe/Stockholm
- AWS_ACCESS_KEY_ID=YOUR_AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY=YOUR_AWS_SECRET_ACCESS_KEY
- AWS_HOSTED_ZONE_ID=YOUR_HOSTED_ZONE_ID_HERE
- AWS_REGION=eu-west-1
dns:
- 1.1.1.1
- 1.0.0.1
command:
# Enable the Traefik dashboard and API
- --api.dashboard=true
- --log.level=INFO
- --entrypoints.https.address=:443
- --entrypoints.traefik.address=:8443
- --entrypoints.http.address=:80
- --providers.docker=true
- --providers.docker.exposedByDefault=false
- --serversTransport.insecureSkipVerify=true
- --serversTransport.maxIdleConnsPerHost=5
- --serversTransport.forwardingTimeouts.idleConnTimeout=60s
# Route53 ACME configuration
- --[email protected]
- --certificatesResolvers.route53.acme.caServer=https://acme-v02.api.letsencrypt.org/directory
# For testing, use staging first: --certificatesResolvers.route53.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory
- --certificatesResolvers.route53.acme.storage=/etc/traefik/acme/route53.json
- --certificatesResolvers.route53.acme.dnsChallenge.provider=route53
- --certificatesResolvers.route53.acme.dnsChallenge.disablePropagationCheck=false
- --certificatesResolvers.route53.acme.dnsChallenge.delayBeforeCheck=10
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`traefik.yourdomain.com`)"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.routers.traefik.entrypoints=traefik"
- "traefik.http.routers.traefik.tls=true"
- "traefik.http.routers.traefik.tls.certresolver=route53"
- "traefik.http.routers.traefik.tls.domains[0].main=yourdomain.com"
- "traefik.http.routers.traefik.tls.domains[0].sans=*.yourdomain.com"
Service Configuration
Add TLS certificates to any service with these labels:
some-service:
image: some-service:1.0.0
networks:
- traefik
labels:
- "traefik.enable=true"
- "traefik.http.routers.some-service.rule=Host(`service.yourdomain.com`)"
- "traefik.http.routers.some-service.entrypoints=https"
- "traefik.http.routers.some-service.tls=true"
- "traefik.http.routers.some-service.tls.certresolver=route53"
- "traefik.http.services.some-service.loadbalancer.server.port=3030"
Testing with Staging Environment
Important: Before deploying to production, test your configuration with Let’s Encrypt staging to avoid hitting rate limits:
Comment out the production server line and uncomment the staging line:
# - --certificatesResolvers.route53.acme.caServer=https://acme-v02.api.letsencrypt.org/directory - --certificatesResolvers.route53.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directoryTest your setup completely with staging certificates
Once verified, switch back to production server and restart Traefik
Delete the staging
acme.jsonfile before switching to production
This prevents hitting Let’s Encrypt’s rate limits (50 certificates per week) during testing.
And your’e done!
Buy Me a Coffee