Featured image of post Setup IPv6 properly on docker (Fix Source IPv6 propagation)

Setup IPv6 properly on docker (Fix Source IPv6 propagation)

If you’re wondering why there are a lot of connections coming from your docker gateway right after you enabled IPv6 for your services, you’ve come to the right place.

Unfortunately, setting up IPv6 support for Docker isn’t as simple as setting up a DNS record and exposing the container to all interfaces.

If you just expose the container to an IPv6 connection without any additional setup, it will work, but without any IPv6 source propagation, you will get a lot of connections seemingly coming from the Docker gateway (usually starting with 172).

The fix for this is to make sure all networks from the bridge network to the internal docker compose networks are IPv6 ready, one network that is IPv4 only will bring the problem back.

Enable IPv6 support

/etc/docker/daemon.json

1
2
3
4
{
  "experimental": true,
  "ip6tables": true
}

This will enable ipv6tables support for Docker, which allows port mapping and network isolation, but requires the experimental flag.

Enabling IPv6 on the default bridge network

Enabling ipv6 in the config should be enough now, but to make sure all networks are IPv6 enabled, we add IPv6 to the default bridge network.

/etc/docker/daemon.json

1
2
3
4
5
6
{
  "ipv6": true,
  "fixed-cidr-v6": "2001:db8:1::/64",
  "experimental": true,
  "ip6tables": true
}

Dynamic IPv6 Subnet Allocation

Now with the previous settings you should be ready to go. However, you will need to manually set a subnet for each network, either within Compose or with docker network create --ipv6 --subnet=xxx $NETWORK_NAME.

If you want Docker to automatically allocate subnets, as it does with IPv4, you will need to provide it with a pool.

/etc/docker/daemon.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
  "ipv6": true,
  "fixed-cidr-v6": "2001:db8:1::/64",
  "experimental": true,
  "ip6tables": true,
  "default-address-pools": [
    { "base": "172.17.0.0/16", "size": 16 },
    { "base": "172.18.0.0/16", "size": 16 },
    { "base": "172.19.0.0/16", "size": 16 },
    { "base": "172.20.0.0/14", "size": 16 },
    { "base": "172.24.0.0/14", "size": 16 },
    { "base": "172.28.0.0/14", "size": 16 },
    { "base": "192.168.0.0/16", "size": 20 },
    { "base": "2001:db8::/104", "size": 112 }
  ]
}

2001:db8::/104 should not be used as a real subnet, it’s for documentation purposes only. If you want a local pool, go to simpledns.plus and replace the first two address blocks with those generated by the site.

Now restart the docker daemon:

1
sudo systemctl restart docker

Migrating Existing Containers / Docker Compose Projects

Restarting the daemon alone won’t be enough if you have containers running, especially those inside a Docker Compose project using an internal network.

You will need to remove all containers connected to a network other than bridge.

If you are using Compose, first delete all containers and their networks (this should’t delete volumes):

1
docker compose down

Add enable_ipv6: true to all networks, if you didn’t define any networks, then you are using the default network, and you should define it and add the option to it:

1
2
3
networks:
  default:
    enable_ipv6: true

Classic docker networks need to be removed and rebuilt with the --IPv6 option:

1
docker network rm $NETWORK && docker network create --ipv6 $NETWORK

Now you should have full IPv6 support with proper IPv6 source IP propagation.

Testing the changes

To make sure it actually works, run a Python container connected to a network you’ve created and see if it propagates the address or not:

1
docker run -p 8080:8080 --rm -it --network $NETWORK python:latest python3 -m http.server 8080 --bind ::

Now just connect to it on port 8080 and see if the IP is displayed correctly.

If the source still shows up as a local IPv4 address, just test it with the bridge network:

1
docker run -p 8080:8080 --rm -it python:latest python3 -m http.server 8080 --bind ::

If it works, then the problem is that the network you are using doesn’t have IPv6 enabled, if it still doesn’t work, make sure the config changes have been applied!

sources

https://docs.docker.com/config/daemon/ipv6/

FarisZR
Built with Hugo
Theme Stack designed by Jimmy