Pihole, Tailscale, NAS, and Docker
June 08, 2022 -For about a year now, I've used pi-hole as a network-level ad-blocking solution in our home network. The result has been a very pleasant upgrade of our internet usage, so much so that it's hard to imagine going back now.
Recently, however, I've been brainstorming more uses for the Raspberry Pi, reimagining it as a lightweight home server and not just a dedicated network device. The primary goals of this exercise were the following:
- Network-attached storage (NAS): a central storage server for shared access from devices on the home network
- Media consumption: applications such as Plex and Navidrome for enjoying personal media including movies, TV, and music
While achieving each of those goals was an interesting journey in and of itself, the focus of this post is on a third goal that considerably amplifies the value of a home server: a self-hosted VPN.
Why self-host a VPN?
VPNs have many uses, from accessing corporate networks securely to having network traffic appear to be coming from your home location while traveling. Typically, those VPNs are hosted by either your employer or a third-party company. However, in a self-hosted VPN, the VPN is administered on devices you own, and the objective is to securely access assets in the home network from trusted devices while they are not natively in the network.
This unlocks, for example:
- Ad-blocking with pihole from mobile devices around town or while traveling
- Access to home media on the road
- Ability to access personal files from anywhere
...all with the protection of network-level security (i.e. without exposing services directly to the internet).
Setting it up
My VPN of choice is Tailscale, which is an offering built on top of WireGuard, an open-source and highly-regarded general-purpose VPN. In particular, Tailscale is a mesh VPN, meaning that devices on the network connect directly to peer devices (in contrast to traditional VPNs in which traffic routes through a central hub). Specifically, Tailscale manages the configuration and provisioning of the network topology, so that peers know about one another and can connect to one another securely using modern cryptography and clever networking.
Setting up a Tailscale network is quite easy - first you register for an account (the free tier is really quite generous), and then you install the software package on each device in the network. Thankfully, they have all the major desktop and mobile OSes covered, which is great, because many of the best benefits of this VPN will be seen on mobile devices.
A problem: Pihole and Docker
With tailscale installed on all of the relevant devices (e.g. Raspberry Pi, cell phone, laptop), this means that all devices should have access to the network services running on the Raspberry Pi, regardless of their true network location, correct?
Not so fast (at least, depending on your installation of pihole). It turns out that many of the mainstream suggestions for running Pihole on a NAS recommend running it in a Docker container. That is, the most widely-used pattern is to have the NAS server natively run a build of your NAS software (Synology, TrueNAS, Unraid, Openmediavault, etc.), and then to run additional services via Docker, presumably to streamline service administration and to reduce exposure of services to the actual underlying OS.
Under this pattern, network services run in docker containers and then map ports back to the host
OS. However, there is a problem. Both pihole and your NAS software likely compete for port 80. That
is, let's say the IP address of your NAS server is 192.168.0.2; likely accessing
http://192.168.0.2
takes you to the NAS administration page. Since pihole also wants to serve on
port 80, most installation guides using Docker (such as this
one suggest
creating a macvlan network, which essentially exposes
pihole under a new IP address. As a result, the rest of the home network would understand pihole to
be running on (say) 192.168.0.3, and the fact that it is actually in a docker container on the NAS
server is just an implementation detail.
You may be able to see where this is going - if we must direct DNS traffic in the home network to 192.168.0.3 to get the benefits of ad-blocking, that is well and good from within the native home network, but not if we want to also enjoy ad-blocking from devices on the Tailscale VPN, because we have no ability to natively install Tailscale on 192.168.0.3.
Solutions
Conceptually, there are at least 3 possible ways to resolve this:
- Set up a subnet router in Tailscale.
- Run pihole on a dedicated device (i.e. other than the NAS), on which you can natively install Tailscale.
- Tweak the installation of Pihole so it is compatible with the host NAS installation.
In (1), the subnet router would natively integrate with Tailscale, and it would relay traffic to and from other devices in the network, which do not need to natively integrate. While this is an attractive option in some ways, it proved to be difficult to set up in a satisfactory way. The only IP available on the tailscale network for DNS resolution would be the (Tailscale) IP of the Raspberry Pi, whereas the IP address serving Pihole is still the virtual IP on the macvlan network. I believe this option would work if one could relay traffic from 192.168.0.2 on port 53 to 192.168.0.3. While this seems to be possible, it involves some complex virtual networking setup (described here) and even after following the steps, I could not get it to work.
(2) would be very functional, but a bit more costly. With 2 Raspberry Pis, for example, one could run Pihole natively and the other could run openmediavault, and each could be natively connected to Tailscale.
I was considering resorting to (2), but as I had only one Raspberry Pi at the time of writing, I
wanted to explore all the alternatives before purchasing a potentially unnecessary device. It turns
out that there is a fairly straightforward solution, (3). Recall that the main conflict between the
NAS software and Pihole is the use of port 80. Rather than use port 80, then, we can simply use the
WEB_PORT
environment variable in
the Pihole installation to specify a different port (such as port 81). This worked like a charm and
is the method I use currently; I just need to remember to specify the port when administrating
pihole.
Conclusion
The result of all our labors? Seamless ad-blocking enjoyed both within the home network and for devices on Tailscale VPN!
Note: I've only used Openmediavault personally, but I don't see any reason why this method would not work on other NAS installations such as Synology, TrueNAS, Unraid, etc..