Traefik

Modern HTTP reverse proxy and load balancer. Automatic service discovery, Docker/Kubernetes integration, Let's Encrypt automatic certificate acquisition.

Reverse ProxyLoad BalancerDynamic ConfigurationMicroservicesAutomatic HTTPSCloud NativeDockerKubernetes

Server

Traefik Proxy

Overview

Traefik Proxy is a modern HTTP reverse proxy and load balancer designed for microservice architectures. It integrates with existing infrastructure components (Docker, Kubernetes, etc.) to automatically and dynamically configure itself. By listening to service registry/orchestrator APIs and generating routes in real-time, it significantly simplifies microservice deployment. With automatic Let's Encrypt integration, comprehensive observability features, and a chainable middleware system, it is widely adopted in modern cloud-native environments.

Details

Traefik Proxy features a sophisticated architecture composed of EntryPoints (network listeners), Routers (routing logic), Middlewares (request/response processing), and Services (backend servers). A dual configuration system of static configuration (loaded at startup) and dynamic configuration (updated at runtime) enables configuration changes without restarts. It integrates with diverse providers like Docker, Kubernetes, Consul, and Etcd to provide service discovery capabilities. Advanced load balancing features include Weighted Round Robin, health checks, failover, and mirroring.

Key Features

  • Dynamic Configuration Management: Zero-downtime configuration changes through orchestrator integration
  • Automatic Service Discovery: Automatic route generation from Docker/Kubernetes and other providers
  • Automatic HTTPS: Let's Encrypt integration with wildcard certificate support
  • Comprehensive Observability: Metrics, logging, and distributed tracing capabilities
  • Middleware System: Flexible processing for authentication, header manipulation, redirects, etc.
  • Single Binary: Simple deployment with a single executable file

Pros and Cons

Pros

  • Automatic configuration optimized for microservices and container environments
  • Dynamic configuration system enabling configuration changes without restarts
  • Significant simplification of certificate management through automatic Let's Encrypt integration
  • Rich observability integration with Prometheus, OpenTelemetry, and more
  • Flexible request processing through chainable middleware
  • Easy deployment with official Docker images and single binary

Cons

  • High learning curve due to the combination of static and dynamic configurations
  • Configuration complexity risks due to provider dependencies
  • Configuration complexity with advanced routing rules
  • Overhead compared to traditional static proxies
  • Difficult debugging and troubleshooting in large-scale environments
  • Risk of configuration update stoppage during provider failures

Reference Pages

Code Examples

Basic Configuration and HTTP Routing

# traefik.yml (static configuration)
api:
  dashboard: true
  insecure: true

entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"

providers:
  file:
    directory: "/etc/traefik/dynamic"
    watch: true
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false

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

log:
  level: INFO

accessLog: {}

metrics:
  prometheus:
    addEntryPointsLabels: true
    addServicesLabels: true
# dynamic.yml (dynamic configuration)
http:
  routers:
    api-router:
      rule: "Host(`api.example.com`)"
      service: api-service
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt
      middlewares:
        - auth-middleware
        - rate-limit

    frontend-router:
      rule: "Host(`www.example.com`)"
      service: frontend-service
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt

  middlewares:
    auth-middleware:
      basicAuth:
        users:
          - "admin:$2y$10$..."
    
    rate-limit:
      rateLimit:
        burst: 100
        average: 50

  services:
    api-service:
      loadBalancer:
        servers:
          - url: "http://api-server1:8080"
          - url: "http://api-server2:8080"
        healthCheck:
          path: "/health"
          interval: "30s"
          timeout: "5s"

    frontend-service:
      loadBalancer:
        servers:
          - url: "http://frontend-server:3000"

Docker Compose Integration and Service Discovery

# docker-compose.yml
version: '3.8'

services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    command:
      - --api.dashboard=true
      - --api.insecure=true
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --certificatesresolvers.letsencrypt.acme.httpchallenge=true
      - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
      - --certificatesresolvers.letsencrypt.acme.email=your-email@example.com
      - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
      - --log.level=INFO
      - --accesslog=true
      - --metrics.prometheus=true
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - letsencrypt:/letsencrypt
    networks:
      - traefik-network

  web-app:
    image: nginx:alpine
    container_name: web-app
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.webapp.rule=Host(`app.example.com`)"
      - "traefik.http.routers.webapp.entrypoints=websecure"
      - "traefik.http.routers.webapp.tls.certresolver=letsencrypt"
      - "traefik.http.services.webapp.loadbalancer.server.port=80"
      - "traefik.http.middlewares.webapp-auth.basicauth.users=admin:$$2y$$10$$..."
      - "traefik.http.routers.webapp.middlewares=webapp-auth"
    networks:
      - traefik-network

  api-app:
    image: node:alpine
    container_name: api-app
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.api.rule=Host(`api.example.com`) && PathPrefix(`/api`)"
      - "traefik.http.routers.api.entrypoints=websecure"
      - "traefik.http.routers.api.tls.certresolver=letsencrypt"
      - "traefik.http.services.api.loadbalancer.server.port=3000"
      - "traefik.http.middlewares.api-ratelimit.ratelimit.average=100"
      - "traefik.http.middlewares.api-ratelimit.ratelimit.burst=200"
      - "traefik.http.routers.api.middlewares=api-ratelimit"
    networks:
      - traefik-network

volumes:
  letsencrypt:

networks:
  traefik-network:
    external: true

Kubernetes Integration (IngressRoute CRD)

# traefik-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: traefik
  namespace: traefik-system

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: traefik
rules:
  - apiGroups: [""]
    resources: ["services", "endpoints", "secrets"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["extensions", "networking.k8s.io"]
    resources: ["ingresses", "ingressclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["traefik.io"]
    resources: ["*"]
    verbs: ["get", "list", "watch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: traefik
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: traefik
subjects:
  - kind: ServiceAccount
    name: traefik
    namespace: traefik-system

---
# traefik-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: traefik
  namespace: traefik-system
  labels:
    app: traefik
spec:
  replicas: 2
  selector:
    matchLabels:
      app: traefik
  template:
    metadata:
      labels:
        app: traefik
    spec:
      serviceAccountName: traefik
      containers:
      - name: traefik
        image: traefik:v3.0
        args:
          - --api.dashboard=true
          - --entrypoints.web.address=:80
          - --entrypoints.websecure.address=:443
          - --providers.kubernetescrd
          - --certificatesresolvers.letsencrypt.acme.httpchallenge=true
          - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
          - [email protected]
          - --certificatesresolvers.letsencrypt.acme.storage=/data/acme.json
          - --log.level=INFO
          - --accesslog=true
          - --metrics.prometheus=true
        ports:
        - name: web
          containerPort: 80
        - name: websecure
          containerPort: 443
        - name: admin
          containerPort: 8080
        volumeMounts:
        - name: data
          mountPath: /data
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: traefik-data

---
# traefik-ingressroute.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: api-ingressroute
  namespace: default
spec:
  entryPoints:
    - websecure
  routes:
  - match: Host(`api.example.com`)
    kind: Rule
    services:
    - name: api-service
      port: 80
    middlewares:
    - name: api-auth
    - name: api-ratelimit
  tls:
    certResolver: letsencrypt

---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: api-auth
  namespace: default
spec:
  basicAuth:
    secret: api-auth-secret

---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: api-ratelimit
  namespace: default
spec:
  rateLimit:
    average: 100
    burst: 200

---
apiVersion: v1
kind: Secret
metadata:
  name: api-auth-secret
  namespace: default
data:
  users: YWRtaW46JGFwcjEkSDZKeFhXb3lQYVhuE...  # htpasswd format

Load Balancing and Health Check Configuration

# Weighted round-robin configuration
http:
  services:
    weighted-service:
      weighted:
        services:
        - name: service-v1
          weight: 70
        - name: service-v2
          weight: 30

    service-v1:
      loadBalancer:
        servers:
        - url: "http://app-v1-1:8080"
        - url: "http://app-v1-2:8080"
        healthCheck:
          path: "/health"
          interval: "10s"
          timeout: "3s"
          scheme: "http"

    service-v2:
      loadBalancer:
        servers:
        - url: "http://app-v2-1:8080"
        - url: "http://app-v2-2:8080"
        healthCheck:
          path: "/health"
          interval: "10s"
          timeout: "3s"

    # Sticky session configuration
    sticky-service:
      loadBalancer:
        servers:
        - url: "http://backend1:8080"
        - url: "http://backend2:8080"
        sticky:
          cookie:
            name: "server-session"
            secure: true
            httpOnly: true

    # Failover configuration
    failover-service:
      failover:
        service: primary-service
        fallback: backup-service

    primary-service:
      loadBalancer:
        servers:
        - url: "http://primary-server:8080"
        healthCheck:
          path: "/health"
          interval: "5s"

    backup-service:
      loadBalancer:
        servers:
        - url: "http://backup-server:8080"

Advanced Middleware Configuration

# Authentication and authorization middleware
http:
  middlewares:
    # OAuth2 authentication
    oauth-auth:
      forwardAuth:
        address: "http://oauth-provider:4181"
        authResponseHeaders:
          - "X-Forwarded-User"
          - "X-Auth-User"
          - "X-Secret"

    # JWT authentication
    jwt-auth:
      plugin:
        jwt:
          secret: "your-jwt-secret"
          alg: "HS256"

    # Rate limiting
    rate-limit-strict:
      rateLimit:
        extractorFunc: "request.host"
        rateLimitKey: "client.ip"
        average: 6
        period: "1m"
        burst: 12

    # CORS configuration
    cors-middleware:
      headers:
        accessControlAllowMethods:
          - GET
          - OPTIONS
          - PUT
          - POST
          - DELETE
        accessControlAllowOriginList:
          - "https://example.com"
          - "https://api.example.com"
        accessControlMaxAge: 100
        addVaryHeader: true

    # Security headers
    security-headers:
      headers:
        contentTypeNosniff: true
        browserXssFilter: true
        forceSTSHeader: true
        stsIncludeSubdomains: true
        stsPreload: true
        stsSeconds: 31536000

    # Request transformation
    transform-request:
      addPrefix:
        prefix: "/api/v1"

    # Response transformation
    transform-response:
      headers:
        customRequestHeaders:
          X-Custom-Request-Header: "request-value"
        customResponseHeaders:
          X-Custom-Response-Header: "response-value"

  routers:
    protected-api:
      rule: "Host(`secure.example.com`)"
      service: api-service
      middlewares:
        - oauth-auth
        - rate-limit-strict
        - cors-middleware
        - security-headers
        - transform-request
      tls:
        certResolver: letsencrypt

TCP Routing and SSL Termination

# TCP configuration
tcp:
  routers:
    mysql-router:
      rule: "HostSNI(`mysql.example.com`)"
      service: mysql-service
      tls:
        passthrough: false
        certResolver: letsencrypt

    postgres-router:
      rule: "HostSNI(`postgres.example.com`)"
      service: postgres-service
      tls:
        passthrough: true

    redis-router:
      rule: "HostSNI(`*`)"
      service: redis-service
      entryPoints:
        - redis

  services:
    mysql-service:
      loadBalancer:
        servers:
        - address: "mysql-master:3306"
        - address: "mysql-slave:3306"
        proxyProtocol:
          version: 1

    postgres-service:
      loadBalancer:
        servers:
        - address: "postgres-primary:5432"
        - address: "postgres-secondary:5432"

    redis-service:
      loadBalancer:
        servers:
        - address: "redis-node1:6379"
        - address: "redis-node2:6379"
        - address: "redis-node3:6379"

entryPoints:
  redis:
    address: ":6379"
  mysql:
    address: ":3306"
  postgres:
    address: ":5432"

Monitoring and Logging Configuration

# traefik.yml
log:
  level: INFO
  format: json

accessLog:
  filePath: "/var/log/traefik/access.log"
  format: json
  fields:
    defaultMode: keep
    headers:
      defaultMode: drop
      names:
        User-Agent: keep
        Authorization: drop
        Content-Type: keep

metrics:
  prometheus:
    addEntryPointsLabels: true
    addServicesLabels: true
    buckets:
      - 0.1
      - 0.3
      - 1.2
      - 5.0

tracing:
  jaeger:
    samplingServerURL: "http://jaeger:14268/api/sampling"
    localAgentHostPort: "jaeger:6831"

ping:
  entryPoint: "ping"

entryPoints:
  ping:
    address: ":8082"

api:
  dashboard: true
  debug: true

Troubleshooting

# Check Traefik status
docker logs traefik

# Check configuration
curl http://localhost:8080/api/rawdata

# Check router status
curl http://localhost:8080/api/http/routers

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

# Check middleware status
curl http://localhost:8080/api/http/middlewares

# Check health
curl http://localhost:8082/ping

# Check metrics
curl http://localhost:8080/metrics

# Reload configuration (file provider)
docker exec traefik kill -SIGUSR1 1

# Change log level
docker exec traefik traefik --log.level=DEBUG

# Check SSL certificates
openssl s_client -connect your-domain.com:443 -servername your-domain.com

# Validate Docker Compose configuration
docker-compose config