Chapter 8intermediate

TLS & ACME

Automatic TLS with ACME

Traefik has built-in ACME support for automatic TLS certificate management. It can automatically obtain and renew certificates from Let's Encrypt or any ACME-compatible CA.

What is ACME?

ACME (Automatic Certificate Management Environment) is a protocol for automating certificate issuance and renewal. Let's Encrypt is the most popular ACME CA, and it's free.

ACME Configuration

yaml
certificatesResolvers:
  letsencrypt:
    acme:
      email: admin@example.com
      storage: /letsencrypt/acme.json
      caServer: "https://acme-v02.api.letsencrypt.org/directory"  # Production
      # caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"  # Staging

      # Choose one challenge type:
      httpChallenge:
        entryPoint: web

      # OR
      # tlsChallenge: {}

      # OR
      # dnsChallenge:
      #   provider: route53

ACME Challenge Types

HTTP-01 Challenge

The most common and simplest. Let's Encrypt validates by sending an HTTP request to http://<domain>/.well-known/acme-challenge/.

yaml
certificatesResolvers:
  letsencrypt:
    acme:
      httpChallenge:
        entryPoint: web     # Port 80 entrypoint MUST be open

HTTP-01 Requirements

  • Port 80 must be publicly accessible
  • The web entrypoint (port 80) must exist — even with http.redirections.entryPoint.to: websecure
  • Does NOT support wildcard certificates

TLS-ALPN-01 Challenge

Validates via TLS handshake on port 443. No separate port needed.

yaml
certificatesResolvers:
  letsencrypt:
    acme:
      tlsChallenge: {}

TLS-ALPN-01 Benefits

  • Only needs port 443 (no port 80 required)
  • Works behind TCP load balancers that forward TLS
  • More stealthy — no .well-known endpoint exposed
  • Still doesn't support wildcards

DNS-01 Challenge

Validates via DNS TXT records. Required for wildcard certificates.

yaml
certificatesResolvers:
  letsencrypt:
    acme:
      dnsChallenge:
        provider: route53           # AWS Route53
        delayBeforeCheck: 0
        resolvers:
          - "1.1.1.1:53"
          - "8.8.8.8:53"

DNS-01 Providers

Traefik supports 30+ DNS providers: route53, cloudflare, gcloud, digitalocean, azure, ovh, hetzner, linode, duckdns, acme-dns, and many more. Each requires environment variables with API credentials.

Wildcard Certificates

yaml
routers:
  app:
    rule: "Host(`*.example.com`)"
    tls:
      certResolver: letsencrypt     # Must use DNS-01 challenge

Router TLS Configuration

yaml
http:
  routers:
    secure-app:
      rule: "Host(`example.com`)"
      service: app
      tls:
        certResolver: letsencrypt    # Which ACME resolver
        options: my-tls-options@file # TLS options
        domains:
          - main: example.com
            sans:
              - www.example.com
              - api.example.com

The tls field on a router enables TLS termination for that router. Without it, the router serves plain HTTP. Routers on an HTTPS entrypoint MUST have tls: {} at minimum.

Custom Certificates (Non-ACME)

You can also provide certificates manually:

yaml
tls:
  certificates:
    - certFile: /etc/traefik/certs/example.pem
      keyFile: /etc/traefik/certs/example-key.pem
      stores:
        - default

  stores:
    default:
      defaultCertificate:
        certFile: /etc/traefik/certs/default.pem
        keyFile: /etc/traefik/certs/default-key.pem

TLS Options

Fine-tune TLS security:

yaml
tls:
  options:
    default:
      minVersion: VersionTLS12
      maxVersion: VersionTLS13
      cipherSuites:
        - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
      sniStrict: false
      preferServerCipherSuites: true

    modern:
      minVersion: VersionTLS13
      sniStrict: true

    mtls-only:
      clientAuth:
        caFiles:
          - /etc/traefik/certs/ca.pem
        clientAuthType: RequireAndVerifyClientCert

Default TLS Options

Traefik uses a safe default TLS configuration. Only override if you have specific compliance requirements (PCI-DSS, HIPAA, etc.) or need mTLS.

Mutual TLS (mTLS)

yaml
tls:
  options:
    mtls:
      clientAuth:
        caFiles:
          - /etc/traefik/certs/ca.pem
        clientAuthType: RequireAndVerifyClientCert
      minVersion: VersionTLS12

http:
  routers:
    internal-api:
      rule: "Host(`api.internal.example.com`)"
      service: api-service
      tls:
        options: mtls

Certificate Storage

ACME certificates are stored in a JSON file:

json
{
  "letsencrypt": {
    "Account": { ... },
    "Certificates": [
      {
        "Domain": { "Main": "example.com", "SANs": ["www.example.com"] },
        "Certificate": "...base64...",
        "Key": "...base64..."
      }
    ]
  }
}

Certificate Backup

Always back up your acme.json file. If lost, you'll be rate-limited by Let's Encrypt when requesting replacement certificates. Store it in a secure, backed-up location.

Staging vs Production

Always test with Let's Encrypt staging first:

yaml
certificatesResolvers:
  letsencrypt-staging:
    acme:
      caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
      email: admin@example.com
      storage: /letsencrypt/acme-staging.json
      httpChallenge:
        entryPoint: web

Let's Encrypt has rate limits: 50 certificates per domain per week. Staging has much higher limits. Always test with staging first, then switch to production.

Troubleshooting ACME

Common issues:

IssueCauseSolution
acme: error: 403HTTP-01: domain unreachableCheck port 80 is open and no redirect interferes
acme: error: 429Rate limitedWait a week or use staging
Certificate not renewingACME storage path wrongCheck storage path is writable
DNS challenge timeoutDNS propagation delayIncrease delayBeforeCheck
Wrong certificate servedSNI mismatchCheck Host rule matches certificate domain

Next Chapter

Learn about Observability — metrics, logging, and tracing with Traefik.