Traefik is a reverse proxy built for containers. It watches the Docker API, and when a container starts with the right labels, Traefik automatically routes a domain to it and obtains a Let’s Encrypt certificate. Add a new app, and its HTTPS site is live — no proxy config to edit.

1. Traefik with Docker Compose

mkdir -p ~/traefik && cd ~/traefik
touch acme.json && chmod 600 acme.json
docker network create proxy

compose.yaml:

services:
  traefik:
    image: traefik:v3.4
    restart: unless-stopped
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --providers.docker.network=proxy
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entrypoint.to=websecure
      - --entrypoints.web.http.redirections.entrypoint.scheme=https
      - --entrypoints.websecure.address=:443
      - [email protected]
      - --certificatesresolvers.le.acme.storage=/acme.json
      - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./acme.json:/acme.json
    networks:
      - proxy

networks:
  proxy:
    external: true
docker compose up -d
docker compose logs -f traefik

Key settings:

  • exposedbydefault=false — only containers with traefik.enable=true are published. Without it, every container becomes reachable.
  • The web entrypoint redirects everything to HTTPS.
  • acme.json stores certificates; it must be chmod 600.

Check the current Traefik version; v3 changed some label and rule syntax compared with v2.

2. Route a container with labels

Any app on the proxy network:

services:
  whoami:
    image: traefik/whoami
    restart: unless-stopped
    networks: [proxy]
    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=le

networks:
  proxy:
    external: true

Point DNS for whoami.example.com at the server and run docker compose up -d. Within seconds Traefik obtains a certificate and serves the site over HTTPS.

If the container listens on a non-default or multiple ports, tell Traefik which:

      - traefik.http.services.whoami.loadbalancer.server.port=8080

The app needs no published ports — Traefik reaches it over the Docker network, so it isn’t exposed directly.

3. Middlewares

Middlewares modify requests. Basic authentication for an admin tool:

echo $(htpasswd -nB admin) | sed -e 's/\$/\$\$/g'
    labels:
      - traefik.http.middlewares.auth.basicauth.users=admin:$$2y$$05$$…
      - traefik.http.routers.tool.middlewares=auth

($ must be doubled in Compose files.) Other useful middlewares: ipallowlist (restrict by IP), ratelimit, headers (security headers, HSTS), redirectregex, stripprefix.

4. The dashboard (carefully)

The dashboard shows routers, services and middlewares — very helpful for debugging. Enable it with --api.dashboard=true and expose it through a router with authentication:

    labels:
      - traefik.enable=true
      - traefik.http.routers.dash.rule=Host(`traefik.example.com`)
      - traefik.http.routers.dash.service=api@internal
      - traefik.http.routers.dash.entrypoints=websecure
      - traefik.http.routers.dash.tls.certresolver=le
      - traefik.http.routers.dash.middlewares=auth

Never expose it without authentication or an IP allow-list.

5. Wildcard certificates via DNS challenge

For many subdomains or services not reachable on port 80, use a DNS challenge:

      - --certificatesresolvers.le.acme.dnschallenge.provider=cloudflare
    environment:
      CF_DNS_API_TOKEN: ${CF_DNS_API_TOKEN}

And on a router: tls.domains[0].main=example.com, tls.domains[0].sans=*.example.com.

Security notes

  • Mounting the Docker socket (even read-only) gives Traefik powerful access. Consider a socket proxy (e.g. a container exposing only read-only API endpoints) between Traefik and Docker.
  • Keep Traefik updated.
  • Only ports 80/443 need to be public.

Troubleshooting

  • 404 page not found — no router matched: check the Host() rule, traefik.enable=true, and that the container is on the proxy network.
  • Bad Gateway — wrong service port, or Traefik and the app don’t share a network.
  • Self-signed “TRAEFIK DEFAULT CERT” — certificate issuance failed: check logs, DNS and that port 80 reaches Traefik.

Traefik vs alternatives

Traefik is ideal when containers come and go frequently. A Docker VPS running Traefik can host dozens of apps behind one IP.

  • Traefik
  • Docker
  • Reverse Proxy