Skip to content

Traefik

Traefik is a modern, Docker-native reverse proxy with automatic service discovery and SSL certificate management.

Docker Compose Setup

Basic Configuration

# docker-compose.yml
services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik.yml:/traefik.yml:ro
      - ./acme.json:/acme.json
      - ./config:/config
    networks:
      - proxy
    labels:
      - "traefik.enable=true"
      # Dashboard
      - "traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN}`)"
      - "traefik.http.routers.traefik.entrypoints=https"
      - "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
      - "traefik.http.routers.traefik.service=api@internal"
      # Basic auth for dashboard
      - "traefik.http.routers.traefik.middlewares=auth"
      - "traefik.http.middlewares.auth.basicauth.users=${TRAEFIK_AUTH}"

networks:
  proxy:
    external: true

Traefik Configuration

# traefik.yml
api:
  dashboard: true
  insecure: false

entryPoints:
  http:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: https
          scheme: https
  https:
    address: ":443"

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    network: proxy
  file:
    directory: /config
    watch: true

certificatesResolvers:
  letsencrypt:
    acme:
      email: your@email.com
      storage: acme.json
      httpChallenge:
        entryPoint: http

Setup Steps

# Create network
docker network create proxy

# Create acme.json with proper permissions
touch acme.json
chmod 600 acme.json

# Generate basic auth password
htpasswd -nb admin yourpassword
# Add output to .env as TRAEFIK_AUTH

# Start
docker compose up -d

Adding Services

Service with Traefik Labels

# Example: Whoami test service
services:
  whoami:
    image: traefik/whoami
    container_name: whoami
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.${DOMAIN}`)"
      - "traefik.http.routers.whoami.entrypoints=https"
      - "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
    networks:
      - proxy

networks:
  proxy:
    external: true

Service with Custom Port

services:
  myapp:
    image: myapp:latest
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.myapp.rule=Host(`myapp.${DOMAIN}`)"
      - "traefik.http.routers.myapp.entrypoints=https"
      - "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
      - "traefik.http.services.myapp.loadbalancer.server.port=3000"
    networks:
      - proxy

Path-Based Routing

services:
  api:
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.api.rule=Host(`${DOMAIN}`) && PathPrefix(`/api`)"
      - "traefik.http.routers.api.entrypoints=https"
      - "traefik.http.routers.api.tls.certresolver=letsencrypt"
      - "traefik.http.middlewares.api-strip.stripprefix.prefixes=/api"
      - "traefik.http.routers.api.middlewares=api-strip"

Middlewares

Basic Authentication

labels:
  - "traefik.http.middlewares.myauth.basicauth.users=admin:$$hashed$$password"
  - "traefik.http.routers.myapp.middlewares=myauth"

Rate Limiting

labels:
  - "traefik.http.middlewares.ratelimit.ratelimit.average=100"
  - "traefik.http.middlewares.ratelimit.ratelimit.burst=50"
  - "traefik.http.routers.myapp.middlewares=ratelimit"

IP Whitelist

labels:
  - "traefik.http.middlewares.local-only.ipwhitelist.sourcerange=192.168.1.0/24,10.0.0.0/8"
  - "traefik.http.routers.myapp.middlewares=local-only"

Headers

labels:
  - "traefik.http.middlewares.security.headers.browserXssFilter=true"
  - "traefik.http.middlewares.security.headers.contentTypeNosniff=true"
  - "traefik.http.middlewares.security.headers.frameDeny=true"
  - "traefik.http.middlewares.security.headers.stsIncludeSubdomains=true"
  - "traefik.http.middlewares.security.headers.stsSeconds=31536000"
  - "traefik.http.routers.myapp.middlewares=security"

Redirect HTTP to HTTPS

Already configured in traefik.yml, but can also use:

labels:
  - "traefik.http.middlewares.redirect-https.redirectscheme.scheme=https"
  - "traefik.http.routers.myapp-http.middlewares=redirect-https"

DNS Challenge (Wildcard Certificates)

For internal services or wildcard certs:

# traefik.yml
certificatesResolvers:
  letsencrypt-dns:
    acme:
      email: your@email.com
      storage: acme.json
      dnsChallenge:
        provider: cloudflare
        resolvers:
          - "1.1.1.1:53"
          - "8.8.8.8:53"
# docker-compose.yml
services:
  traefik:
    environment:
      - CF_API_EMAIL=your@email.com
      - CF_DNS_API_TOKEN=your-token

TCP/UDP Routing

TCP Service (Database)

# traefik.yml
entryPoints:
  postgres:
    address: ":5432"

# docker-compose.yml
services:
  postgres:
    labels:
      - "traefik.enable=true"
      - "traefik.tcp.routers.postgres.rule=HostSNI(`*`)"
      - "traefik.tcp.routers.postgres.entrypoints=postgres"
      - "traefik.tcp.services.postgres.loadbalancer.server.port=5432"

File-Based Configuration

For non-Docker services:

# config/external.yml
http:
  routers:
    external-router:
      rule: "Host(`external.domain.com`)"
      entryPoints:
        - https
      tls:
        certResolver: letsencrypt
      service: external-service

  services:
    external-service:
      loadBalancer:
        servers:
          - url: "http://192.168.1.100:8080"

Monitoring

Prometheus Metrics

# traefik.yml
metrics:
  prometheus:
    entryPoint: metrics
    buckets:
      - 0.1
      - 0.3
      - 1.2
      - 5.0

entryPoints:
  metrics:
    address: ":8082"

Access Logs

# traefik.yml
accessLog:
  filePath: "/var/log/traefik/access.log"
  bufferingSize: 100
  filters:
    statusCodes:
      - "400-499"
      - "500-599"

Troubleshooting

Check Configuration

# View logs
docker logs traefik

# Check running routers
curl http://localhost:8080/api/http/routers

# Check services
curl http://localhost:8080/api/http/services

Common Issues

  1. Certificate not generating
  2. Check acme.json permissions (600)
  3. Verify DNS is pointing to your server
  4. Check Let's Encrypt rate limits

  5. Service not discovered

  6. Ensure traefik.enable=true label
  7. Check service is on the proxy network
  8. Verify Docker socket is mounted

  9. 503 Service Unavailable

  10. Check backend service is running
  11. Verify port in loadbalancer.server.port

See Also