Homelab from Zero #4: Pi-hole, network-wide ad blockingHomelab from Zero #4: Pi-hole, network-wide ad blocking

Homelab from Zero #4: Pi-hole, network-wide ad blocking

This is part 4 of Homelab from Zero. In part 3 you installed Docker and ran your first service. Today the whole household benefits: we’ll run Pi-hole, an ad blocker that works at the network level, so every phone, laptop, and smart TV gets cleaner pages with nothing installed on them.

How blocking the whole network works

Every time a device loads a page, it first asks a DNS server “what’s the address for ads.example.com?” Normally your router forwards that question to your ISP and gets an answer. Pi-hole sits in the middle as your DNS server: for normal sites it answers truthfully, but for known ad and tracker domains it answers “nowhere,” so the ad never loads.

Because every device already asks DNS for everything, you block ads everywhere by changing one setting, no per-device apps, no browser extensions.

Step 1: Free up port 53 (Ubuntu only)

Pi-hole needs port 53, the DNS port. On Ubuntu Server a background service called systemd-resolved is already sitting on it, so we move it aside first:

sudo sed -i 's/#DNSStubListener=yes/DNSStubListener=no/' /etc/systemd/resolved.conf
sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
sudo systemctl restart systemd-resolved

On a Raspberry Pi running Raspberry Pi OS you can skip this step, port 53 is already free.

Step 2: Run Pi-hole

Same docker run shape as part 3, with a few more lines. Pick a real password where it says changeme:

docker run -d \
--name pihole \
-p 53:53/tcp -p 53:53/udp \
-p 8081:80 \
-e TZ=Etc/UTC \
-e FTLCONF_webserver_api_password=changeme \
-e FTLCONF_dns_listeningMode=ALL \
-v ~/pihole:/etc/pihole \
--restart unless-stopped \
pihole/pihole:latest

What the new pieces do:

Piece Plain English
-p 53:53/tcp -p 53:53/udp The DNS port: this is what devices will ask
-p 8081:80 The admin web page (part 3’s Heimdall already has 8080)
-e TZ=Etc/UTC Your timezone, so the graphs read right: set your own
FTLCONF_webserver_api_password The password for the admin page
FTLCONF_dns_listeningMode=ALL Answer queries coming from other devices

Step 3: Open the dashboard

On your normal computer, visit the server’s address from part 2 with the admin port and /admin on the end:

http://192.168.1.73:8081/admin

Log in with the password you set. You’ll see a dashboard with a queries graph, empty for now, because nothing is using Pi-hole yet. Let’s fix that.

Step 4: Point your network at it

The easiest way to cover every device at once is to set Pi-hole as the DNS server on your router. Log into your router’s admin page (the same one from part 2), find the DNS or DHCP settings, and set the primary DNS server to your Pi-hole’s address:

192.168.1.73

Leave the secondary blank, or set it to the same address, if you list your ISP’s DNS as backup, devices will quietly use it and skip the blocking.

Save, then reconnect a device to the network (toggle Wi-Fi off and on). Reload a few pages and watch the queries graph on the dashboard start to climb. That’s your whole house flowing through Pi-hole.

Can’t change the router? Some ISP routers don’t allow it. As a fallback, set the DNS manually on individual devices instead, same address, in each device’s network settings.

The commands you’ll actually use

Command What it does
docker logs pihole What is Pi-hole saying? (start here if DNS breaks)
docker exec pihole pihole -g Update the block lists
docker exec -it pihole pihole setpassword Change the admin password
docker restart pihole Turn it off and on again
docker stop pihole Stop it: the network falls back to the router’s DNS

One safety note: if you ever delete the container while the router points at it, the house loses DNS until you change the router back. Stopping Pi-hole is fine, just set the router’s DNS back to automatic first if you’re removing it for good.

What you have now

Network-wide ad and tracker blocking from a single container, covering every device that touches your network, and a dashboard that quietly shows how much junk it’s swatting. The pattern is the same one from part 3: one docker run, a port, a config folder.

In part 5 we make the lab tell us when something’s wrong: Uptime Kuma, monitoring with alerts, so you find out a service is down before the household does.


← Back to blog

Following along?