IPv6NAT in Unraid's Docker Containers Behind a Reverse Proxy to Make Outgoing IPv6 Requests Work

This tip is a bit out of context, but will make sense once I write more about the NAS I did set up.

The NAS I have runs Unraid. It’s a Slackware-based Linux operating system that provides a bit of redundancy/recovery from drive failures without the RAID setup overhead and performance penalties. More details will follow later.

With Unraid OS, you install web services as Docker containers. I have next to zero experience with Docker, so this was a “fun” experience.

For our ultimate goal to get rid of Dropbox, iCloud, Google Drive, and other cloud services, we wanted to have a self-hosted Nextcloud instance. In the past months, friends and I experimented with connecting our Nextcloud instances on our Raspberry Pis. That worked surprisingly well thanks to the power of IPv6.

A bit of backstore about IPv6: In Germany, it seems the trend is to vend IPv6 addresses from your internet service provider’s router to the computers in the network. Folks in chats from the UK told me they have a hard time getting an IPv6 at all. Here, you also still have IPv4 LAN addresses, like the classic 192.168.0.xxx namespace. Provided the router forwards ports 80 and 443 for HTTP and HTTPS traffic, respectively, I am able to use the IPv6 addresses of a friend’s device to get there from one machine in my network directly. I also just recently discovered this detail about IPv6 – that each IPv6 address in unique, unlike e.g., which is the LAN IPv4 address of my Unitymedia/Vodafone ConnectBox router, and all similar routers in all my neighbors’s homes. The router has a globally unique IPv6 namespace within which it can assign IPs freely. These globally unique namespaces are super cool, because you don’t need to use port forwarding in the router to forward to a particular device in the LAN. You just “open” the port and then then each device in your LAN with a globally unique IPv6 can be accessed from anywhere else on the planet. (Which is also a risk, of course.)

With the successful connection between Raspberry Pis, I wanted to get something similar with the Unraid NAS. It works in a similar fashion: install the Nextcloud Docker container, map its ports 80/443 to something that’s not used by Unraid itself (e.g. 8080/8443) and then you can access it directly using these ports.

But the approach I picked is installing a reverse proxy that receives all traffic on the standard ports and then forwards the requests to Docker containers based on the request, e.g. based on subdomain matching rules or sub-directories.

The subdomain-based approach works out this way:

  • example.com is answered by the reverse proxy itself,
  • nextcloud.example.com is received by the proxy, and based on a nextcloud.* rule, it forwards requests to a Nextcloud container.
  • phpmyadmin.example.com is received by the proxy and forwarded to a phpmyadmin.* container.

Up until today, I had trouble with making outgoing IPv6 connections from containers in the proxy network, though.

The problem seems to be Docker’s own support of IPv6, especially with v19.10.3 that’s shipped with Unraid OS at the moment. (v20.x ship with IPv6 NAT, it seems!) IPv6 is an afterthought in Docker – at least that’s what folks on the internet say.

A simple test is to run ping6 google.com – that works fine from the Unraid box itself, but not from within containers inside the reverse proxy network. Similarly, curl -vI <raspberry-pi-with-ipv6-address-only> times out. From within the Nextcloud container, sharing folders with the existing Raspberry Pi instances times out, too.

Solving IPv6 NAT with a Container

To make IPv6 work with Docker containers, we’re supposed to turn on IPv6 NAT. It’s a built-in feature since 20.03 or so, but not available in the Unraid Docker version.

With reverse proxies, the containers are expected to be in an internal bridge network, the proxy network, created via e.g. docker network create --ipv6 proxynet. Details will follow in later installments/write-ups.

To get this feature in the Unraid proxy net, install https://github.com/robbertkl/docker-ipv6nat from Docker Hub in Unraid by adding a custom container:

  • Repository: robbertkl/ipv6nat
  • Network Type: Host
  • Privileged: On
  • Add path assignment: /var/run/docker.sock <-> /var/run/docker.sock (read-only)

Without the path, the log will show that unix:///var/run/docker.sock requests fail because the path isn’t available inside the container.

Assuming that the proxynet network exists, all containers except ipv6nat need to stay in the bridge proxy network. ipv6nat is part of the host network, so it can manage the other containers’s network settings/IP assignments.

After restarting the proxy and Nextcloud and what have you, outgoing IPv6 requests now should work!

I cannot yet interpret these findings. Did the IPv6 requests not go out at all? I don’t think so, because domains were resolved to IPV6 addresses; did the responses not reach the container? That’s likely.

So this is a fix to a problem that bugged me on and off for the past months – because, for one, the NAS itself did cost money to build but didn’t provide any value unless I could trust the whole thing to work properly.

With IPv6 NAT bolted on, Unraid 6.8 with Docker 19.10 can do the job. I bet in next to no time at all, Unraid 6.9 will come out and ship with a Docker version that does IPv6 NAT natively …

In the meantime, I’ll whip up an easier to install Unraid container for this purpose so others can benefit from this finding, too.