Install Pi-hole on Raspberry Pi
The Classic Combo
Pi-hole was literally named after the Raspberry Pi. It is the original Pi project for self-hosting — a $35 board that blocks ads for your entire network, consumes 2-3 watts of power, and runs silently in a corner. If you are new to self-hosting, this is the easiest first project you can do.
Two installation methods:
Bare-metal install (recommended for a dedicated Pi) — Run the official installer script directly on Raspberry Pi OS. No Docker, no containers, no layers of abstraction. Pi-hole runs as native system services. Simplest setup, easiest to maintain, lowest resource usage.
Docker install — Run Pi-hole in a container on Raspberry Pi OS. Use this if the Pi also runs other Docker containers. Slightly more overhead but keeps Pi-hole isolated from the host OS.
For a Pi dedicated to DNS, use the bare-metal install. It is simpler and lighter.
Prerequisites
Hardware
| Component | Minimum | Recommended |
|---|---|---|
| Board | Raspberry Pi Zero 2 W | Raspberry Pi 4 (2 GB) or Pi 5 |
| Storage | 8 GB microSD (Class 10) | 16 GB+ microSD (A2 rated) |
| Power | 5V/2.5A micro-USB (Pi Zero 2 W) | Official Pi power supply |
| Network | Wi-Fi (built-in) | Ethernet (Pi 4/5 via built-in port) |
| Case | Optional | Any case with passive cooling |
What runs Pi-hole:
- Pi Zero 2 W — Works perfectly. 512 MB RAM is more than enough for DNS. The quad-core ARM Cortex-A53 handles home network DNS without breaking a sweat. Best for a minimal, low-power, Wi-Fi-connected DNS server.
- Pi 3B+ — Fine. Has Ethernet, which is preferable for a DNS server.
- Pi 4 (any RAM) — Overkill for just Pi-hole, but great if you want to run other services alongside it.
- Pi 5 — Way overkill for Pi-hole alone. Use a Pi 5 if you also plan to run Home Assistant, Grafana, or other services.
Power consumption: A Pi Zero 2 W running Pi-hole draws about 1-2 watts idle. A Pi 4 draws 3-5 watts. At $0.12/kWh, that is $1-5 per year in electricity. Pi-hole pays for its own electricity in ad-blocked bandwidth savings.
Headless Setup (No Monitor)
Most people run Pi-hole headless — no monitor, no keyboard, SSH only. Here is how to set up Raspberry Pi OS without ever connecting a display.
Flash Raspberry Pi OS Lite
- Download and install the Raspberry Pi Imager
- Insert your microSD card
- In the Imager:
- Choose OS: Raspberry Pi OS (other) > Raspberry Pi OS Lite (64-bit)
- Choose Storage: Your microSD card
- Click the gear icon (or Ctrl+Shift+X) for Advanced Options
- In Advanced Options:
- Enable SSH — select “Use password authentication”
- Set username and password — default
pi/ your chosen password - Configure Wi-Fi (if not using Ethernet) — enter SSID and password
- Set locale — your timezone and keyboard layout
- Click Write
First SSH Connection
Insert the SD card into the Pi, connect Ethernet (if available), and power on. Wait 60 seconds for the first boot.
Find the Pi’s IP address. Options:
- Check your router’s connected devices / DHCP lease table
- Run
ping raspberrypi.localfrom another device (works if mDNS is supported) - Use
nmap -sn 192.168.1.0/24to scan your subnet
SSH into the Pi:
ssh pi@<pi-ip-address>
Update the system:
sudo apt update && sudo apt upgrade -y
Configure a Static IP
Your network depends on Pi-hole’s IP for DNS. It must not change. Configure a static IP via dhcpcd:
sudo nano /etc/dhcpcd.conf
Add at the bottom (adjust values for your network):
interface eth0 # Use wlan0 for Wi-Fi
static ip_address=192.168.1.53/24
static routers=192.168.1.1
static domain_name_servers=1.1.1.1 8.8.8.8
Using .53 as the last octet is a nice convention for a DNS server — easy to remember.
Apply:
sudo systemctl restart dhcpcd
Reconnect via SSH using the new static IP.
Method 1: Bare-Metal Install (Recommended)
The official one-line installer is the simplest way to get Pi-hole running on a dedicated Pi.
Run the Installer
curl -sSL https://install.pi-hole.net | bash
This launches an interactive installer (ncurses-based) that walks through:
- Network interface — Select
eth0(Ethernet) orwlan0(Wi-Fi) - Upstream DNS — Choose Cloudflare, Google, Quad9, or custom
- Blocklists — Accept the default Steven Black list (you can add more later)
- Admin web interface — Install it (say yes)
- Lighttpd web server — Required for the admin interface (say yes)
- Query logging — Enable for troubleshooting (can disable later for privacy)
- Privacy mode — Choose how much query data to show in the dashboard
The installer takes 2-5 minutes. At the end, it displays your admin password. Save this password. You can change it later with:
pihole -a -p
Verify Installation
Access the admin interface at http://192.168.1.53/admin (your Pi’s static IP).
Test DNS resolution:
dig @192.168.1.53 google.com
Check Pi-hole status:
pihole status
Managing Pi-hole (Bare-Metal)
Pi-hole’s CLI tool handles most operations:
pihole status # Check if Pi-hole is running
pihole -up # Update Pi-hole
pihole -g # Update gravity (blocklists)
pihole -l # View the tail of the log
pihole restartdns # Restart the DNS resolver
pihole -a -p # Change web admin password
pihole enable # Enable blocking
pihole disable 5m # Disable blocking for 5 minutes
Pi-hole runs as three systemd services:
pihole-FTL— The DNS resolver and query enginelighttpd— Web server for the admin interface
Check their status:
sudo systemctl status pihole-FTL
sudo systemctl status lighttpd
Method 2: Docker Install
Use this if the Pi runs other Docker containers and you want Pi-hole isolated.
Install Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker pi
Log out and back in.
Docker Compose Configuration
mkdir -p ~/pihole && cd ~/pihole
Create docker-compose.yml:
services:
pihole:
container_name: pihole
image: pihole/pihole:2026.02.0
ports:
- "53:53/tcp"
- "53:53/udp"
- "80:80/tcp"
environment:
TZ: "America/New_York"
FTLCONF_webserver_api_password: "change-me-to-a-strong-password"
FTLCONF_dns_upstreams: "1.1.1.1;1.0.0.1"
FTLCONF_dns_listeningMode: "ALL"
volumes:
- ./etc-pihole:/etc/pihole
cap_add:
- NET_ADMIN
- SYS_TIME
- SYS_NICE
restart: unless-stopped
Start it:
docker compose up -d
Raspberry Pi OS does not run systemd-resolved by default, so there is no port 53 conflict like on Ubuntu. The Docker Pi-hole binds to port 53 without issues.
Access the admin at http://192.168.1.53/admin.
Configuration
Point Your Network to Pi-hole
After installation (either method), configure your network to use Pi-hole for DNS.
Router method (recommended):
- Log into your router’s admin panel
- Set the primary DNS server to your Pi’s static IP (e.g.,
192.168.1.53) - Do not set a non-Pi-hole secondary DNS — devices will randomly bypass Pi-hole
- Save and reboot the router
Per-device method: Set DNS to the Pi’s IP in each device’s network settings. Useful for testing but does not scale.
Add Blocklists
The default blocklist blocks ~100K domains. For better coverage:
- Go to Adlists in the web UI
- Add these recommended lists:
- Hagezi Multi Pro:
https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/adblock/pro.txt - OISD Big:
https://big.oisd.nl/
- Hagezi Multi Pro:
- Go to Tools > Gravity > Update to apply
Start with one or two additional lists. Adding too many increases RAM usage and false positives.
PoE HAT (Power over Ethernet)
If your Pi is near your router/switch but far from a power outlet, a PoE HAT eliminates the need for a separate power supply. The Pi 4 and Pi 5 support PoE through official PoE+ HATs.
Requirements:
- A PoE-capable switch or PoE injector
- The official Raspberry Pi PoE+ HAT (Pi 4) or PoE+ HAT for Pi 5
- A Cat5e or better Ethernet cable
This simplifies the Pi-hole setup to a single cable: Ethernet for both network and power. Mount the Pi in a case near your switch and forget about it.
Platform-Specific Tips
- Pi Zero 2 W is enough. Pi-hole uses ~50-80 MB of RAM on a typical home network. The Pi Zero 2 W’s 512 MB is plenty. Save your Pi 4/5 for heavier workloads like Home Assistant or Jellyfin.
- Ethernet over Wi-Fi. A DNS server should have the most reliable network connection possible. If your Pi has an Ethernet port, use it. Wi-Fi drops cause DNS outages for your entire network.
- SD card longevity. Pi-hole writes logs and query data frequently. Use an A2-rated SD card for better write endurance. For maximum reliability, disable query logging in Settings > Privacy or set a short log retention period.
- Overclock is unnecessary. Pi-hole’s CPU usage is negligible. DNS lookups are I/O-bound (network), not CPU-bound. Do not overclock for Pi-hole — it adds heat and instability with no benefit.
- Multiple Pi-holes for redundancy. Run two Pi-hole instances on two separate Pis. Set your router’s primary DNS to Pi #1 and secondary DNS to Pi #2. If one Pi fails, the other handles all DNS queries. Use Pi-hole’s built-in Gravity Sync or Orbital Sync to keep blocklists synchronized.
Troubleshooting
Pi-hole Not Blocking Ads
Symptom: Pi-hole dashboard shows queries, but ads still appear on devices.
Fix:
-
Verify the device is actually using Pi-hole for DNS:
nslookup ads.google.comThe server should show your Pi’s IP. If it shows your router or
127.0.0.53, the device is not using Pi-hole. -
Some ads are served from the same domain as the content (e.g., YouTube ads from
googlevideo.com). Pi-hole cannot block these without breaking the content itself. -
Some devices hardcode DNS servers (e.g., Chromecast uses
8.8.8.8). Block outbound DNS at the router level:- Create a firewall rule that redirects all port 53 traffic to your Pi-hole IP
- Or block all port 53 traffic that is not destined for your Pi-hole
High CPU on Pi Zero 2 W
Symptom: pihole-FTL uses 100% of one CPU core.
Fix: This usually happens during a gravity update (processing blocklists). It is temporary — wait for it to finish. If it persists:
- Reduce the number of blocklists. Each list adds processing overhead during updates.
- Reduce query logging verbosity in Settings > Privacy.
- Check if conditional forwarding is causing a DNS loop — disable it temporarily and see if CPU drops.
Cannot Access Admin Interface
Symptom: http://pi-ip/admin shows “Connection refused” or does not load.
Fix (bare-metal):
sudo systemctl status lighttpd
sudo systemctl start lighttpd
If Lighttpd fails to start, check if another service is using port 80:
sudo ss -tlnp | grep ':80'
Fix (Docker):
docker compose ps
docker compose logs pihole | tail -20
If the container is running but port 80 is not accessible, check UFW or iptables rules.
DNS Stops Working After Pi Reboot
Symptom: After a power outage or reboot, the network has no DNS until the Pi finishes booting.
Fix: This is expected — Pi-hole needs 30-60 seconds to boot and start the DNS service. Mitigation options:
- Use a small UPS (uninterruptible power supply) to keep the Pi running during brief outages
- Run a second Pi-hole on another Pi for redundancy
- Set your router’s secondary DNS to a public DNS (e.g.,
1.1.1.1) as a fallback — note that some queries will bypass Pi-hole when using a secondary
SD Card Corruption
Symptom: Pi fails to boot, shows filesystem errors, or Pi-hole’s database becomes corrupted.
Fix: SD cards wear out from constant writes. Recovery:
- Flash a fresh Raspberry Pi OS to a new SD card
- Reinstall Pi-hole
- Import your settings from a Teleporter backup (if you exported one before the failure)
Prevention:
- Use an A2-rated SD card (better write endurance)
- Reduce writes: set query logging to “Anonymous” in Settings > Privacy
- Move to a USB SSD for long-term reliability (see the Pi hardware section for SSD boot instructions)
- Export Teleporter backups regularly: Settings > Teleporter > Export
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments