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…

  1. Create an IAM user: letsencrypt-dns-challenge
  2. Generate access keys for programmatic access
  3. 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:

  1. 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/directory
    
  2. Test your setup completely with staging certificates

  3. Once verified, switch back to production server and restart Traefik

  4. Delete the staging acme.json file 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