In This Post...
PiHole blocks advertiser traffic from an entire network, and can even help to speed up the network. Running PiHole Docker+Kubernetes poses a couple interesting challenges.
This is one of several posts on containerization of common, useful software.
PiHole Docker Considerations
Stability is very important when it comes to Pi-Hole, since it acts as a DNS server. If you haven’t already done so, make sure your home server is highly-available.
If Pi-Hole is down, any devices using Pi-Hole as the DNS server will slow to access the internet at best (assuming they have a secondary DNS server, like Google’s
18.104.22.168, to fall back upon) or unable to access the internet at worst (if there is no secondary, reachable DNS server). Setting Pi-Hole as the primary DNS server on the router means that this applies to every device on the network. This is the best way to achieve the benefits of Pi-Hole for every device, but makes it imperative that the docker container not stop running.
Some users may decide that they prefer to run Pi-Hole directly on the host rather than inside Docker/Kubernetes, since these add additional points of potential failure. I prefer to run everything in Kubernetes because it gives me convenient observability tools, allowing me to monitor everything remotely.
It may be tempting to run Pi-Hole in host networking mode, but I prefer to avoid that whenever possible…
Kubernetes Helm Chart
As of this writing, there is not an official (“stable”) Kubernetes helm chart for Pi-Hole. However, I was able to get the Pi-Hole helm chart from mojo2600 working well.
In the README, there is a reference to MetalLB (a load balancer for baremetal clusters). For running a home server, this is an excellent way to assign a static IP without resorting to hostNetwork or NodePorts.
Custom DNS Names (DNSMasq)
When accessing the home server(s) — running things like Home Assistant — it’s best if the traffic never leaves the local network. This is faster (no internet requests to the outside world) and more secure (no data leaves the network).
A typical way of going about this is to access the server via the LAN IP address when on the local network, and otherwise to use the public domain name. However, this complicates various other tasks because it becomes necessary to write software that uses the URL appropriate to the context. In some cases, this may even become prohibitive (when a server expects to be accessed at a specific URL).
Instead, it’s possible to use Pi-Hole to run dnsmasq, which effectively allows you make it so that queries from inside the network receive the local IP address of the server instead of the remote IP address (see below for configuration files).
For example, in the cabin, Home Assistant runs on a server on the local network at
192.168.0.100, which is accessible to the outside world as
house.snowy-cabin.com. Normally, users typing this URL in the browser would receive back the public IP address (as described in creating a server with a custom domain name). However, when inside the network, we can run
nslookup house.snowy-cabin.com to see:
Server: 192.168.0.101 Address: 192.168.0.101#53 Name: house.snowy-cabin.com Address: 192.168.0.100
The PiHole (running at
192.168.0.101) tells us that the server lives at
192.168.0.100. But if we instead ask Google about this server (
nslookup house.snowy-cabin.com 22.214.171.124):
Server: 126.96.36.199 Address: 188.8.131.52#53 Non-authoritative answer: Name: house.snowy-cabin.com Address: 184.108.40.206
Queries coming from the outside world instead connect to the public IP.
Using Switchboard, https and client IP addresses are supported natively. This means that I can type
https://house.snowy-cabin.com in the browser at home, have a secure/encrypted connection to the local server, and the server is able to identify my LAN IP address as making the request. This enables features like Home Assistant’s trusted networks & trusted users. Because Home Assistant can identify the request as coming from the LAN, it is able to bypass the login.
I like using Home Assistant as a hub for the various services on my network, including PiHole. This requires embedding the admin interface in an iframe, which is tricky because PiHole configures
lighttpd to DENY cross-origin requests.
A work-around is to edit
/etc/lighttpd/lighttpd.conf; from within the docker container:
sed -i "s/\"DENY\"/\"ALLOW\"/" /etc/lighttpd/lighttpd.conf \ && service lighttpd restart
Unfortunately, this does not survive restarts, and attempting to override the value in
/etc/lighttpd/external.conf has thusfar been unsuccessful.
My Deployment File(s)
Here are the
values.yaml I use with the helm chart:
persistentVolumeClaim: enabled: true admin: existingSecret: pi-hole-secrets serviceTCP: loadBalancerIP: 192.168.0.101 annotations: metallb.universe.tf/allow-shared-ip: pi-hole type: LoadBalancer serviceUDP: loadBalancerIP: 192.168.0.101 annotations: metallb.universe.tf/allow-shared-ip: pi-hole type: LoadBalancer dnsmasq: customDnsEntries: - address=/house.snowy-cabin.com/192.168.0.100
The persistentVolumeClaim refers to NFS volume, configured via the nfs-client-provisioner chart. The admin.existingSecret uses a pre-existing password for login to the PiHole docker frontend (web UI).
Other than that, the configuration more or less matches the example in the helm chart.