Sick of seeing ads on every single device in your house? Banner ads on your phone, video ads on the smart TV, tracking scripts following you around the web on your laptop — it's relentless. You could install an ad blocker extension on every browser, but that doesn't help your phone apps, your smart TV, or your IoT gear. Pi-hole fixes all of that in one hit. It blocks ads and trackers at the DNS level for your entire network — phones, tablets, smart TVs, game consoles, everything. No extensions needed, no per-device setup, just clean browsing across the board.

What Is Pi-hole?

Pi-hole is a DNS sinkhole — basically a DNS server that sits on your network and intercepts every DNS request from every device. When something tries to load a domain that's on a known ad or tracking blocklist, Pi-hole intercepts the request and returns a blank response instead of the ad content. The ad simply never loads. Your browser (or app, or smart TV) just gets nothing back, so the ad space stays empty and the page loads faster.

It works for every device on your network, no configuration needed on the devices themselves. If it uses your network's DNS, Pi-hole is filtering it.

How It Works

The flow is dead simple:

  1. Your router points all DNS queries to Pi-hole (instead of your ISP's DNS or Google's)
  2. Pi-hole receives the DNS request and checks it against its blocklists
  3. If the domain is on a blocklist (e.g. ads.doubleclick.net), Pi-hole returns 0.0.0.0 — the ad never loads
  4. If the domain is clean, Pi-hole forwards it to an upstream DNS server (like Cloudflare or Google) and returns the real IP as normal

That's it. No agents, no proxies, no packet inspection. Just DNS filtering. Simple and effective.

Docker Compose Setup

Here's a clean Docker Compose config to get Pi-hole running. Create a directory for it and drop this into a docker-compose.yml:

services:
  pihole:
    image: pihole/pihole:latest
    container_name: pihole
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "80:80/tcp"
    environment:
      - TZ=Australia/Sydney
      - WEBPASSWORD=changeme
      - FTLCONF_LOCAL_IPV4=192.168.1.x  # your Docker host IP
    volumes:
      - ./pihole/etc-pihole:/etc/pihole
      - ./pihole/etc-dnsmasq.d:/etc/dnsmasq.d
    restart: unless-stopped

A few things to note:

  • 53:53/tcp and 53:53/udp — DNS runs on port 53, both TCP and UDP
  • 80:80/tcp — The web admin dashboard
  • WEBPASSWORD — Set this to something decent, it's your dashboard login
  • FTLCONF_LOCAL_IPV4 — Replace 192.168.1.x with the actual IP of your Docker host on your local network

Deploy It

Spin it up:

docker compose up -d

Give it a minute to pull the image and start up. Once it's running, open http://your-ip/admin in your browser and log in with the WEBPASSWORD you set in the compose file.

Pointing Your Network to Pi-hole

This is the important bit — you need to tell your devices to use Pi-hole as their DNS server. You've got two options:

Option 1 (recommended): Change DNS in your router's DHCP settings

Log into your router and find the DHCP settings (usually under LAN or Network settings). Change the DNS server to the IP address of your Pi-hole host. Every device on your network will automatically pick it up next time they renew their DHCP lease. This is the set-and-forget approach — all devices are covered, no per-device faffing about.

Option 2: Set DNS per-device manually

If you want to test Pi-hole before going all-in, you can manually set the DNS server on individual devices. Go into your device's network settings, find DNS, and point it at your Pi-hole IP. Handy for testing, but not great long-term since you'd need to do it on every device.

The Dashboard

Pi-hole's admin dashboard is genuinely excellent. It shows you:

  • Total queries and percentage blocked
  • Queries over time (nice graph showing activity throughout the day)
  • Top blocked domains — you'll be surprised how chatty some apps are
  • Top permitted domains
  • Query log — every single DNS request, searchable and filterable
  • Client activity — see which devices are making the most queries

It's a real eye-opener. You'll quickly see just how much tracking and telemetry is happening on your network.

Adding More Blocklists

Pi-hole ships with a solid default blocklist, but you can add more for broader coverage. Head to Settings > Adlists in the dashboard and add URLs to additional blocklists.

The best source for curated community blocklists is firebog.net. They categorise lists by type (advertising, tracking, malicious, etc.) and mark which ones are safe to use without breaking things. The green-ticked lists are generally safe to enable without dramas.

Tip: After adding new blocklists, run Tools > Update Gravity in the dashboard to pull in the new domains. Pi-hole calls its blocklist database "Gravity" — fitting name, really.

Whitelisting

Fair warning — some things will break. Certain apps and services use tracking URLs that also serve legitimate content. If something stops working after enabling Pi-hole, check the query log to see what's being blocked and whitelist the domain in the dashboard. Common culprits include some Microsoft services, Spotify's tracking domains, and certain smart TV apps.

It's easy to whitelist — just find the blocked domain in the query log and click the whitelist button. No stress.

Upstream DNS

Pi-hole only handles the blocking side of things. For everything else, it needs an upstream DNS server to resolve legitimate queries. By default it uses Google (8.8.8.8), but you can change this in the dashboard settings:

  • Cloudflare1.1.1.1 (fast, privacy-focused)
  • Quad99.9.9.9 (includes malware blocking)
  • Google8.8.8.8 (the default, reliable)
  • Unbound — Run your own recursive DNS resolver for full privacy (no third-party DNS at all). That's a whole other rabbit hole but worth looking into if you're keen.

What to Expect

Once everything's humming along, expect around 20-40% of all DNS queries on your network to be blocked. That number will vary depending on your browsing habits and how many IoT devices you've got, but it's pretty typical. Your browsing experience gets noticeably faster and cleaner — pages load quicker because they're not fetching dozens of ad and tracking scripts, and you'll see far fewer ads across all your devices.

A Note About Port 53

If your Docker host is running Ubuntu (or any systemd-based distro), there's a good chance systemd-resolved is already sitting on port 53. Pi-hole won't be able to bind to it and the container will fail to start.

The fix is straightforward:

# Edit the resolved config
sudo nano /etc/systemd/resolved.conf

# Set DNSStubListener=no
[Resolve]
DNSStubListener=no

# Restart the service
sudo systemctl restart systemd-resolved

That frees up port 53 for Pi-hole. You might also need to update /etc/resolv.conf to point to a real DNS server temporarily (like 1.1.1.1) while Pi-hole starts up.

Note: This is part of the homelab series. Pi-hole is one of those foundational services that makes everything else on your network better. Once you've got it running, you'll wonder how you ever lived without it.

Links: