===== Setting up IPv6 NAT in Docker =====
Yes, I know NAT on IPv6 is evil. But Docker's IPv6 implementation is so flawed that this is the only feasible way to get egress traffic from containers working somewhat reliably.
If you want your containers to be able to establish egress connections over IPv6 using the same source address as non-containerized services on the host - such as the reverse proxy - using NAT on IPv6 does make some sense.
----
\\
==== Configuring Docker to use IPv6 ====
First, install Docker:
sudo apt install docker.io docker-cli
Then configure Docker to enable IPv6:
{
"ipv6": true,
"fixed-cidr-v6": "2001:db8:db8::/64"
}
Restart Docker:
sudo systemctl restart docker
You should now see an ''inet6'' address for the ''docker0'' interface:
$ ip addr show dev docker0
docker0: mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:35:12:16:5c brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 2001:db8:db8::1/64 scope global
valid_lft forever preferred_lft forever
----
\\
==== Configuring the firewall to forward packets ====
By default, Linux does not allow packet forwarding, and Docker only manipulates the IPv4 forwarding rules when started, even when IPv6 is enabled. So you'll have to configure everything yourself.
\\
=== sysctl values ===
Create a file called ''/etc/sysctl.d/packetforwarding.conf'' and add these lines:
net.ipv6.conf.all.forwarding=2
net.ipv6.conf.all.proxy_ndp=1
Then load them:
sudo sysctl -p /etc/sysctl.d/packetforwarding.conf
In some cases you have to reboot for this to actually delegate to your network interface. It can also help to set it manually once:
sudo sysctl -w net.ipv6.conf.ens3.forwarding=2
sudo sysctl -w net.ipv6.conf.ens3.proxy_ndp=1
(Change ''ens3'' to the interface your server uses to connect to the internet.)
\\
=== Firewall rules ===
Start by installing UFW:
sudo apt install ufw
By default, UFW changes your iptables/nftables rules to deny all ingress traffic, allow all egress traffic and disable routed traffic. Keep that in mind when you enable it.
Edit ''/etc/ufw/before6.rules'' to allow masquerading for the Docker subnet (or even a larger one if you want). Add these lines at the top of the file:
# Docker
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 2001:db8::/32 -o ens3 -j MASQUERADE
COMMIT
(Change ''ens3'' to the interface your server uses to connect to the internet.)
To allow IPv6 NAT on the interfaces dynamically generated by ''docker compose'', set the default routing policy to ''Allow'':
sudo ufw default allow routed
Finally, you have to allow (some) ingress traffic to avoid locking yourself out when you enable the firewall. You have two options:
1. Allow all ingress traffic:
sudo ufw default allow incoming
2. Allow ingress traffic on the ports you actually use:
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
This example allows only SSH, HTTP and HTTPS. Of course, add all the ports you want to be able to reach from the outside.
All that's left is to enable the firewall:
sudo ufw enable
Your Docker containers should now, hopefully, be able to access the internet over IPv6.
----