(This might be applicable to Manjaro on other architectures, too, but I know for sure it's applicable to ARM. Please move this post if it's in the wrong place.)
Continuing my adventures in Docker setup, started here: Pi Hole with/without Docker?
Source, with much more information and explanation: https://medium.com/@skleeschulte/how-to-enable-ipv6-for-docker-containers-on-ubuntu-18-04-c68394a219a2
My network runs both IPv4 and IPv6, and I get a public v6 address from my ISP with no issues. Since I wanted to set up docker specifically to run pi-hole, and I am capable of making IPv6 DNS resolution requests, I wanted to get v6 enabled in Docker.
Docker provides these instructions: https://docs.docker.com/config/daemon/ipv6/
A few points:
The instructions indicate a key-value pair should be added to
/etc/docker/daemon.jsonto enable IPv6. If this file does not exist, do not create it. Docker can take instructions on startup either from a
daemon.jsonfile or via command line flags. Trying to give it both can possibly lead to strange errors/docker failing to start, etc.
- Update: The docker docs (https://docs.docker.com/config/daemon/) say it's fine to use both as long as they don't overlap, and for reasons discussed below I think using both is probably ideal. My earlier statement came from some anecdotal reports of problems caused by mixing them. The key is not to use the command line and the .json file to set the same flags. Sorry for any confusion on this point.
When I installed docker from
pacman, it did not create the
daemon.jsonfile, so instead we're using command line flags.
The command line flags are passed to
dockerdin docker's system-wide
.servicefile's ExecStart command, at
Important: when you update docker through
pacman, the update will erase your changes to the comand line flags in the
docker.servicefile. You will need to put them back using the instructions below. (This is, I think, why it is considered preferable to use the daemon.json file to manage your settings. It should persist after package upgrades.
Option 1: Editing the .service file:
Critical: either back up this file or comment out the existing ExecStart command before adding a new ExecStart. If you do not input a valid replacement,
dockerdwill fail to start. Make sure you can bring it back.
- Edit the ExecStart command to look like this:
ExecStart=/usr/bin/dockerd -H fd:// --ipv6 --fixed-cidr-v6 "fd00::/80"
--fixed-cidr-v6gives docker an, in this case, locally accessible subnet of size /80 IPv6 addresses to play with. Without the subnet,
dockerdwill crash on start with a mildly spectacular error. You can give it a pool of globally accessible IPv6 addresses if your ISP issues you one of those, but this punches a massive hole in docker's isolation wall, as your containers are now using addresses on the public internet.
- Close and save the file.
- Critical: either back up this file or comment out the existing ExecStart command before adding a new ExecStart. If you do not input a valid replacement,
Option 2: Creating a
sudo nano /etc/docker/daemon.jsonto create a blank config file named
- Add the following key-value pairs to the file, exactly as written, then save and close the file:
systemctl restart docker.service
- If the service successfully restarts, IPv6 support is now enabled. If it doesn't, either you or I made a typo somewhere.
Inspecting your docker's bridge network should now look something like this. Notice the IPv6 bits:
- If you have an IPv6 address, but you don't see an IPv6 gateway: reboot the machine and check again.
- The subnet we assigned led to auto-creation of a default gateway on our local network. Without further configuration (see below), the bridge network's v6 topography cannot access the internet. The v4 gateway, by default, can. I'm still investigating how best to fix this.
Final Step: Figure out the best way to bug the docker developers to please make this simpler. It is my understanding that this not happening automatically just by using the enable IPv6 flag is actually a bug. Consider: IPv4 works automatically.
But wait! Sadly, that's not the end of it. While your docker containers can now get IPv6 addresses and do IPv6 things, they cannot access anything outside your local network, since you gave them a local subnet. To let them outside, you'll need to "enable NAT for the private Docker subnet on the host."
More critically, I'm not sure this command works on Manjaro yet, and even the vague idea of mixing NAT with IPv6 is giving me hives. Perhaps @Strit or @Darksky or @linux-aarhus might know for sure if it's safe to run this command on Manjaro.
EDIT 4 (What is time? When am I?)
I've blanked out all my attempts to helpfully summarize how to do the IPv6 routing with pure docker. I cannot get my head around that. All the information I had originally posted is up in the link at the top, but I'm afraid if I try to talk about it, I'll just do more harm than good.
New Strategy: Enable IPv6 routing on a per-container basis using docker-compose for new containers. This has the advantage of being much easier to understand. Also, it actually worked when I tried it, which is a plus.
(No, at this point I'm not sure how I found this. I actually got lost on Google and stumbled into a bugtracker report where someone happened to volunteer their working configuration.)
That's an example of a docker-compose setup for pi-hole, using cloudflared to provide DNS over HTTPS, and supporting IPv6 ad block. I hope. Still testing, but the service came up and the docker network looks good.
For existing containers: If you've already got a docker container you want to add IPv6 to, there's a way to do that. Here's an example, again using pihole.