PiHole Docker+Kubernetes

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 home assistant custom side panel
My pihole docker container runs in Kubernetes alongside Home Assistant using a custom panel.

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, 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, 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:


Name:   house.snowy-cabin.com

The PiHole (running at tells us that the server lives at But if we instead ask Google about this server (nslookup house.snowy-cabin.com


Non-authoritative answer:
Name:   house.snowy-cabin.com

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.

Embedding (IFrame)

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:

  enabled: true

  existingSecret: pi-hole-secrets

    metallb.universe.tf/allow-shared-ip: pi-hole
  type: LoadBalancer

    metallb.universe.tf/allow-shared-ip: pi-hole
  type: LoadBalancer

    - address=/house.snowy-cabin.com/

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.

Read the Diff

The Diff is a weekly email with step-by-step instructions, project ideas, and links. Drop your email in the form below, and I'll send you some of my favorite resources. The links cover everything from off-grid/vanlife construction to home automation and Raspberry Pis.

... but this site has no paywalls. If you do choose to sign up for this mailing list I promise I'll keep the content worth your time.

Written by
(zane) / Technically Wizardry
Join the discussion


Around the Web