Traefik’s headers middleware doesn’t just add or remove headers; it’s a powerful, albeit sometimes overlooked, tool for shaping HTTP requests and responses at the edge, acting as a fine-grained traffic manipulator before your services even see the traffic.

Let’s say you have a simple Traefik setup routing traffic to a backend service running on localhost:8080. Here’s the Traefik configuration:

# traefik.yml
entryPoints:
  web:
    address: ":80"

providers:
  docker:
    exposedByDefault: false

api:
  dashboard: true

# services.yml
http:
  routers:
    my-router:
      rule: "Host(`localhost`)"
      service: "my-service"
      entryPoints:
        - "web"

  services:
    my-service:
      loadBalancer:
        servers:
          - url: "http://localhost:8080"

  middlewares:
    add-custom-header:
      headers:
        customRequestHeaders:
          X-Custom-Request-Header: "MyValue"
    remove-user-agent:
      headers:
        browserForwarding: false # This is how you remove a header
    modify-x-forwarded-for:
      headers:
        customHeaders:
          X-Forwarded-For: "1.2.3.4" # This overwrites, not modifies

# routers.yml - linking middleware to router
http:
  routers:
    my-router:
      rule: "Host(`localhost`)"
      service: "my-service"
      entryPoints:
        - "web"
      middlewares:
        - "add-custom-header@file"
        - "remove-user-agent@file"
        - "modify-x-forwarded-for@file" # Example of modifying

Now, if you send a request to localhost with curl -v http://localhost, you’ll see Traefik in action:

*   Trying 127.0.0.1:80...
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.81.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/plain
< Content-Length: 15
< Date: Tue, 23 May 2023 10:00:00 GMT
< X-Custom-Request-Header: MyValue
< X-Forwarded-For: 1.2.3.4
< Server: Traefik
<
Hello, World!

Notice a few things:

  • X-Custom-Request-Header: MyValue was added to the request that Traefik forwarded to your backend.
  • The User-Agent header from your curl request is gone. Traefik’s browserForwarding: false setting on headers.browserForwarding tells it not to pass through browser-specific headers like User-Agent, Accept-Language, etc.
  • X-Forwarded-For: 1.2.3.4 is present. This is where it gets interesting. Setting customHeaders with a specific header name and value overwrites any existing header with that name. Traefik doesn’t append to X-Forwarded-For by default; it replaces it. This is a crucial distinction.

The core problem the headers middleware solves is the need for a centralized, configurable point to manage HTTP headers for requests and responses before they reach or leave your application services. This is invaluable for security, observability, and service integration.

Here’s how it works internally: Traefik processes middlewares sequentially based on their order in the router’s middlewares list. For each request, it iterates through the configured middlewares. The headers middleware specifically targets header manipulation.

  • customRequestHeaders: This section adds new headers or overwrites existing ones on the request going to your backend service.
  • customHeaders: This section, when used without specifying customRequestHeaders, acts on the response headers going back to the client. If you use it on a request-level router, it will overwrite the X-Forwarded-For (and others) as shown above.
  • browserForwarding: When set to false, it instructs Traefik to strip out common browser headers like User-Agent, Accept-Language, Accept-Encoding, and Referer. Setting it to true (or omitting it, as true is the default) allows these headers to pass through.

The most surprising thing about the headers middleware is how customHeaders interacts with X-Forwarded-For. Many expect X-Forwarded-For to be a cumulative list, with Traefik appending the client’s IP. However, the customHeaders configuration, when applied directly to a router, acts as a direct replacement. If you want to correctly append to X-Forwarded-For, you’d typically rely on Traefik’s default behavior or use specific plugins/configurations that handle IP address accumulation more intelligently, or even better, ensure your backend services are configured to trust the X-Forwarded-For header and append to it themselves if needed, or use Traefik’s forwardedHeaders middleware.

To truly append to X-Forwarded-For and maintain the chain of proxies, you’d typically use Traefik’s forwardedHeaders middleware instead of directly manipulating X-Forwarded-For with customHeaders. The forwardedHeaders middleware is designed to correctly manage the X-Forwarded-For and X-Forwarded-Proto headers, adding the client’s IP address to the X-Forwarded-For list.

The next logical step after mastering header manipulation is understanding how to manage request body transformations or how to implement rate limiting to protect your services.

Want structured learning?

Take the full Traefik course →