Logo

Traefik: Docker-native reverse proxy

Traefik: Docker-native reverse proxy

Traefik is the reverse proxy designed for dynamic environments: Docker, Kubernetes, Nomad. Auto-discovery via labels, automatic Let's Encrypt HTTPS, real-time dashboard.

Introduction

Traefik shines where Nginx struggles: environments where services come and go (containers, K8s). Each new Docker container is auto-discovered via labels and exposed in HTTPS.

Features:

  • Auto-discovery (Docker, K8s, Consul, etcd, file)
  • Automatic HTTPS via Let's Encrypt
  • Load balancing
  • Real-time web dashboard
  • Rich middlewares (auth, rate limit, headers, CORS)
  • HTTP/2, HTTP/3, gRPC
  • Prometheus metrics

Prerequisites

  • Linux VPS with Docker + Docker Compose
  • Domain pointing to VPS
  • Ports 80, 443 open
  • Root access

Step 1: Base structure

sudo mkdir -p /opt/traefik/{config,letsencrypt}
cd /opt/traefik
sudo touch letsencrypt/acme.json
sudo chmod 600 letsencrypt/acme.json

Step 2: Static config

sudo nano /opt/traefik/config/traefik.yml
api:
  dashboard: true
  insecure: false

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: ":443"
    http:
      tls:
        certResolver: letsencrypt

certificatesResolvers:
  letsencrypt:
    acme:
      email: [email protected]
      storage: /letsencrypt/acme.json
      httpChallenge:
        entryPoint: web

providers:
  docker:
    exposedByDefault: false
    network: traefik

log:
  level: INFO

accessLog: {}

Step 3: docker-compose.yml

services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    restart: unless-stopped
    networks:
      - traefik
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./config/traefik.yml:/traefik.yml:ro
      - ./letsencrypt:/letsencrypt
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.rule=Host(`traefik.your-domain.com`)"
      - "traefik.http.routers.traefik.entrypoints=websecure"
      - "traefik.http.routers.traefik.service=api@internal"
      - "traefik.http.routers.traefik.middlewares=auth"
      - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$abc..."

networks:
  traefik:
    external: true
sudo docker network create traefik
echo $(htpasswd -nbB admin YOUR_PASSWORD) | sed -e s/\\$/\\$\\$/g

Step 4: Start

cd /opt/traefik
sudo docker compose up -d
sudo docker compose logs -f

Access dashboard: https://traefik.your-domain.com.

Step 5: Expose app via labels

services:
  myapp:
    image: nginx
    networks:
      - traefik
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.myapp.rule=Host(`myapp.your-domain.com`)"
      - "traefik.http.routers.myapp.entrypoints=websecure"
      - "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
      - "traefik.http.services.myapp.loadbalancer.server.port=80"

networks:
  traefik:
    external: true
docker compose up -d

Step 6: Useful middlewares

Basic auth

- "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$abc..."
- "traefik.http.routers.myapp.middlewares=auth"

Rate limit

- "traefik.http.middlewares.ratelimit.ratelimit.average=100"
- "traefik.http.middlewares.ratelimit.ratelimit.burst=200"
- "traefik.http.routers.myapp.middlewares=ratelimit"

Compression

- "traefik.http.middlewares.compress.compress=true"
- "traefik.http.routers.myapp.middlewares=compress"

Security headers

- "traefik.http.middlewares.security.headers.stsSeconds=31536000"
- "traefik.http.middlewares.security.headers.stsIncludeSubdomains=true"
- "traefik.http.middlewares.security.headers.contentTypeNosniff=true"
- "traefik.http.middlewares.security.headers.framedeny=true"
- "traefik.http.routers.myapp.middlewares=security"

Chain multiple

- "traefik.http.routers.myapp.middlewares=auth,ratelimit,compress,security"

Step 7: Whoami for testing

services:
  whoami:
    image: traefik/whoami
    networks:
      - traefik
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.your-domain.com`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      - "traefik.http.routers.whoami.tls.certresolver=letsencrypt"

Step 8: Wildcard with DNS-01

certificatesResolvers:
  letsencrypt:
    acme:
      email: [email protected]
      storage: /letsencrypt/acme.json
      dnsChallenge:
        provider: cloudflare
        resolvers:
          - "1.1.1.1:53"
          - "1.0.0.1:53"

In docker-compose:

environment:
  - [email protected]
  - CF_API_KEY=your_cloudflare_global_api_key
- "traefik.http.routers.myapp.tls.domains[0].main=your-domain.com"
- "traefik.http.routers.myapp.tls.domains[0].sans=*.your-domain.com"

Step 9: Advanced routing

# Path prefix
- "traefik.http.routers.api.rule=Host(`api.your-domain.com`) && PathPrefix(`/v1`)"

# Multiple hosts
- "traefik.http.routers.myapp.rule=Host(`a.com`) || Host(`b.com`)"

# Strip prefix
- "traefik.http.middlewares.strip.stripprefix.prefixes=/api"
- "traefik.http.routers.myapp.middlewares=strip"

Step 10: Sticky sessions

- "traefik.http.services.myapp.loadbalancer.sticky.cookie.name=session"
- "traefik.http.services.myapp.loadbalancer.sticky.cookie.secure=true"

Step 11: Prometheus metrics

metrics:
  prometheus:
    addEntryPointsLabels: true
    addServicesLabels: true

Step 12: Healthcheck

- "traefik.http.services.myapp.loadbalancer.healthcheck.path=/healthz"
- "traefik.http.services.myapp.loadbalancer.healthcheck.interval=10s"
- "traefik.http.services.myapp.loadbalancer.healthcheck.timeout=3s"

Troubleshooting

Service not discovered

Check traefik.enable=true, network traefik, rule syntax.

sudo docker logs traefik | grep myapp

Cert won't generate

sudo cat /opt/traefik/letsencrypt/acme.json

If empty: check Traefik logs, DNS, ports 80/443.

404 Page not found

curl -v https://myapp.your-domain.com

Host header must match rule exactly.

Dashboard inaccessible

Check auth middleware and api@internal service reference.

Useful commands

docker exec traefik traefik healthcheck
docker compose logs -f traefik
cat /opt/traefik/letsencrypt/acme.json | jq '.letsencrypt.Certificates[].domain.main'
docker compose up -d                   # auto-reload on label change
docker compose pull && docker compose up -d

Conclusion

Traefik is ideal for:

  • Dynamic Docker environments
  • Kubernetes stacks
  • Frequently changing configs
  • Multi-tenancy

For static prod, Nginx or Caddy are more direct. But once containers come into play, Traefik changes the game.

Going further:

  • Enable Traefik Pilot for advanced observability
  • Use Crowdsec bouncer for collaborative security
  • Combine with Authelia for SSO/MFA

Resources

Join our Discord community server

For any questions, suggestions, or just to chat with the community, join us on Discord!

900+Members