Mimic IPv4 docker behavior for IPv6 with Shorewall and NAT


Docker IPv6 support is messed up. Instead of sharing a non-routed IPv6 prefix between host and containers, just like it does for IPv4, docker team decided to implement a full IPv6 support, with routing and everything.
The point is: most of people just want basic IPv6 inside the container (in my case I’m doing monitoring checks) and would love to have it working out of the box. Honestly, who wants a dedicated routed prefix for its IPv6 containers ? Certainly not me.

So here’s the trick: we’re going to use a chosen prefix between docker daemon and its host and we’ll use shorewall6 to NAT it when going outside. Basically it’ll mimic IPv4 behavior.

So first, make sure IPv6 is working correctly on host (actually while writing this doc, it was not on my sample setup :D):

Then, define a IPv6 prefix to be use inside docker by editing /etc/docker/daemon.json

Create the file if not existing yet.

Restart docker daemon:

Now your container should have an IP range in the range (and a default gateway):

You host should be able to reach the container too:

Here we go… Now all we need to do is make a source NAT of 2a00:1450::/64 when going out of eth0 on the host server.

For this, we’ll use shorewall:

And we’ll create a default configuration based on provided examples:

Default configuration can work but I’ll tweak it a bit.

In /etc/shorewall6/interfaces I renamed the interface to loc instead of net and disable routeur advertisment (IPv6 gateway statically defined in /etc/network/interfaces) and I need to define the docker bridge interface:

In /etc/shorewall6/zones there must be one ipv6 zone for each interface:

In /etc/shorewall6/policy I give full access to host server to any network, docker has access to local network (but not to its host) and I block everything else

Then, I create a few overrides in /etc/shorewall6/rules to authorize Ping and SSH from local network:

As you can see, there’s a few more rules: at least one containers uses a MariaDB server on the host, so I permit that. Also I permit Nagios NRPE and SNMP from local network to host (fw) for monitoring purpose and I also accept the same from container to host because there’s a monitoring container that will actually monitor its own host.

Now we need to NAT the private IPv6 subnet used by docker in /etc/shorewall6/snat

Finally we’ll enable IP_FORWARDING in */etc/shorewall6/shorewall.conf* by setting it to yes and restart shorewall:

And that’s it: