TL;DR — Quick Summary

Complete guide to Traefik middlewares: configure HTTP routing, rate limiting, security headers, authentication, and circuit breakers for production.

Traefik Middlewares: HTTP Routing, Rate Limiting, and Security Guide

Traefik middlewares are the core mechanism for transforming HTTP requests and responses between the edge and your upstream services. Whether you need to enforce rate limits, inject security headers, strip path prefixes, or delegate authentication to an external service, each behavior is a discrete middleware object you attach to a router. This guide covers every major middleware category with configuration examples, a comparison against alternatives, and a complete production Docker Compose example.

Prerequisites

  • Traefik v2.x or v3.x running as a Docker container or on a host
  • Basic familiarity with Docker Compose labels
  • A registered domain with DNS pointing to your server
  • Optional: Authelia or OAuth2-Proxy for ForwardAuth flows

Traefik Architecture: The Request Pipeline

Traefik organizes traffic through four primitives:

  • Entrypoints — network ports where traffic arrives (:80, :443)
  • Routers — match incoming requests by host, path, or headers and direct them to a service
  • Middlewares — transform the request or response (or reject it) before it reaches the service
  • Services — the upstream containers or servers receiving the final request

Traefik discovers these objects automatically from Docker labels, file providers (traefik.yml or dynamic/), or Kubernetes CRDs (IngressRoute, Middleware). This auto-discovery is what makes Traefik an edge router rather than a static proxy.

Middleware Configuration Providers

Docker Labels

labels:
  - "traefik.http.middlewares.my-headers.headers.stsSeconds=31536000"
  - "traefik.http.routers.myapp.middlewares=my-headers"

File Provider (dynamic YAML)

# dynamic/middlewares.yml
http:
  middlewares:
    my-headers:
      headers:
        stsSeconds: 31536000
        stsIncludeSubdomains: true

Kubernetes CRD

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: my-headers
spec:
  headers:
    stsSeconds: 31536000

Security Headers Middleware

The Headers middleware injects or modifies HTTP headers in both directions.

http:
  middlewares:
    secure-headers:
      headers:
        customRequestHeaders:
          X-Forwarded-Proto: "https"
        customResponseHeaders:
          X-Powered-By: ""
        stsSeconds: 31536000
        stsIncludeSubdomains: true
        stsPreload: true
        forceSTSHeader: true
        frameDeny: true
        contentTypeNosniff: true
        browserXssFilter: true
        referrerPolicy: "strict-origin-when-cross-origin"
        permissionsPolicy: "camera=(), microphone=(), geolocation=()"
        contentSecurityPolicy: "default-src 'self'; script-src 'self' 'unsafe-inline'"
        accessControlAllowOrigin: "https://example.com"
        accessControlAllowMethods: "GET,POST,OPTIONS"

customRequestHeaders modifies what reaches the backend. customResponseHeaders modifies what reaches the client. Setting a header to an empty string removes it entirely.

Rate Limiting

The RateLimit middleware limits how frequently a client can make requests.

http:
  middlewares:
    api-rate-limit:
      rateLimit:
        average: 100
        burst: 50
        period: 1m
        sourceCriterion:
          requestHeaderName: "X-API-Key"
  • average — sustained requests allowed per period
  • burst — maximum spike above average
  • period — rolling window (default 1s; supports 1m, 1h)
  • sourceCriterion — what identifies a “client”:
    • requestHeaderName — group by a header value (useful for API keys)
    • requestHost: true — group by the Host header
    • ipStrategy.depth — use the Nth IP in X-Forwarded-For to handle proxies

For edge deployments behind a CDN, set ipStrategy.depth: 1 so Traefik uses the real client IP rather than the CDN’s IP.

BasicAuth and DigestAuth

Protect routes with HTTP authentication when SSO is unavailable.

http:
  middlewares:
    basic-auth:
      basicAuth:
        users:
          - "admin:$apr1$xyz$hashedpassword"
        usersFile: "/etc/traefik/.htpasswd"
        realm: "Admin Area"
        removeHeader: true

Generate password hashes with:

htpasswd -nb admin mysecretpassword

removeHeader: true strips the Authorization header before forwarding, preventing credential leakage to the upstream service. DigestAuth follows the same structure with the digestAuth key.

ForwardAuth: SSO and OAuth2 Integration

ForwardAuth delegates the authentication decision to an external service such as Authelia or OAuth2-Proxy.

http:
  middlewares:
    sso-auth:
      forwardAuth:
        address: "http://authelia:9091/api/verify"
        trustForwardHeader: true
        authResponseHeaders:
          - "Remote-User"
          - "Remote-Groups"
          - "Remote-Name"
          - "Remote-Email"

Traefik sends every incoming request to address first. If that service returns 2xx, the original request proceeds. Any other status code is returned to the client as-is.

authResponseHeaders propagates identity headers from the auth response into the upstream request — this is how the backend knows who the user is without managing sessions itself.

Path Manipulation Middlewares

StripPrefix

Removes a prefix before forwarding, useful when the upstream expects a root path.

http:
  middlewares:
    strip-api:
      stripPrefix:
        prefixes:
          - "/api/v1"
        forceSlash: true

A request to /api/v1/users becomes /users at the upstream.

AddPrefix

Adds a prefix. Useful when multiple routes map to the same service with different path roots.

http:
  middlewares:
    add-v2:
      addPrefix:
        prefix: "/v2"

ReplacePath and ReplacePathRegex

http:
  middlewares:
    legacy-redirect:
      replacePathRegex:
        regex: "^/old/(.*)"
        replacement: "/new/$1"

ReplacePath replaces the full path with a static string. ReplacePathRegex uses a capture group pattern for dynamic rewrites.

Compression

http:
  middlewares:
    compress:
      compress:
        excludedContentTypes:
          - "image/jpeg"
          - "image/png"
        minResponseBodyBytes: 1024

Traefik supports both gzip and brotli. Brotli is used when the client sends Accept-Encoding: br. Content types in excludedContentTypes bypass compression.

Retry and CircuitBreaker

Retry

http:
  middlewares:
    retry-upstream:
      retry:
        attempts: 3
        initialInterval: "100ms"

Traefik retries failed requests up to attempts times with exponential backoff starting at initialInterval.

CircuitBreaker

http:
  middlewares:
    circuit-breaker:
      circuitBreaker:
        expression: "ResponseCodeRatio(500, 600, 0, 600) > 0.30"
        checkPeriod: "10s"
        fallbackDuration: "30s"
        recoveryDuration: "10s"

The circuit opens when expression evaluates to true, blocking traffic for fallbackDuration. After that, it enters a half-open state for recoveryDuration before fully recovering.

IPAllowList

Restrict access to a whitelist of IP ranges.

http:
  middlewares:
    internal-only:
      ipAllowList:
        sourceRange:
          - "10.0.0.0/8"
          - "172.16.0.0/12"
          - "192.168.0.0/16"
        ipStrategy:
          depth: 2

ipStrategy.depth controls which IP in the X-Forwarded-For chain is evaluated, essential when traffic passes through load balancers.

Redirect Middlewares

RedirectScheme (HTTP → HTTPS)

http:
  middlewares:
    https-redirect:
      redirectScheme:
        scheme: "https"
        permanent: true

RedirectRegex (www → non-www)

http:
  middlewares:
    www-redirect:
      redirectRegex:
        regex: "^https://www\\.(.+)"
        replacement: "https://${1}"
        permanent: true

Advanced Middlewares

InFlightReq

Caps concurrent requests per source to prevent thundering-herd overload:

http:
  middlewares:
    in-flight:
      inFlightReq:
        amount: 20
        sourceCriterion:
          ipStrategy:
            depth: 1

Buffering

Buffers the full request body before forwarding, protecting upstreams from slow-loris attacks and enabling retries on 5xx responses:

http:
  middlewares:
    buffer:
      buffering:
        maxRequestBodyBytes: 10485760
        retryExpression: "IsNetworkError() && Attempts() < 2"

PassTLSClientCert

Passes the client TLS certificate as a header to the upstream — required for mTLS service-to-service auth:

http:
  middlewares:
    pass-cert:
      passTLSClientCert:
        pem: true

Middleware Chains

Chains let you compose multiple middlewares into a single named pipeline:

http:
  middlewares:
    secure-stack:
      chain:
        middlewares:
          - secure-headers
          - https-redirect
          - api-rate-limit
          - sso-auth

Attach the chain to a router with one label:

labels:
  - "traefik.http.routers.myapp.middlewares=secure-stack"

Middleware Comparison: Traefik vs Alternatives

FeatureTraefikNginx (modules)Envoy (filters)Kong (plugins)Caddy (handlers)
Rate limitingBuilt-inlimit_req moduleratelimit filterRate Limiting pluginrate_limit handler
Auth delegationForwardAuthauth_requestext_authzOIDC pluginforward_auth
Circuit breakerBuilt-inNot nativeBuilt-inPlugin requiredNot native
Path rewritingBuilt-inrewriterewrite filterBuilt-inrewrite
CompressionBuilt-ingzip modulecompressorNot nativeBuilt-in
Dynamic configAuto (labels/CRD)Requires reloadxDS APIAdmin APIAuto (Caddyfile)
mTLS passthroughPassTLSClientCertssl_client_certBuilt-inPlugin requiredtls handler

Production Docker Compose Example

You have a production API service that needs HTTPS, rate limiting, security headers, and BasicAuth on the admin path.

services:
  traefik:
    image: traefik:v3.1
    restart: unless-stopped
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --providers.file.directory=/etc/traefik/dynamic
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entryPoint.to=websecure
      - --entrypoints.web.http.redirections.entryPoint.scheme=https
      - --entrypoints.websecure.address=:443
      - --certificatesresolvers.le.acme.email=ops@example.com
      - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.le.acme.tlschallenge=true
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt
      - ./dynamic:/etc/traefik/dynamic:ro
    networks:
      - edge

  api:
    image: ghcr.io/example/api:latest
    restart: unless-stopped
    networks:
      - edge
    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=le"
      - "traefik.http.routers.api.middlewares=secure-stack"
      - "traefik.http.services.api.loadbalancer.server.port=8080"
      # Security headers
      - "traefik.http.middlewares.hdrs.headers.stsSeconds=31536000"
      - "traefik.http.middlewares.hdrs.headers.frameDeny=true"
      - "traefik.http.middlewares.hdrs.headers.contentTypeNosniff=true"
      - "traefik.http.middlewares.hdrs.headers.browserXssFilter=true"
      # Rate limit
      - "traefik.http.middlewares.rl.rateLimit.average=120"
      - "traefik.http.middlewares.rl.rateLimit.burst=40"
      - "traefik.http.middlewares.rl.rateLimit.period=1m"
      # Compress
      - "traefik.http.middlewares.compress.compress=true"
      # Chain
      - "traefik.http.middlewares.secure-stack.chain.middlewares=hdrs,rl,compress"

networks:
  edge:
    external: true

The file provider at ./dynamic/ holds longer middleware definitions (auth credentials, circuit breaker expressions) that are impractical in labels.

Gotchas and Edge Cases

  • Dollar signs in BasicAuth hashes must be doubled ($$) in Docker labels because Docker Compose interpolates single $ as a variable.
  • Middleware order in a chain matters. Apply redirects before auth; apply compression last.
  • ForwardAuth latency adds one extra HTTP round-trip per request. Cache auth decisions in Authelia or OAuth2-Proxy to minimize impact.
  • RateLimit counters are per-replica. A deployment with three Traefik replicas effectively multiplies the allowed rate by three unless you use a shared store.
  • StripPrefix with forceSlash: false may cause 404s on upstreams that expect a trailing slash. Test with both values.
  • CircuitBreaker expressions use Traefik’s built-in expression language, not Prometheus PromQL. Refer to the Traefik docs for ResponseCodeRatio, NetworkErrorRatio, and LatencyAtQuantileMS.

Summary

  • Traefik middlewares attach to routers and transform requests before they reach upstream services
  • Use Headers for HSTS, CSP, and CORS; always remove sensitive upstream headers
  • RateLimit with sourceCriterion handles API throttling; set ipStrategy.depth behind CDNs
  • ForwardAuth integrates cleanly with Authelia and OAuth2-Proxy for SSO without modifying application code
  • StripPrefix, ReplacePath, and AddPrefix handle path normalization for multi-tenant routing
  • CircuitBreaker and Retry provide upstream resilience; combine them with Buffering for slow-upload protection
  • Chain middleware composes reusable security pipelines attachable to any router with one label
  • In Docker labels, double all $ characters in bcrypt/htpasswd hashes