Logo

Pi-hole: DNS ad and tracking blocker

Pi-hole: DNS ad and tracking blocker

Pi-hole turns a Raspberry Pi (or any VPS) into a network-wide ad and tracker blocker. All devices behind it are protected without installing anything on them. Web dashboard, community lists, per-client stats.

Introduction

Pi-hole:

  • DNS resolver that returns NXDOMAIN for ad/tracking domains
  • Covers all apps: mobile, smart TV, console, IoT
  • Community blocklists (StevenBlack, OISD)
  • Web dashboard with per-client stats
  • Manual whitelist / blacklist
  • API and CLI
  • Optional DHCP integration

vs Unbound: Pi-hole is blocking + UI focused; Unbound is recursive resolution focused. Often combined: Pi-hole in front (UI + blocking), Unbound behind (private recursion).

Prerequisites

  • Linux VPS Debian / Ubuntu (or Raspberry Pi)
  • 512 MB RAM, 1 vCPU min
  • Root access
  • Port 53 UDP/TCP free
  • Port 80 (UI) free

Step 1: Installation

curl -sSL https://install.pi-hole.net | bash

Interactive script asks:

  • Network interface
  • Upstream DNS provider (Quad9, Cloudflare)
  • Default blocklists
  • Web dashboard (yes)
  • Query logging (yes)
  • Privacy level (Show everything)

At end:

Configure your devices to use the Pi-hole as their DNS server using:
IPv4: 192.168.1.10
Your Admin Webpage login password is: aBc123XyZ

Step 2: UI access

Visit http://VPS_IP/admin. Login with displayed password.

Step 3: Configure your devices

3 options:

  1. Per-device manual: change DNS in each device.
  2. Via router: change LAN DNS in your router. All DHCP clients automatically get Pi-hole.
  3. Pi-hole as DHCP: Pi-hole can be your DHCP server (Settings > DHCP).

Step 4: First test

From a Pi-hole client:

dig doubleclick.net

Should return 0.0.0.0 or NXDOMAIN.

Dashboard shows live:

  • Total queries
  • Queries blocked
  • % blocked
  • Top clients
  • Top blocked domains

Step 5: Add blocklists

Group Management > Adlists. Recommended:

https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
https://big.oisd.nl
https://adaway.org/hosts.txt
https://v.firebog.net/hosts/Easyprivacy.txt
https://v.firebog.net/hosts/AdguardDNS.txt

After adding: Tools > Update Gravity to compile.

Step 6: Whitelist and blacklist

Group Management > Domains > Whitelist > add example.com. Group Management > Domains > Blacklist > add adparasite.com.

Regex supported:

(\.|^)telemetry\..*\.microsoft\.com$

Step 7: Combine with Unbound (local recursive)

Pi-hole forwards to Cloudflare/Quad9 by default. For more privacy, add Unbound behind:

  1. Install Unbound (see tutorial 30) on same machine, port 5335:
server:
    interface: 127.0.0.1
    port: 5335
  1. In Pi-hole, Settings > DNS:
    • Uncheck all upstream DNS
    • Custom 1 (IPv4): 127.0.0.1#5335

Pi-hole filters, Unbound resolves recursively without external middleman. Max privacy.

Step 8: Groups (multi-tenant)

Different policies per device/group:

Group Management > Groups > create "Adults" and "Kids".

Group Management > Clients > add IP/MAC, assign to group.

Group Management > Adlists > assign some lists to "Kids" group.

Step 9: DNS over HTTPS for upstream

sudo apt install -y cloudflared
sudo nano /etc/default/cloudflared
CLOUDFLARED_OPTS=--port 5053 --upstream https://1.1.1.1/dns-query --upstream https://1.0.0.1/dns-query

Systemd:

sudo nano /etc/systemd/system/cloudflared.service
[Unit]
Description=cloudflared DNS over HTTPS proxy
After=syslog.target network-online.target

[Service]
Type=simple
EnvironmentFile=/etc/default/cloudflared
ExecStart=/usr/local/bin/cloudflared proxy-dns $CLOUDFLARED_OPTS
Restart=on-failure
RestartSec=10
KillMode=process

[Install]
WantedBy=multi-user.target
sudo systemctl enable --now cloudflared

In Pi-hole > Settings > DNS > Custom 1: 127.0.0.1#5053.

Step 10: Auto-update blocklists

Default: weekly. To force more often:

sudo crontab -e
0 3 * * * /usr/local/bin/pihole updateGravity > /var/log/pihole-gravity.log 2>&1

Step 11: Backup and restore

Settings > Teleporter > Backup downloads .tar.gz with full config.

To restore: Teleporter > Restore > select file.

Step 12: API

curl http://VPS_IP/admin/api.php?summary&auth=YOUR_TOKEN

Token in Settings > API.

Useful endpoints:

  • summary: global stats
  • top_clients: most active clients
  • getQueryTypes: query types breakdown
  • topItems: top domains queried/blocked

Troubleshooting

"Reply UNKNOWN_HOST"

Pi-hole doesn't resolve:

sudo systemctl status pihole-FTL
sudo tail -f /var/log/pihole/pihole.log
dig @1.1.1.1 google.com

Legit domain blocked by mistake

Query Log > find domain > "Blocked by". Whitelist it.

Dashboard inaccessible

sudo systemctl status lighttpd
sudo systemctl restart lighttpd pihole-FTL

Check port 80 not used by Nginx/Apache.

Pi-hole + Unbound: SERVFAIL

If Pi-hole forwards to 127.0.0.1#5335 but Unbound not running:

sudo systemctl status unbound
sudo unbound-checkconf

Update fails

pihole -up
sudo tail -f /tmp/pihole_update.log

Useful commands

pihole status
pihole -t                  # live tail
pihole -up                 # update Pi-hole
pihole -g                  # update gravity (blocklists)

pihole disable
pihole disable 10m
pihole enable

pihole -w example.com
pihole -b adparasite.com
pihole --regex '^.*ads.*'

pihole -c                  # chronometer
pihole -a -p               # reset admin password

sudo tail -f /var/log/pihole/pihole.log
sudo tail -f /var/log/pihole/FTL.log

Conclusion

Pi-hole turns your network into ad/tracker-free zone:

  • Blocks ads at DNS level (all apps)
  • Real-time per-client stats
  • Combinable with Unbound for max privacy
  • Very light (runs on Raspberry Pi)

Going further:

  • Combine with Unbound for recursive resolution
  • Enable Pi-hole DHCP for auto client naming
  • For HA, deploy 2 Pi-hole + Gravity Sync

Resources

Join our Discord community server

For any questions, suggestions, or just to chat with the community, join us on Discord!

900+Members