How to Self-Host Pi-hole: Network-Wide Ad Blocking for Every Device on Your Network
Pi-hole is a DNS-level ad blocker that runs on your own hardware and silently blocks advertisements, trackers, and malicious domains for every single device on your network, including your phone, smart TV, gaming console, and IoT gadgets, without installing anything on those devices. A single Pi-hole server handles your entire household. This guide covers everything from how Pi-hole actually works, to setting it up on a Raspberry Pi or with Docker, to accessing your admin interface from anywhere using a Localtonet tunnel.
How Pi-hole Works: DNS Sinkholing Explained
Every time you open a website or app, your device asks a DNS server: "What is the IP address for this domain?" Normally, this request goes to your ISP's DNS server or a public resolver like Google (8.8.8.8) or Cloudflare (1.1.1.1). Pi-hole inserts itself between your devices and that upstream DNS server.
When a device on your network asks "What is the IP address for ads.doubleclick.net?", Pi-hole checks the request against its blocklists. If the domain is on a blocklist, Pi-hole responds with a null address (0.0.0.0) instead of forwarding the request upstream. The device thinks the ad server does not exist, the connection attempt fails silently, and no ad loads. If the domain is not blocked, Pi-hole forwards the query to your upstream resolver and returns the real answer.
Pi-hole v6 (released February 2025, current version v6.4.1 / Docker 2026.04.0) is a significant rewrite. The old lighttpd web server is gone. FTL now has its own embedded web server and REST API. All settings are consolidated into a single /etc/pihole/pihole.toml file. The Docker image switched from Debian to Alpine Linux, shrinking from 113 MB to 38 MB. If you are following older tutorials, the environment variable names and configuration paths have changed. This guide covers the current v6 setup.
What Hardware Do You Need?
Pi-hole is extremely lightweight. It runs well on almost any Linux hardware, including hardware that would be considered obsolete for anything else.
| Hardware | Suitability | Notes |
|---|---|---|
| Raspberry Pi Zero 2 W | ✅ Good for small networks | Handles 10,000+ DNS queries/second on Pi 4 in benchmarks; Zero 2 W is less powerful but more than sufficient for a typical home. Use a USB-Ethernet adapter for a wired connection. |
| Raspberry Pi 4 / Pi 5 | ✅ Excellent | More than enough power. Can run Pi-hole alongside other services like Localtonet, Home Assistant, or Frigate NVR on the same machine. |
| Any always-on Linux machine | ✅ Excellent | An old PC, NUC, or mini-PC running Debian/Ubuntu works perfectly. Pi-hole uses minimal RAM (~50-100 MB) and essentially zero CPU at idle. |
| Docker on any Linux host | ✅ Recommended | Runs alongside other Docker containers. Easy to update and manage. Official Docker image is 38 MB (Alpine Linux). |
| VPS / cloud server | ⚠️ Works but different setup | Possible but your home devices need to reach the VPS for DNS. Using Localtonet for the admin UI and a VPN for DNS routing is the typical approach. |
Your entire network will point to Pi-hole's IP address for DNS. If that IP changes (because your router assigned a new one via DHCP), DNS breaks for every device. Before proceeding: either set a static IP on the Pi-hole machine itself, or create a DHCP reservation in your router so the Pi-hole always gets the same IP. This is the most important prerequisite.
Installation Method 1: Bare Metal (Raspberry Pi or Linux)
The official Pi-hole installer is a single curl command. It runs an interactive setup wizard that guides you through the configuration.
Disable systemd-resolved (Ubuntu and Debian only)
Ubuntu and most Debian-based systems run systemd-resolved, which has a stub DNS listener on port 53. This conflicts with Pi-hole's FTL process. Disable it first:
# Disable the systemd-resolved stub listener
sudo sed -i 's/#DNSStubListener=yes/DNSStubListener=no/' /etc/systemd/resolved.conf
sudo systemctl restart systemd-resolved
# Verify port 53 is now free
sudo ss -tulpn | grep :53
# If no output appears, port 53 is free and ready for Pi-hole
Raspberry Pi OS (Raspbian) does not have this issue and you can skip this step.
Run the Pi-hole installer
curl -sSL https://install.pi-hole.net | bash
The installer launches an interactive wizard. It asks you to choose an upstream DNS provider (Cloudflare, Google, Quad9, or custom), confirm your static IP, and set up the web interface. Accept the defaults unless you have a specific preference. The entire installation takes about 2-5 minutes.
Set your admin password
pihole setpassword
Enter New Password (Blank for no password):
Confirm Password:
[✓] Password Correct
Access the web interface
Open http://YOUR-PI-HOLE-IP/admin in your browser and log in with the password you just set. The dashboard shows real-time DNS query statistics.
Installation Method 2: Docker Compose
The Docker method is recommended if you are running Pi-hole alongside other containers, or if you prefer a clean setup that is easy to update and remove.
In Pi-hole v5, the admin password was set with WEBPASSWORD. In v6, this has changed to FTLCONF_webserver_api_password. Using the old variable name in a v6 container will result in a random password being assigned and you will not be able to log in. Use the correct v6 variable name shown below.
Disable systemd-resolved stub listener (Ubuntu / Debian)
sudo sed -i 's/#DNSStubListener=yes/DNSStubListener=no/' /etc/systemd/resolved.conf
sudo systemctl restart systemd-resolved
Create the docker-compose.yml
services:
pihole:
container_name: pihole
image: pihole/pihole:latest
restart: unless-stopped
ports:
- "53:53/tcp" # DNS over TCP
- "53:53/udp" # DNS over UDP
- "80:80/tcp" # Web admin UI (HTTP)
- "443:443/tcp" # Web admin UI (HTTPS, self-signed cert)
# Uncomment if you want Pi-hole to serve as your DHCP server:
# - "67:67/udp"
environment:
TZ: "Europe/Istanbul" # your timezone
FTLCONF_webserver_api_password: "YourPassword" # v6 password variable — NOT WEBPASSWORD
FTLCONF_dns_listeningMode: "ALL" # required for Docker bridge network
# Upstream DNS servers (semicolon-separated):
FTLCONF_dns_upstreams: "1.1.1.1;1.0.0.1" # Cloudflare
# Or use Quad9 for malware blocking:
# FTLCONF_dns_upstreams: "9.9.9.9;149.112.112.112"
volumes:
- "./etc-pihole:/etc/pihole" # config and databases
cap_add:
- NET_ADMIN # required if using Pi-hole as DHCP server
- SYS_TIME # required if Pi-hole should set system time (NTP)
- SYS_NICE # optional: gives Pi-hole more CPU priority
Start the container
docker compose up -d
# Wait 30-60 seconds for Pi-hole to fully start and download initial blocklists
# Then check the logs:
docker logs pihole
::: Starting pihole-FTL...
[i] Pi-hole blocking is enabled
[✓] Started Pi-hole FTL
Access the admin interface
Open http://YOUR-SERVER-IP/admin in your browser. Log in with the password you set in FTLCONF_webserver_api_password. If port 80 is in use on your host, change the port mapping to e.g. "8080:80" and access it at http://YOUR-SERVER-IP:8080/admin.
Pointing Your Network to Pi-hole
Installing Pi-hole does not automatically make it your DNS server. You need to tell your network to use it. There are two approaches:
Option A: Configure your router (recommended)
Log into your router's admin interface and find the DHCP or LAN settings. Set the primary DNS server to your Pi-hole's IP address. Leave the secondary DNS field empty or enter the Pi-hole IP again. Do not enter a public DNS server like 8.8.8.8 as a secondary — if you do, devices that get errors from Pi-hole will fall back to Google DNS and bypass all blocking.
After saving, reconnect your devices (or wait for DHCP lease renewal) and DNS queries will flow through Pi-hole. You should start seeing queries appear in the Pi-hole dashboard within minutes.
Option B: Configure devices individually
If you cannot change your router's DNS settings (rental equipment, ISP lock), set the DNS server manually on each device you want to protect. This is the less convenient approach since it requires per-device configuration.
| Device | Where to set DNS |
|---|---|
| Windows | Settings → Network and Internet → Change adapter options → IPv4 Properties → Use the following DNS server addresses |
| macOS | System Settings → Network → your connection → DNS → add Pi-hole IP |
| iPhone / iPad | Settings → Wi-Fi → your network → Configure DNS → Manual → add Pi-hole IP |
| Android | Settings → Connections → Wi-Fi → long-press your network → Manage network settings → IP settings: Static → DNS 1: Pi-hole IP |
Choosing Blocklists: What to Add
Pi-hole comes pre-configured with StevenBlack's Unified Hosts list, which is a solid starting point. The community has developed several other well-maintained blocklists that significantly improve coverage. Here are the ones worth adding in 2026:
HaGeZi's Blocklists — Gold standard for 2026
HaGeZi has become the most actively maintained and respected blocklist collection. It offers tiered lists for different levels of aggressiveness:
| List | URL | Best for |
|---|---|---|
| Multi Normal | https://raw.githubusercontent.com/hagezi/dns-blocklists/main/adblock/multi.txt |
Most homes. Best "set it and forget it" list. Low false positive rate. |
| Multi Pro | https://raw.githubusercontent.com/hagezi/dns-blocklists/main/adblock/pro.txt |
More aggressive blocking. Occasional false positives on obscure sites. |
| Threat Intelligence Feeds | https://raw.githubusercontent.com/hagezi/dns-blocklists/main/adblock/tif.txt |
Malware, ransomware, and C2 domains. Low false positive risk. Good to add alongside any tier. |
OISD — Safest option for mixed households
OISD is maintained with a strict policy: any domain that interferes with the normal operation of a legitimate website or app is removed. This makes it the list with the fewest false positives. If you share your network with people who complain every time something breaks, start with OISD.
# OISD Basic (ads and trackers, very safe)
https://adguardteam.github.io/HostlistsRegistry/assets/filter_27.txt
# OISD Big (more comprehensive, still very safe)
https://big.oisd.nl
StevenBlack (default) + malware lists
Pi-hole ships with StevenBlack's Unified Hosts list already enabled. You can extend it at the StevenBlack GitHub to add optional categories: fakenews, gambling, adult content, or social media. Alongside these, the URLHaus list covers active malware distribution domains:
# URLHaus — active malware distribution domains
https://urlhaus.abuse.ch/downloads/hostfile/
# Phishing Army — phishing sites, updated daily
https://phishing.army/download/phishing_army_blocklist.txt
To add blocklists: log into the Pi-hole admin UI, go to Lists, paste the URL, click Add, then go to the Gravity page and click Update (or run pihole -g from the terminal). Pi-hole downloads and processes all lists into a single gravity.db database. The update process runs automatically on a schedule.
Adding dozens of blocklists to maximize the blocked domain count creates more false positives without meaningfully better protection. The HaGeZi Multi Normal list alone covers the vast majority of real-world ad and tracker domains. Adding more aggressive lists on top causes breakage that requires you to manage whitelists constantly. Start with one or two lists and add more only when you specifically encounter ads that are getting through.
Dealing with False Positives: Whitelist Management
Occasionally Pi-hole blocks a domain that a legitimate website or app needs. This shows up as a broken feature (images not loading, login failing, app not connecting) rather than an obvious error message. The typical diagnostic process:
Check the query log for the affected device
In the Pi-hole admin UI, go to Query Log. Filter by the device's IP address. Look for queries with a red "blocked" status around the time the issue occurred. The domain that was blocked is visible in the log.
Whitelist the domain
# Add domain to whitelist via CLI
pihole -w example.com
# Or from the admin UI: Domains → Add domain → select Allowlist
Use the Antigravity feature for larger allowlists
Pi-hole v6 added Antigravity: subscribed allowlists that work exactly like blocklists but in reverse. HaGeZi's allowlist includes affiliate and tracking referral links that enable email links and search results to work correctly — a useful addition if you have aggressive blocklists and notice legitimate referral links breaking.
Accessing Pi-hole's Admin Interface Remotely
Pi-hole's admin UI runs on port 80 of your local server. When you are at home, you can access it directly at http://192.168.x.x/admin. When you are away from home, that address is not reachable.
A Localtonet HTTP tunnel gives Pi-hole's admin interface a stable public HTTPS URL so you can check your network stats, add whitelists, and manage blocklists from anywhere. The DNS service itself (port 53) stays on your local network — only the web admin interface gets the public URL.
Install and authenticate Localtonet on the Pi-hole machine
chmod +x localtonet
sudo mv localtonet /usr/local/bin/
sudo localtonet authtoken YOUR_TOKEN
Create an HTTP tunnel for port 80
In the Localtonet dashboard: Protocol = HTTP, Local IP = 127.0.0.1, Local Port = 80, Subdomain = your choice (e.g. pihole → pihole.localto.net).
If you mapped Pi-hole to a different port (e.g. 8080), use that port instead.
Install Localtonet as a service so it starts automatically
sudo localtonet --install-service --authtoken YOUR_TOKEN
sudo localtonet --start-service --authtoken YOUR_TOKEN
Access Pi-hole admin from anywhere
Open https://pihole.localto.net/admin from your phone or any browser. Pi-hole's login page appears. Log in with your password to see live query stats and manage your setup remotely.
Once exposed via a public URL, your Pi-hole admin interface is reachable by anyone who knows the URL. Pi-hole requires a login to make any changes, so your password is the only barrier. Use a strong, unique password. Do not leave the password field blank.
Essential Pi-hole Commands
| Command | What it does |
|---|---|
pihole -g |
Update gravity: downloads all blocklists and rebuilds the blocking database. Run after adding new lists. |
pihole -t |
Tail the live DNS query log in the terminal. Shows queries in real time as devices make requests. |
pihole -q example.com |
Query whether a specific domain is on any of your blocklists and which list it comes from. |
pihole -w example.com |
Add a domain to the allowlist (whitelist). Unblocks it immediately. |
pihole -b example.com |
Add a domain to the blocklist manually. Blocks it immediately. |
pihole restartdns |
Restart the DNS resolver without a full FTL restart. Faster than a full restart for config changes. |
pihole status |
Shows whether Pi-hole is enabled and blocking, the number of blocked domains, and FTL status. |
pihole -up |
Update Pi-hole to the latest version. Always read the release notes before running on a production system. |
pihole-FTL --teleporter |
Export all settings, blocklists, and whitelists to a backup archive. Use this before updating or migrating. |
Backup and Restore
Pi-hole stores all its important data in the /etc/pihole directory. The key file is gravity.db, a SQLite database that contains your blocklists, allowlists, custom domain entries, and query history.
The easiest backup method is the built-in Teleporter: Settings → Teleporter → Export. This creates a downloadable archive of your configuration that you can import on any Pi-hole instance. For Docker setups, backing up the ./etc-pihole volume directory achieves the same result.
# Create a backup archive of the Pi-hole configuration
sudo tar -czf pihole-backup-$(date +%Y%m%d).tar.gz /etc/pihole
# For Docker: backup the mounted volume
tar -czf pihole-backup-$(date +%Y%m%d).tar.gz ./etc-pihole
To restore: import the Teleporter archive via Settings → Teleporter → Import, or extract the backup archive to the original location and restart Pi-hole.
Troubleshooting Common Problems
| Problem | Cause | Fix |
|---|---|---|
| Port 53 already in use, Pi-hole fails to start | systemd-resolved stub listener on Ubuntu/Debian is occupying port 53 |
Disable the stub listener: sudo sed -i 's/#DNSStubListener=yes/DNSStubListener=no/' /etc/systemd/resolved.conf && sudo systemctl restart systemd-resolved |
| Docker container starts but cannot log in to admin UI | Using old WEBPASSWORD variable name instead of v6's FTLCONF_webserver_api_password |
Update your docker-compose.yml to use FTLCONF_webserver_api_password. Recreate the container with docker compose up -d --force-recreate. |
| Pi-hole is running but nothing is being blocked | Devices are not using Pi-hole as their DNS server | Check router DNS settings. Verify by running nslookup ads.google.com YOUR-PI-HOLE-IP — if Pi-hole responds with 0.0.0.0, blocking is working. If another IP responds, devices are bypassing Pi-hole. |
| Some devices bypass Pi-hole entirely | Devices or apps using hardcoded DNS (8.8.8.8, 1.1.1.1, or DNS-over-HTTPS) | For hardcoded DNS: add a firewall rule redirecting port 53 traffic to Pi-hole. For DNS-over-HTTPS: use Pi-hole's ability to block known DoH provider domains (HaGeZi has a DoH bypass blocklist). |
| Websites breaking after adding new blocklists | Overly aggressive blocklist blocking legitimate domains | Check the query log for blocked domains when the site breaks. Whitelist the specific domain with pihole -w domain.com. Consider switching to a less aggressive list tier. |
| Pi-hole stats show 0 queries | Pi-hole is not receiving DNS queries from devices | Confirm devices have Pi-hole's IP as their DNS. Check pihole status. Run pihole -t in the terminal and make a web request — queries should appear. If not, the issue is in your network DNS configuration. |
| Admin UI slow after upgrading to v6 | FTL TLS handling is CPU-intensive on low-end hardware | Run sudo systemctl restart pihole-FTL to restart. Adjust webserver.threads in pihole.toml for better performance on low-core hardware. |
| Gravity update fails with "empty shell variable" | Known bug in some older v6 patch versions | Update Pi-hole with pihole -up — this was fixed in a recent maintenance release. For Docker, pull the latest image and recreate the container. |
Frequently Asked Questions
Will Pi-hole break any websites?
With the default blocklist, very rarely. With more aggressive lists, occasionally. The OISD list is specifically maintained to avoid blocking anything that breaks legitimate functionality. When something does break, the fix is almost always a one-time whitelist addition. Most users report that after the initial setup period (a day or two of whitelisting anything that breaks), Pi-hole runs without any issues indefinitely. The query log makes it straightforward to find which domain is being blocked when something stops working.
Does Pi-hole work on mobile data (outside the home network)?
Not automatically. Pi-hole only processes DNS queries from devices on the same local network. When your phone is on mobile data, it uses mobile carrier DNS, not your Pi-hole. To extend Pi-hole protection outside the home, the standard approach is to run a WireGuard or Tailscale VPN server on the same machine as Pi-hole, connect your phone to the VPN when away from home, and set Pi-hole's IP as the VPN's DNS server. Localtonet handles the public URL for the Pi-hole admin interface, but the actual DNS filtering on mobile requires a VPN tunnel back to your home network.
What happens if the Pi-hole machine goes down?
DNS requests time out and devices fall back to whatever secondary DNS is configured, or they fail to resolve domains entirely. Devices set to use only Pi-hole as their DNS server will appear to lose internet connectivity until Pi-hole comes back online. This is why a static IP and a reliable host (not a laptop that gets put to sleep) matter. Some users run two Pi-hole instances on different machines for redundancy. A Raspberry Pi running Pi-hole with a reliable power supply is stable enough that downtime is rare in practice.
What is the difference between Pi-hole and AdGuard Home?
Both are network-wide DNS ad blockers that run on your own hardware. Pi-hole has been around longer, has a larger community, and more third-party blocklist support. AdGuard Home natively supports encrypted DNS protocols like DNS-over-HTTPS and DNS-over-TLS out of the box, which Pi-hole requires an additional Unbound or cloudflared setup to match. AdGuard Home also handles in-browser adblock-style filtering rules natively. Pi-hole's strength is its maturity, extensive documentation, and the gravity system for managing blocklists. For most home users the blocking effectiveness is similar; the choice often comes down to whether native DoH/DoT support is a priority.
Can Pi-hole completely replace a browser ad blocker like uBlock Origin?
No, and the two work best together rather than as alternatives. Pi-hole blocks at the DNS level: it can block entire domains but cannot block a specific path or element on a domain that also serves legitimate content. For example, it cannot block a YouTube ad served from youtube.com because blocking that domain would also block YouTube itself. Browser extensions like uBlock Origin work at the request level and can block specific URLs, element types, and even cosmetically hide ad placeholders. Pi-hole provides network-wide protection for all devices including those that cannot run extensions. A browser extension provides deeper filtering on the browser. Running both gives the best overall coverage.
Manage Your Pi-hole from Anywhere
A Localtonet HTTP tunnel gives your Pi-hole admin interface a stable public HTTPS URL. Check your network stats, add whitelists, and update blocklists from your phone, no matter where you are.
Create Your Free Tunnel →