Traefik v2.1.4: X-Forwarded-For header doet not pass visitor IP when using IPv6

We use Traefik as a front-end for multiple containers running websites, and some of these sites need an ip-whitelist.

In order to do this we create an ipwhitelist middleware that is part of a chain. We craft a docker run command shown below, filled using parameters passed by our CI/CD pipeline:

docker run \
                --name $name \
                --restart unless-stopped \
                -l traefik.enable=true \
                -l "traefik.http.routers.$name.rule=Host(\"$hostheaders\")" \
                -l traefik.http.routers.$name.entrypoints=http,https \
                -l traefik.http.routers.$name.tls=true \
                -l traefik.http.routers.$name.tls.certresolver=letsEncryptResolver \
                -l$name.loadbalancer.passhostheader=true \
                -l traefik.http.routers.$name.middlewares=securedWhitelist-$name \
                -l traefik.http.middlewares.securedWhitelist-$name.chain.middlewares=https-redirect,hsts-header@file,optional-ipwhitelist-$name \
                -l traefik.http.middlewares.optional-ipwhitelist-$name.ipwhitelist.sourcerange=$whitelist \
                -l traefik.http.middlewares.optional-ipwhitelist-$name.ipwhitelist.useXForwardedFor=true \
                -l traefik.http.middlewares.https-redirect.redirectscheme.scheme=https \
               -l traefik.http.middlewares.https-redirect.redirectscheme.permanent=true \
               -l traefik.http.middlewares.https-redirect.redirectscheme.port=443 \
                -l$name.loadbalancer.server.port=$port \
                -d $image

So, the whitelist middleware expects the $whitelist parameter, which is a set of comma separated ip-addresses.

This is all fine and pretty cool, but it depends on the correct ip-address being passed to this middleware and what we actually receive is the IP-address of the Traefik instance. See this snippet of the containous/whoami image:

X-Forwarded-Port: 443
X-Forwarded-Proto: https
X-Forwarded-Server: 20ec8fde9d29

So, that is useless for our purposes.

However, the above is true when you connect to this instance using IPv6! When you connect using IPv4 containous/whoami tells us the following:

X-Forwarded-For: 89.20.***.***
X-Forwarded-Port: 443
X-Forwarded-Proto: https
X-Forwarded-Server: 20ec8fde9d29
X-Real-Ip: 89.20.***.***

So, when Traefik routes traffic to its containers and is accessed via IPv6 it uses the internal IPv4 network addresses and does not pass the correct IPv6 address in the X-forwarded-for and X-real-ip headers.

You could say this is a bug, but maybe this is something you can prevent if you use IPv6 in the docker network? We switched back from using swam mode because IPv6 was a horror to configure in the docker network.

Does anyone have this same issue?


Have you configure the forwarded-header options?

I have looked in to those headers but it was unclear to me what IP-addresses should be added as trusted.

     trustedIPs = ["", ""]

Should the trustedIPs be the addresses of the traefik instance itself? The docker host is an single instance without any additional proxies in front of it.

For now I am using the following static configuration:

  address = ":80"

      trustedIPs = ["", ""]
      insecure = true

  address = ":443"
      trustedIPs = ["", ""]
      insecure = true

I'm seeing the same issue, we recently saw a few clients on IPv6 and found their IPv6 was blank in our case, version traefik:v2.2

Have you found any solution to this?

I found that the forwardedHeaders forwarded for instance the username from basic auth.

But X_FORWARDED_FOR is still, the IP of traefik, not the client.

1 Like

A year later, with traefik 2.5.4 I get the real client ip in X-Forwarded-For if I use ipv4, but the IPv6Gateway fd30:1::1 on the proxy network, when I use IPv6

I'm using the image: "traefik/whoami" to see this.

I'm seeing something along these lines, all I get in the X-Forwarded-For is the actual K8S host, rather than the client (i.e. my laptop).

Add this to /etc/docker/daemon.json:

 "experimental": true, 
 "ip6tables": true 


  "ipv6": true,
  "fixed-cidr-v6": "fd..::/64",
  "experimental": true, 
  "ip6tables": true