Let’s Encrypt can issue certificates for your domains automatically, but only if it can prove you control them.

Imagine you’re running Traefik as your edge router, and you want to get TLS certificates for example.com and www.example.com using Let’s Encrypt. Traefik, when configured for ACME, acts as the client to the Let’s Encrypt CA. The CA needs to verify that you actually own the domain names you’re requesting certificates for. This verification happens through a "challenge" process.

Here’s what that looks like in practice. Let’s say you have Traefik running, and it’s configured to manage certificates for your domains. When Traefik starts up or when a certificate is due for renewal, it initiates the ACME process.

# Traefik static configuration (traefik.yml)
entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: "websecure"
          scheme: "https"
  websecure:
    address: ":443"

certificatesResolvers:
  myresolver:
    acme:
      email: "admin@example.com"
      storage: "acme.json"
      httpChallenge:
        entryPoint: "web"

In this configuration, Traefik is set up to listen on ports 80 and 443. The web entrypoint (port 80) is configured to redirect all HTTP traffic to HTTPS (websecure on port 443). The certificatesResolvers section defines how Traefik will obtain certificates. myresolver is the name of our resolver, and it’s configured to use ACME. The email is for Let’s Encrypt notifications, and storage specifies where the obtained certificates will be saved. Crucially, httpChallenge tells Traefik to use the HTTP-01 challenge method, and it will perform this challenge on the web entrypoint.

When Let’s Encrypt wants to verify example.com, it will send an HTTP request to http://example.com/.well-known/acme-challenge/some-token. Traefik, listening on port 80, intercepts this request. It then generates a response that includes the some-token provided by Let’s Encrypt, along with a specific key. Traefik serves this response back to Let’s Encrypt. If the response is correct, Let’s Encrypt knows that the server at example.com can respond to requests on port 80, which implies control over the domain.

Let’s see this in action with a hypothetical Traefik container and a simple docker-compose.yml:

# docker-compose.yml
version: '3.7'

services:
  traefik:
    image: traefik:v2.10
    container_name: traefik
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik.yml:/etc/traefik/traefik.yml
      - ./acme.json:/acme.json
    networks:
      - traefik-net

  whoami:
    image: traefik/whoami
    container_name: whoami
    networks:
      - traefik-net
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.example.com`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      - "traefik.http.routers.whoami.tls.certresolver=myresolver"
      - "traefik.http.services.whoami.loadbalancer.server.port=80"

networks:
  traefik-net:
    external: true

In this setup, Traefik is running and configured via traefik.yml (as shown previously). The whoami service is a simple container that echoes back request information. It’s exposed through Traefik with the rule Host(whoami.example.com) and is configured to use the myresolver for TLS.

When you navigate to https://whoami.example.com, Traefik intercepts the request. It checks its acme.json for a certificate for whoami.example.com. If it doesn’t exist or is expired, it triggers the ACME challenge. For the HTTP-01 challenge, Traefik would receive a request from Let’s Encrypt to http://whoami.example.com/.well-known/acme-challenge/.... Traefik, listening on port 80, would respond with the correct token. Once Let’s Encrypt verifies this, it issues the certificate, and Traefik automatically configures it for the whoami router on the websecure entrypoint.

The core problem Traefik’s ACME solves is the manual, error-prone process of obtaining and renewing SSL/TLS certificates. Before this, you’d manually generate a Certificate Signing Request (CSR), submit it to a CA, download the certificate, and then configure your web server. This had to be repeated every 60-90 days, leading to expired certificates and downtime. Traefik automates this entire lifecycle, making it seamless.

The internal mechanism Traefik uses for ACME involves an ACME client library. When a certificate is requested, Traefik communicates with the Let’s Encrypt API. It negotiates the challenge type (HTTP-01 or DNS-01 are common). For HTTP-01, Traefik spins up a temporary endpoint or uses its existing HTTP listener to serve the challenge file. For DNS-01, it interacts with your DNS provider’s API to create a TXT record containing the challenge token, which Let’s Encrypt then queries.

The most surprising thing about Traefik’s ACME implementation is how it manages the acme.json file. It’s not just a static storage; Traefik actively reads from and writes to it, managing certificate renewals, account credentials for Let’s Encrypt, and other ACME-related state. If this file becomes corrupted or is lost, Traefik will lose its ACME account registration and potentially all its issued certificates, forcing a re-registration and re-issuance process. You can inspect this file to see the encrypted private keys and certificate data.

Once you have your ACME certificates working, the next logical step is to understand how to fine-tune the ACME process, such as setting up the DNS-01 challenge for wildcard certificates or configuring custom ACME directory endpoints for staging environments.

Want structured learning?

Take the full Traefik course →