Pi-hole sits between your devices and the rest of the internet, intercepting every DNS query and dropping the ones that resolve to known ad servers and trackers. When it works, ads simply don't load - the browser never gets the IP address, so there's nothing to render and nothing to block visually. It's the closest thing to magic that DNS has to offer.
The catch with running it on a Raspberry Pi at home is that it only protects devices on your home network. As soon as you walk out the door, your phone goes back to the ad-soaked default. The fix is to move Pi-hole to a VPS and tunnel your devices to it - same Pi-hole, same dashboard, but the protection follows you onto coffee-shop Wi-Fi and cellular. This guide walks you through the whole thing.
What you'll have when you're done
- A working Pi-hole instance on a Linux VPS, with the standard web admin panel.
- A WireGuard tunnel that routes your devices' DNS (and optionally all traffic) through it.
- An optional Unbound recursive resolver so you stop leaking queries to Google or Cloudflare.
- A blocklist setup that kills 90% of ads and trackers without breaking websites.
Prerequisites
- A Linux VPS with root access. Pulsar Nano at $3/month is plenty - Pi-hole sips RAM and CPU.
- Ubuntu 22.04 / 24.04 or Debian 12. Pi-hole officially supports both.
- Comfort with the command line and editing config files.
- About 20 minutes.
Before you start: never run Pi-hole as a public open DNS resolver. Port 53 (DNS) should never be exposed to the open internet - it gets abused for amplification attacks and your IP will get blacklisted. We'll lock it down to localhost and the WireGuard subnet only.
Step 1: Update the system
Fresh VPS, fresh updates. Always.
sudo apt update && sudo apt upgrade -y
Reboot if a new kernel came down: sudo reboot.
Step 2: Run the Pi-hole installer
The official installer is a one-liner. Yes, "curl-pipe-bash" makes security people twitch - read the script first if it bothers you (curl -sSL https://install.pi-hole.net | less) and then run it for real.
curl -sSL https://install.pi-hole.net | sudo bash
You'll get an interactive wizard. The answers that matter:
- Upstream DNS provider: pick Cloudflare or Quad9 for now. We'll swap this for Unbound later.
- Static IP address: let it use the current IP. On a VPS this is fine - your IP isn't changing.
- Install the admin web interface: yes.
- Install the lighttpd web server: yes (if you don't already have nginx/Caddy running).
- Log queries: yes (you can turn it off later).
- Privacy mode: "Show everything" is fine for personal use. Pick higher modes if you want less data retention.
When it finishes, the installer prints your admin password. Write this down. If you lose it: pihole setpassword.
Test the admin panel by visiting http://YOUR_VPS_IP/admin in a browser. You should see the Pi-hole dashboard.
Step 3: Lock down DNS access
By default Pi-hole listens on all interfaces. We want it to only answer queries from localhost and our WireGuard subnet, not the public internet.
Open the Pi-hole admin -> Settings -> DNS. Under "Interface listening behavior," select "Listen only on interface eth0" (or whatever your VPS interface is named). Save.
Then close port 53 to the open internet via firewall. If you're using ufw:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH # don't lock yourself out
sudo ufw allow 80/tcp # admin panel (HTTP)
sudo ufw allow 443/tcp # admin panel if you add TLS later
sudo ufw allow 51820/udp # WireGuard
sudo ufw enable
Notice we never opened port 53. Pi-hole will only be reachable for DNS through the WireGuard tunnel we set up next.
Step 4: Install WireGuard for mobile access
If you haven't already, follow our WireGuard setup guide - it covers installation, key generation, and the first peer in detail. Once that's done, come back here.
Assuming WireGuard is up with the tunnel subnet 10.66.0.0/24, two things need to change to route DNS through Pi-hole:
4a. Allow DNS traffic from the WireGuard subnet to reach Pi-hole. On the VPS:
sudo ufw allow from 10.66.0.0/24 to any port 53
4b. Edit each WireGuard client config to point DNS at the Pi-hole. The DNS line under [Interface] should be:
DNS = 10.66.0.1
(That's the server's IP inside the WireGuard subnet - the same machine running Pi-hole.) Re-import the config on each client, reconnect the tunnel, and you're done.
Verify it's working: turn on the WireGuard tunnel on your phone, then visit dnsleaktest.com. You should see your VPS's IP listed as your DNS server, not your ISP's or your carrier's.
Step 5: Add a better blocklist
Pi-hole ships with a small default blocklist (StevenBlack's). It works, but it's conservative. For a meaningful step up, add Hagezi's Pro list - aggressive enough to block the bulk of trackers and ads, conservative enough not to break sites.
In the admin panel: Group Management -> Adlists. Paste this URL into "Address":
https://raw.githubusercontent.com/hagezi/dns-blocklists/main/dnsmasq/pro.txt
Click "Add." Then update gravity (Pi-hole's blocklist compile step):
pihole -g
You should see the new domains added. You'll go from ~100k blocked domains to ~250-300k.
If you find legitimate sites breaking, the easy fix is to allow them: Domain Management -> Whitelist. Add the domain. No need to restart.
Step 6: Optional - Unbound for recursive DNS
Pi-hole is forwarding your queries to Cloudflare or Google, which means those providers see your DNS lookups. If that's a concern, install Unbound on the same VPS and use it as your upstream.
sudo apt install -y unbound
Create the config:
sudo nano /etc/unbound/unbound.conf.d/pi-hole.conf
server:
# Listen only on localhost
interface: 127.0.0.1
port: 5335
do-ip4: yes
do-udp: yes
do-tcp: yes
do-ip6: no
# Trust glue only if it is within the server's authority
harden-glue: yes
# Require DNSSEC data for trust-anchored zones
harden-dnssec-stripped: yes
# Don't use Capitalization randomization
use-caps-for-id: no
# Reduce EDNS reassembly buffer size
edns-buffer-size: 1232
# Caching
cache-min-ttl: 3600
cache-max-ttl: 86400
prefetch: yes
num-threads: 1
# Privacy
hide-identity: yes
hide-version: yes
Start it:
sudo systemctl enable --now unbound
Test:
dig pulsar67.com @127.0.0.1 -p 5335
You should see a response with the correct A record. Now point Pi-hole at Unbound: admin panel -> Settings -> DNS. Uncheck all upstream providers. Under "Custom 1 (IPv4)," add 127.0.0.1#5335. Save.
Your queries now go: your device -> WireGuard -> Pi-hole -> Unbound -> the actual authoritative DNS servers. No Cloudflare, no Google, no logged third-party. You're talking directly to the root and TLD servers.
Step 7: Confirm the whole chain works
From your phone or laptop, with WireGuard active:
- Visit a site you know has lots of ads (a news site is a fine test). They should be missing.
- Check the Pi-hole admin dashboard - you should see your device's queries flowing in, with the "Blocked" counter ticking up.
- Run
dnsleaktest.comagain - should still show only your VPS's IP, no fallbacks. - Visit d3ward's ad-block test. With Hagezi Pro you should score 80%+.
Common gotchas
"Some apps' notifications stopped working"
Hagezi Pro blocks some push-notification CDN endpoints. If a specific app breaks, the Pi-hole query log will show what it's trying to reach - whitelist that domain in the admin.
"YouTube ads are still there"
DNS can't reliably block YouTube ads because Google serves them from the same CDN as the videos. There's no DNS-based fix for this; you need an in-browser blocker like uBlock Origin or a YouTube-specific client like NewPipe. Pi-hole handles everything else.
"Pi-hole stopped responding"
Most often this is gravity failing during an update. SSH in, run pihole -g, and read the output. If a blocklist URL is dead, remove it from the admin's Adlists page.
"I want HTTPS on the admin panel"
Highly recommended. Install Caddy as a reverse proxy on port 443, point it at lighttpd on localhost:80, and let Caddy handle Let's Encrypt automatically. Your admin panel becomes https://pihole.yourdomain.com with a real cert.
What this combination gives you
Once everything is wired up, the math is hard to beat. Pulsar Nano is $3/month. Pi-hole is free. WireGuard is free. Unbound is free. For the price of a single coffee per month you get:
- Ad-blocked DNS on every device, on every network, anywhere on earth.
- A trusted exit IP for hotel and coffee-shop Wi-Fi.
- A recursive resolver that doesn't leak queries to any third party.
- A dashboard showing every query your devices make - genuinely educational about how much background telemetry is flying around.
The closest commercial equivalent is NextDNS or Control-D at $20-40/year, and you're still trusting their no-logs claims. Self-hosted you trust yourself.
If you want the marketing-page version with the plan recommendations spelled out, the Pi-hole hosting page covers it. If you just want to spin up a VPS and get started, plans are here.
Stuck? The Pulsar67 contact form goes to engineers who actually run their own Pi-holes. We'll help.