Manually Assigning an IPv6 address to HAProxy container for correct x-forwardfor logging

I’m currently running a single instance of Docker on a single VM. I’ve assigned Docker an IPv6 CIDR because I want to support IPv4 and IPv6 connections. Here is my daemon.json

{
"tls": true,
"tlsverify": true,
"tlscacert": "/etc/docker/ca.pem",
"tlscert": "/etc/docker/server.crt",
"tlskey": "/etc/docker/server-key.pem",
"ipv6": true,
"fixed-cidr-v6": "2001:19f0:6001:1c12::/80",
"hosts": ["127.0.0.1:2376", "10.10.6.10:2376", "fd://"]
}

So I have my HAProxy container, it has 80/443 exposed, and it has option forwardfor set so my backend servers get the client’s real IP address. This works great … for IPv4. The DNS for my websites is pointed to the public address of the box itself. Docker/IPv4 forwards ports directly between the box’s public IP and the HAProxy container. However for the public IPv6 address, it translates it to IPv4! Now in my nginx/apchee logs, I just get the internal IPv4 address of the Docker bridge 172.17.0.1.

Now I realize, I can just point the DNS AAAA record to the IPv6 global address of my HAProxy container, open up 80/443 on my ipv6 firewall and now I’ll get the client’s real IP address forwarded on. The trouble is, for that to be viable, I need a static IPv6 address on that container using the default network. I have no idea how to do this. If I use --ip6 2001:19f0:6001:1c12::a100:a100:a100:1, I get the error User specified IP address is supported on user defined networks only.

I’ve already built a full provisioning tool in Ruby called Bee2, which just simply creates container links and does everything on the default network. Is there no way to pin a given IPv6 address to a given container, without using a user defined network? Why are IPv6 ports not bound directly into the container like they are with IPv4?

All I really want are the client’s real IPv6 addresses in the Apache/Nginx logs in the simplest way possible. What are my options at this point?

if you use the -6 parm then the network addressing will be ipv6

to force a specifc ip address 4 or 6 needs a --network created

I didn’t use the the -6 parm. I used the Docker Engine API and did everything in code. I was hoping I could get away with fixing this without having to refactoring huge sections of it to add networks.

Using the Docker Engine API, it will still automatically assign IPs if I don’t specify them right? Like the following

     'NetworkingConfig' => (
       {'EndpointsConfig' =>
         {'bee2-network' =>
           {'IPAMConfig' =>
             {'IPv6Address' => static_ipv6}
           }
         }
       }

I’ll still get an auto-assigned IPv4 address correct? And if I just have an EndpointConfig with a name and no other parameters, it will auto-assign both?

The real issue; the problem I’m trying to solve, is the IPv6 incoming port on the host gets translated into IPv4 before hitting HAProxy; losing the client-ip for logging purposes. The connection still works. IPv4 doesn’t do this and hands HAProxy the actual client IP. If there’s anyway to get that same functionality out of IPv6 in Docker, that’d be a much easier solution.

i have no experience with the APIs

In case anyone else is interested, I figured this out myself. I ended up splitting my IPv6 /80 subnet into two /96 subnets. I assigned one to the default Docker bridge and created a user defined network with the second. I then used the IPAMConfig settings I listed above to set a static IPv6 address within the 2nd subnet for my HAProxy container and setup my DNS AAAA records to hit that address. I also had to enable IPv6 support on HAProxy and add firewall rules for that static IPv6 address.

A full writeup can be found at the following: