What is Pi-hole?
Pi-hole is a DNS filter that runs locally on your network. When a device looks up a domain, the request goes to Pi-hole first. If Pi-hole recognises the domain as an ad server or tracker, it returns 0.0.0.0. If it does not, it forwards the request to a real DNS resolver like 1.1.1.1 or 9.9.9.9.
Pi-hole v6 was released in January 2025 and is a complete rewrite. The new version ships with a redesigned web interface and no longer needs lighttpd as a separate service. The web server is now built into Pi-hole itself.
Pi-hole does not require a Raspberry Pi. It runs on any Linux machine. A Pi 3, 4, or 5 is ideal though: low power, silent, and more than capable of handling DNS for a home network.
What you need
- Raspberry Pi (3, 4, or 5) running Raspberry Pi OS Bookworm/Bullseye, or Ubuntu Server 22.04/24.04
- USB3 SSD adapter + 120 GB+ SSD (strongly recommended) or SD card at least 8 GB (see next section)
- SSH access or a connected monitor and keyboard
- A static or reserved IP address for the Pi
SD cards die. Use an SSD.
Pi-hole's gravity.db is a SQLite database that constantly logs DNS queries and periodically updates blocklists. That is not occasional writes. It is steady I/O. SD cards are not built for that, and most die within 6-18 months under Pi-hole load. You usually find out at night when the whole household loses internet and nobody knows why.
A USB3 SSD adapter plus a 120 GB+ SSD is a one-time cost of around 25-35 EUR and solves the problem permanently. Samsung 870 Evo and Kingston A400 are both solid choices. For something more compact, a high-endurance USB stick works too. Samsung FIT Plus and the SanDisk Endurance series are well-tested options.
On Pi 4 and Pi 5 you can boot directly from USB SSD. Set the boot order to USB-first in raspi-config:
sudo raspi-config
# Advanced Options → Boot Order → USB Boot
Flash the OS image directly to the SSD with Raspberry Pi Imager and the Pi will ignore the SD card entirely.
Static IP for the Pi
Pi-hole needs a fixed IP address. Without one, the address changes on the next reboot and your network can no longer find the DNS server. The easiest approach is a DHCP reservation in your router: look up the Pi's MAC address and assign it the same IP every time.
Alternatively, set a static IP directly in Pi OS. Open /etc/dhcpcd.conf and add:
interface eth0
static ip_address=192.168.1.100/24
static routers=192.168.1.1
static domain_name_servers=127.0.0.1 1.1.1.1
Replace 192.168.1.100 with the IP you want and 192.168.1.1 with your router's address. Use wlan0 instead of eth0 for WiFi. Then reboot:
sudo reboot
Installation
The official installation method is a single command:
curl -sSL https://install.pi-hole.net | bash
The installer is interactive. It asks which upstream DNS provider to use (pick 1.1.1.1 or 9.9.9.9), which starting blocklist to include, and whether to install the web interface. Accept the defaults unless you have a specific reason to change them. At the end, the installer displays a password for the admin interface. Write it down.
Docker Compose (recommended)
A single docker run command works, but Docker Compose is much better: easier to update, restart, and extend with additional services. With Docker Compose on SSD you can run Pi-hole, Portainer, Heimdall, and AdGuard Home on the same Pi without conflicts.
Create a directory and a docker-compose.yml:
mkdir ~/pihole && cd ~/pihole
version: "3"
services:
pihole:
image: pihole/pihole:latest
container_name: pihole
restart: unless-stopped
ports:
- "53:53/tcp"
- "53:53/udp"
- "80:80/tcp"
environment:
TZ: "Europe/Copenhagen"
WEBPASSWORD: "change-this"
volumes:
- ./etc-pihole:/etc/pihole
- ./etc-dnsmasq.d:/etc/dnsmasq.d
cap_add:
- NET_ADMIN
Replace change-this with a real password. Start Pi-hole:
docker compose up -d
Data is stored in ./etc-pihole and ./etc-dnsmasq.d relative to the directory you ran the command from. With Docker Compose on SSD it is straightforward to add other services to the same docker-compose.yml as you need them.
The admin interface and first login
Open a browser and go to:
http://[pi-ip]/admin
Log in with the password shown at the end of the installer. If you need to set a new one:
pihole -a -p
The dashboard shows live queries, blocking rate, and a Query Log where you can see exactly what has been blocked and what passed through.
Point your router at Pi-hole
For all devices on the network to automatically use Pi-hole, set the router's DNS to the Pi's IP. Log in to your router's admin page (typically 192.168.1.1 or 192.168.0.1), find the DHCP settings, and set the primary DNS to the Pi's IP.
Example router settings:
Primary DNS: 192.168.1.100 (Pi's IP)
Secondary DNS: 1.1.1.1 (Cloudflare fallback)
After saving, restart devices on your network (or renew their DHCP lease) so they pick up the new DNS server.
Add better blocklists
Pi-hole's default list is the StevenBlack hosts file with around 120,000 domains. It is a solid starting point, but OISD Basic is better maintained, covers over 1 million domains, and is known for very low false positives.
Go to Settings, Adlists, and add:
https://big.oisd.nl/
Click Add, then run a gravity update so Pi-hole downloads and processes the new lists:
pihole -g
Gravity usually takes a couple of minutes. Afterwards the dashboard shows the updated blocked domain count.
Test that it works
From a terminal on any device on your network:
nslookup doubleclick.net [pi-ip]
If the response is 0.0.0.0 or :: (IPv6), Pi-hole is blocking correctly. If it returns a real IP, the domain is not on your current blocklist.
Check the Query Log in the Pi-hole dashboard as well. You can watch requests come in live and verify blocking is happening.
What Pi-hole does NOT do
Pi-hole blocks DNS queries, not HTTPS traffic. That means it cannot block ads that are embedded in application code rather than loaded from a separate ad domain. YouTube ads are the classic example: they are served from Google's own domains and bypass Pi-hole.
Apps with hardcoded DNS servers (for example, querying 8.8.8.8 directly) bypass Pi-hole entirely. It is not common, but it happens. You can intercept those with a DNS redirect rule on your router, but that is outside the scope of this guide.
Useful commands
# Check status
pihole status
# Update blocklists (gravity)
pihole -g
# Disable for 5 minutes
pihole disable 5m
# Re-enable
pihole enable
# Whitelist a domain
pihole -w example.com
# Tail the live query log
pihole -t
Keeping Pi-hole updated
Pi-hole updates itself with:
pihole -up
Run it manually every now and then, or schedule it as a cron job.
Frequently asked questions
Does Pi-hole block ads in apps?
Yes, for apps that call a separate ad domain. Apps that serve ads from their own domain — YouTube and Spotify being the main examples — cannot be blocked via DNS. That is a fundamental limitation of how DNS-based blocking works.
Can Pi-hole slow down my internet connection?
No. Pi-hole caches responses locally and is typically faster than most ISP DNS servers. You will usually see faster DNS lookups, not slower ones. The only exception is a Pi already under heavy load from other tasks.
What is the best blocklist to start with?
Start with StevenBlack Unified (included by default). It is conservative, well-documented and has a low false-positive rate. Add OISD Full once you are comfortable with the setup. The most aggressive lists block too much and are frustrating to tune.