Skip to main content
Back to Category

Traefik Reverse Proxy: Modern Load Balancer for Docker and Kubernetes

Traefik installation, automatic service discovery with Docker provider, Let's Encrypt SSL, middleware configuration, dashboard, Kubernetes Ingress Controller, and load balancing.

Read time: 18 min DevOps & Automation
traefikreverse proxyload balancerdockerkubernetesssldevops
Author
REXE Teknoloji Network & Security Team
Editor
REXE Teknoloji Technical Editorial
First published
Last updated

Traefik Reverse Proxy: Modern Load Balancer for Docker and Kubernetes

Traefik is a modern edge router and reverse proxy designed for microservice architectures. Thanks to its deep integration with Docker and Kubernetes, it automatically discovers and routes services.

What is Traefik?

Key features of Traefik:

  • Automatic service discovery: Automatic routing via Docker/Kubernetes labels
  • Let's Encrypt integration: Automatic SSL certificate management
  • Middleware system: Auth, rate limiting, redirect, headers
  • Dashboard: Real-time monitoring interface
  • Multiple providers: Docker, Kubernetes, Consul, etcd support
  • TCP/UDP routing: Support for non-HTTP protocols

Traefik v3 offers better performance and new features compared to v2. This guide focuses on Traefik v3.

Traefik v3 Installation

Installation with Docker Compose

hljs yaml
# docker-compose.yml
services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"  # Dashboard (close in production)
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik.yml:/etc/traefik/traefik.yml:ro
      - ./config:/etc/traefik/config:ro
      - traefik_certs:/certs
    networks:
      - traefik-net
    labels:
      - "traefik.enable=true"
      # Dashboard
      - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)"
      - "traefik.http.routers.dashboard.service=api@internal"
      - "traefik.http.routers.dashboard.middlewares=auth"
      - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$xyz$$hash"
      - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"

volumes:
  traefik_certs:

networks:
  traefik-net:
    external: true

traefik.yml Configuration

hljs yaml
# traefik.yml
global:
  checkNewVersion: true
  sendAnonymousUsage: false

api:
  dashboard: true
  insecure: false  # false in production

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
          permanent: true

  websecure:
    address: ":443"
    http:
      tls:
        certResolver: letsencrypt
    http3:
      advertisedPort: 443

certificatesResolvers:
  letsencrypt:
    acme:
      email: admin@example.com
      storage: /certs/acme.json
      httpChallenge:
        entryPoint: web
      # DNS challenge (for wildcard)
      # dnsChallenge:
      #   provider: cloudflare
      #   resolvers:
      #     - "1.1.1.1:53"

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    network: traefik-net
  file:
    directory: /etc/traefik/config
    watch: true

log:
  level: INFO
  filePath: /var/log/traefik/traefik.log

accessLog:
  filePath: /var/log/traefik/access.log
  bufferingSize: 100

Automatic Routing with Docker Provider

Register services automatically with Traefik using Docker labels:

hljs yaml
# Example application
services:
  webapp:
    image: nginx:alpine
    networks:
      - traefik-net
    labels:
      # Enable Traefik
      - "traefik.enable=true"

      # HTTP router
      - "traefik.http.routers.webapp.rule=Host(`app.example.com`)"
      - "traefik.http.routers.webapp.entrypoints=websecure"
      - "traefik.http.routers.webapp.tls.certresolver=letsencrypt"

      # Service port
      - "traefik.http.services.webapp.loadbalancer.server.port=80"

      # Apply middleware
      - "traefik.http.routers.webapp.middlewares=security-headers,rate-limit"

networks:
  traefik-net:
    external: true

Multi-Service Example

hljs yaml
services:
  api:
    image: myapi:latest
    networks:
      - traefik-net
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.api.rule=Host(`api.example.com`)"
      - "traefik.http.routers.api.entrypoints=websecure"
      - "traefik.http.routers.api.tls.certresolver=letsencrypt"
      - "traefik.http.services.api.loadbalancer.server.port=3000"
      # Health check
      - "traefik.http.services.api.loadbalancer.healthcheck.path=/health"
      - "traefik.http.services.api.loadbalancer.healthcheck.interval=30s"

  frontend:
    image: myfrontend:latest
    networks:
      - traefik-net
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.frontend.rule=Host(`example.com`) || Host(`www.example.com`)"
      - "traefik.http.routers.frontend.entrypoints=websecure"
      - "traefik.http.routers.frontend.tls.certresolver=letsencrypt"
      - "traefik.http.services.frontend.loadbalancer.server.port=80"

networks:
  traefik-net:
    external: true

Middleware Configuration

Static Middleware (traefik.yml or config file)

hljs yaml
# config/middlewares.yml
http:
  middlewares:
    # Security headers
    security-headers:
      headers:
        stsSeconds: 31536000
        stsIncludeSubdomains: true
        stsPreload: true
        forceSTSHeader: true
        contentTypeNosniff: true
        frameDeny: true
        referrerPolicy: "strict-origin-when-cross-origin"
        customResponseHeaders:
          X-Powered-By: ""
          Server: ""

    # Rate limiting
    rate-limit:
      rateLimit:
        average: 100
        burst: 50
        period: 1m
        sourceCriterion:
          ipStrategy:
            depth: 1

    # Basic auth
    basic-auth:
      basicAuth:
        users:
          - "admin:$apr1$xyz$hashedpassword"
        removeHeader: true

    # IP allowlist
    ip-whitelist:
      ipAllowList:
        sourceRange:
          - "192.168.1.0/24"
          - "10.0.0.0/8"

    # Redirect www to non-www
    www-redirect:
      redirectRegex:
        regex: "^https://www\\.(.*)"
        replacement: "https://${1}"
        permanent: true

    # Compress
    compress:
      compress:
        excludedContentTypes:
          - text/event-stream

Middleware via Labels

hljs yaml
labels:
  # Define and apply middleware
  - "traefik.http.middlewares.myapp-auth.basicauth.users=user:$$apr1$$hash"
  - "traefik.http.middlewares.myapp-ratelimit.ratelimit.average=50"
  - "traefik.http.middlewares.myapp-ratelimit.ratelimit.burst=20"
  - "traefik.http.routers.myapp.middlewares=myapp-auth,myapp-ratelimit"

  # Redirect middleware
  - "traefik.http.middlewares.redirect-https.redirectscheme.scheme=https"
  - "traefik.http.middlewares.redirect-https.redirectscheme.permanent=true"

Dashboard

hljs yaml
# Secure dashboard configuration
labels:
  - "traefik.enable=true"
  - "traefik.http.routers.traefik-dashboard.rule=Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
  - "traefik.http.routers.traefik-dashboard.service=api@internal"
  - "traefik.http.routers.traefik-dashboard.entrypoints=websecure"
  - "traefik.http.routers.traefik-dashboard.tls.certresolver=letsencrypt"
  - "traefik.http.routers.traefik-dashboard.middlewares=dashboard-auth"
  - "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$apr1$$xyz$$hash"

Generating basic auth password:

hljs bash
# Generate password with htpasswd
echo $(htpasswd -nB admin) | sed -e s/\\$/\\$\\$/g

# Or with openssl
echo "admin:$(openssl passwd -apr1 'yourpassword')" | sed -e 's/\$/\$\$/g'

Kubernetes Ingress Controller

Installation with Helm

hljs bash
# Add Traefik Helm repository
helm repo add traefik https://traefik.github.io/charts
helm repo update

# Install Traefik
helm install traefik traefik/traefik \
  --namespace traefik \
  --create-namespace \
  --set deployment.replicas=2 \
  --set ports.web.redirectTo.port=websecure \
  --set ingressRoute.dashboard.enabled=true

IngressRoute (Traefik CRD)

hljs yaml
# ingressroute.yml
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: webapp-ingress
  namespace: default
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`app.example.com`)
      kind: Rule
      services:
        - name: webapp-service
          port: 80
      middlewares:
        - name: security-headers
  tls:
    certResolver: letsencrypt

Middleware CRD

hljs yaml
# middleware.yml
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: security-headers
  namespace: default
spec:
  headers:
    stsSeconds: 31536000
    stsIncludeSubdomains: true
    contentTypeNosniff: true
    frameDeny: true

TCP/UDP Routing

hljs yaml
# traefik.yml - TCP entrypoint
entryPoints:
  mysql:
    address: ":3306"
  redis:
    address: ":6379"
hljs yaml
# config/tcp.yml
tcp:
  routers:
    mysql-router:
      entryPoints:
        - mysql
      rule: "HostSNI(`*`)"
      service: mysql-service

  services:
    mysql-service:
      loadBalancer:
        servers:
          - address: "mysql:3306"

Load Balancing

hljs yaml
# Load balancing with multiple instances
services:
  api:
    image: myapi:latest
    deploy:
      replicas: 3
    networks:
      - traefik-net
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.api.rule=Host(`api.example.com`)"
      - "traefik.http.services.api.loadbalancer.server.port=3000"
      # Sticky sessions
      - "traefik.http.services.api.loadbalancer.sticky.cookie=true"
      - "traefik.http.services.api.loadbalancer.sticky.cookie.name=traefik_session"
      - "traefik.http.services.api.loadbalancer.sticky.cookie.secure=true"
      # Health check
      - "traefik.http.services.api.loadbalancer.healthcheck.path=/health"
      - "traefik.http.services.api.loadbalancer.healthcheck.interval=10s"
      - "traefik.http.services.api.loadbalancer.healthcheck.timeout=3s"

Conclusion

Traefik is a powerful reverse proxy and load balancer solution for modern microservice infrastructures. With its deep integration with Docker and Kubernetes, automatic SSL management, and rich middleware ecosystem, it's a reliable choice for production environments. Its label-based configuration allows each service to define its own routing rules.

Frequently Asked Questions

What is the main difference between Traefik and Nginx?

Traefik has deep integration with Docker/Kubernetes and automatically discovers services. Nginx requires static configuration and needs a reload for every change. Traefik supports dynamic configuration and updates with zero downtime. Nginx is more mature and may perform better under very high traffic. Traefik is preferred for microservice environments, Nginx for traditional web servers.

How do I keep the Traefik dashboard secure in production?

Never expose the dashboard in insecure mode (port 8080) in production. Protect the dashboard with HTTPS and basic auth by adding labels to the Traefik container. Restrict access to specific IPs with the IP whitelist middleware. Alternatively, completely disable the dashboard and use Prometheus/Grafana for monitoring.

How is DNS challenge configured for Let's Encrypt wildcard certificates?

Set the dnsChallenge provider under certificatesResolvers in traefik.yml. For Cloudflare, 'provider: cloudflare' and the 'CF_DNS_API_TOKEN' environment variable are required. Define the relevant API keys as environment variables for other DNS providers. DNS challenge is more secure than HTTP challenge and enables wildcard certificate issuance.

Does middleware order matter in Traefik?

Yes, middlewares are applied in the order they are defined. The generally recommended order is: IP whitelist → Rate limit → Auth → Headers. Wrong ordering can lead to unexpected behavior. For example, if you put the auth middleware before rate limiting, unauthenticated requests will also count toward the rate limit.

How do you achieve zero-downtime deployment with Traefik?

Use rolling updates in Docker Swarm or Kubernetes. Traefik automatically routes traffic when new containers are ready. Health check configuration is critical: traffic is not sent to unhealthy containers. Define the health check endpoint with the 'traefik.http.services.myapp.loadbalancer.healthcheck.path=/health' label.

How do I get a single certificate (SAN) for multiple domains in Traefik?

Traefik obtains separate certificates for each domain. For multiple domains, use 'Host(`a.com`) || Host(`b.com`)' in the router rule. Separate certificates are automatically obtained for each domain. DNS challenge is required for wildcard certificates. Manual configuration or external certificate usage may be needed for SAN certificates.

Related Articles

Server Automation with Ansible: Infrastructure as Code

Ansible installation, inventory file, playbook writing, role structure, variables, encrypted vault, ad-hoc commands, and server configuration automation. Step-by-step guide.

20 min
ansibleautomationinfrastructure as code
Network TrafficInbound GbpsOutbound Gbps