Pi-hole: Complete Install & Config Guide

·

Pi-hole is a Linux-based DNS sinkhole that functions as a network-wide DNS resolver. Every device on your network sends DNS queries through Pi-hole, which compares each requested domain against a local blocklist database (called Gravity) containing over 2 million known ad, tracker, and malware-serving domains. Blocked domains resolve to 0.0.0.0 — the connection never leaves your network. Clean queries are forwarded to your upstream resolver of choice (Cloudflare, Quad9, Google, or your own recursive resolver).

This guide walks through three complete installation paths: a Raspberry Pi running Raspberry Pi OS, a Docker host on any Linux system, and a fresh Ubuntu or Debian VM. All three end at the same place — a running Pi-hole with a configured admin panel, a customised blocklist, and your router pointing DNS traffic through it. Every command is production-accurate for Pi-hole v5.18+.

If you are following this on a VM or Docker host and only want to protect a single machine or lab segment, that works too — simply point that machine's DNS to the Pi-hole IP rather than your router's DHCP settings.

◈ Table of Contents

01 What Pi-hole Does 02 Prerequisites & Requirements 03 Method 1: Raspberry Pi 04 Method 2: Docker 05 Method 3: Ubuntu / Debian VM 06 Admin Panel: Initial Setup 07 Upstream DNS & Blocklists 08 Router & Client DNS Config 09 Advanced: Local DNS, DHCP & Forwarding 10 Monitoring & Maintenance 11 Sources & References
🔍

01 — What Pi-hole Does

SECURITY CONTEXT

Pi-hole intercepts DNS resolution at the network level. When a browser, app, or IoT device on your network tries to resolve a hostname, the query goes to Pi-hole first. Pi-hole checks the domain against its Gravity database. If there is a match, Pi-hole returns 0.0.0.0 (a null address), which causes the connection attempt to fail silently. No packet ever reaches the ad server, telemetry endpoint, or malware C2 domain.

🛡️

Malware Domain Blocking

Blocks DNS resolution to known C2 infrastructure, phishing domains, and malware distribution hosts. Works across every device on the network including those you cannot install software on.

📊

Full DNS Visibility

Every DNS query across your network is logged with timestamp, client IP, and resolution result. Useful for detecting suspicious lateral movement or beaconing behaviour from compromised hosts.

🔒

Tracker & Telemetry Suppression

Stops Windows telemetry, smart TV call-home traffic, and third-party trackers at the DNS layer — before a connection is established, not after.

⚡

Lightweight Footprint

Runs on a Raspberry Pi Zero 2 W (512 MB RAM). Handles thousands of DNS queries per second. Adds under 1 ms of latency for cached responses.

DNS RESOLUTION FLOW — Clean queries reach upstream; blocked domains are sunk locally.

📋

02 — Prerequisites & Requirements

ALL PLATFORMS

Pi-hole has modest resource requirements. The critical constraint is a static IP address — if Pi-hole's IP changes, all clients pointing to it lose DNS resolution. Set a static IP or DHCP reservation before starting the installer.

Platform OS RAM Storage Notes
Raspberry Pi Raspberry Pi OS Lite (Bookworm 64-bit) 512 MB min
1 GB+ rec
8 GB SD card Pi Zero 2 W or newer. Pi 3/4/5 all work. Headless recommended.
Docker Any Linux host with Docker 20.10+ 512 MB rec 2 GB free disk Port 53 must be free on host. Disable systemd-resolved on Ubuntu first.
VM Ubuntu 22.04 / 24.04 LTS or Debian 12 1 GB rec 10 GB disk Virtualbox, VMware, Proxmox, Hyper-V all work. Bridged networking required.

Use bridged network mode for VMs, not NAT. Pi-hole must be directly reachable by other devices on your LAN as a DNS server. With NAT, only the hypervisor host can reach it.

Pi-hole is not a recursive DNS resolver — it is a DNS sinkhole and forwarder. It requires an upstream DNS server to resolve clean queries. Do not point Pi-hole at itself as its own upstream.

🍓

03 — Method 1: Raspberry Pi (Bare Metal)

STEP-BY-STEP
1
Flash OS and Boot Headless
Raspberry Pi Imager

Download Raspberry Pi Imager from raspberrypi.com. Select Raspberry Pi OS Lite (64-bit) — no desktop needed. Before writing the image, click the gear icon (advanced options) and configure:

  • a
    Enable SSH with password authentication or a pre-loaded public key.
  • b
    Set your hostname (e.g. pihole.local), username, and password.
  • c
    Configure Wi-Fi SSID and password if using wireless — wired Ethernet is strongly preferred for a DNS server.

Write the image to your SD card, insert it, power on the Pi, and wait approximately 90 seconds for first boot to complete.

2
SSH In and Update the System
SSH

Find the Pi's IP on your router's DHCP leases page or use a network scanner. SSH in with the credentials you set in Imager.

CONNECT & UPDATE
$ ssh [email protected] # replace with your Pi's IP $ sudo apt update && sudo apt full-upgrade -y $ sudo reboot
3
Set a Static IP Address
Required

On Raspberry Pi OS Bookworm, network configuration uses nmcli (NetworkManager). Set a static IP on your active connection. Replace the example values with your network's details.

FIND ACTIVE CONNECTION NAME
$ nmcli connection show # Note the NAME column — usually "Wired connection 1" or "eth0"
SET STATIC IP (WIRED EXAMPLE)
$ sudo nmcli connection modify "Wired connection 1" \ ipv4.addresses 192.168.1.50/24 \ ipv4.gateway 192.168.1.1 \ ipv4.dns 9.9.9.9 \ ipv4.method manual $ sudo nmcli connection up "Wired connection 1" $ ip addr show eth0 # confirm static IP applied

Alternatively, set a DHCP reservation on your router by binding the Pi's MAC address to a fixed IP. Either method works — what matters is the IP never changes.

4
Run the Pi-hole Installer
Core Install

The official installer script handles all dependencies, installs the Pi-hole service, sets up the web interface, and configures dnsmasq as the DNS resolver backend.

ONE-LINE INSTALL
$ curl -sSL https://install.pi-hole.net | bash

If you prefer to inspect the script before running (recommended):

$ wget -O pihole-install.sh https://install.pi-hole.net $ less pihole-install.sh # review it $ sudo bash pihole-install.sh
INTERACTIVE INSTALLER — WHAT TO SELECT
  • 1
    Select network interface: choose eth0 for wired (recommended) or wlan0 for wireless.
  • 2
    Select upstream DNS: choose Cloudflare (1.1.1.1), Quad9 (9.9.9.9), or Google (8.8.8.8). This can be changed after install.
  • 3
    Install default blocklists: select Yes — this adds the StevenBlack hosts list as a starting point.
  • 4
    Install Admin Web Interface: select Yes.
  • 5
    Install lighttpd: select Yes — this is the web server for the admin panel.
  • 6
    Enable query logging: select Yes. Logs are stored locally; configure retention below.
  • 7
    Privacy level: select "Show everything" for full query logging, or a higher privacy mode if desired.
After Install Completes
  • The installer prints the admin panel URL: http://pi.hole/admin or http://[your-IP]/admin
  • The installer prints a randomly generated admin password — copy it now
  • Pi-hole is immediately running and serving DNS on port 53
5
Verify Pi-hole is Running
Verify
$ pihole status # Expected output: [✓] FTL is listening on port 53 [✓] Pi-hole blocking is enabled [✓] Gravity database: ~X,XXX,XXX domains $ pihole -q google.com # query test — should return an IP $ pihole -q doubleclick.net # should return 0.0.0.0 (blocked)
🐳

04 — Method 2: Docker Installation

STEP-BY-STEP
1
Install Docker Engine
Docker CE

These commands install Docker Engine from Docker's official repository on Ubuntu or Debian. Skip if Docker is already installed.

$ sudo apt update $ sudo apt install -y ca-certificates curl gnupg # Add Docker's GPG key $ sudo install -m 0755 -d /etc/apt/keyrings $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg $ sudo chmod a+r /etc/apt/keyrings/docker.gpg # Add Docker repository $ echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \ https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \ | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null $ sudo apt update $ sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin # Allow current user to run Docker without sudo $ sudo usermod -aG docker $USER && newgrp docker # Verify $ docker --version $ docker compose version
2
Free Port 53 (Ubuntu / Debian Only)
Critical

Ubuntu 18.04+ and Debian 12 run systemd-resolved, which occupies port 53 on localhost. Pi-hole cannot bind to port 53 while this is active. You must disable it before starting the container.

# Check what's holding port 53 $ sudo lsof -i :53 # Disable systemd-resolved $ sudo systemctl stop systemd-resolved $ sudo systemctl disable systemd-resolved # Remove the symlink and set a real resolv.conf $ sudo rm /etc/resolv.conf $ echo "nameserver 9.9.9.9" | sudo tee /etc/resolv.conf # Confirm port 53 is now free $ sudo lsof -i :53 # should return nothing

After Pi-hole is running, it will serve as your host's DNS resolver too. Do not leave /etc/resolv.conf pointing at 127.0.0.53 — that is the stub resolver address for the now-disabled systemd-resolved and will cause DNS failures.

3
Create the Docker Compose File
docker-compose.yml

Create a dedicated directory for Pi-hole's Docker deployment. The compose file below maps persistent volumes for the Pi-hole configuration and dnsmasq settings so your configuration survives container restarts and image updates.

$ mkdir -p ~/pihole && cd ~/pihole $ nano docker-compose.yml
docker-compose.yml
version: "3" services: pihole: container_name: pihole image: pihole/pihole:latest ports: - "53:53/tcp" - "53:53/udp" - "80:80/tcp" # admin panel — change to "8080:80" if port 80 is taken environment: TZ: 'Pacific/Auckland' # set your timezone WEBPASSWORD: 'ChangeThisToAStrongPassword!' PIHOLE_DNS_: '9.9.9.9;149.112.112.112' # Quad9 primary + secondary DNSMASQ_LISTENING: 'all' volumes: - './etc-pihole:/etc/pihole' - './etc-dnsmasq.d:/etc/dnsmasq.d' cap_add: - NET_ADMIN restart: unless-stopped

PIHOLE_DNS_ accepts semicolon-separated upstream resolvers. Use two entries for redundancy: e.g. Quad9 (9.9.9.9;149.112.112.112) or Cloudflare (1.1.1.1;1.0.0.1). Full timezone list: en.wikipedia.org/wiki/List_of_tz_database_time_zones

4
Start the Container and Verify
Launch
$ docker compose up -d # Expected: "Container pihole Started" # Watch startup logs (wait for "Pi-hole Ready" message) $ docker logs -f pihole # Ctrl+C to exit log follow # Confirm port 53 is bound by Docker $ sudo ss -tulnp | grep :53 # Test DNS resolution through Pi-hole $ dig google.com @127.0.0.1 $ dig doubleclick.net @127.0.0.1 # should return 0.0.0.0 # Access admin panel # http://[host-ip]/admin (or http://[host-ip]:8080/admin if you used 8080)
Docker Volumes Created
  • ./etc-pihole — stores Pi-hole's config, blocklists, and Gravity database
  • ./etc-dnsmasq.d — stores custom dnsmasq configuration overrides
  • Both directories are created automatically by Docker Compose in ~/pihole/
5
Updating Pi-hole in Docker
Maintenance

Unlike bare-metal installs, Docker Pi-hole updates are done by pulling the latest image. Your configuration persists in the named volumes.

$ cd ~/pihole $ docker compose pull $ docker compose up -d # Container recreates with the new image; config survives in volumes
🖥️

05 — Method 3: Ubuntu / Debian VM

STEP-BY-STEP
1
Create and Configure the VM
Hypervisor Setup

Minimum spec: 1 vCPU, 1 GB RAM, 10 GB disk. Use Ubuntu 22.04 LTS or 24.04 LTS (or Debian 12). Set the network adapter to Bridged mode — this gives the VM an IP on your LAN segment, making it reachable by all other devices.

  • 1
    In VirtualBox: Settings → Network → Adapter 1 → Attached to: Bridged Adapter
  • 2
    In VMware Workstation: VM Settings → Network Adapter → Bridged: Connected directly to the physical network
  • 3
    In Proxmox: set the bridge to vmbr0 (or whichever bridge is on your LAN VLAN)
  • 4
    In Hyper-V: use an External Virtual Switch connected to your LAN NIC
2
Update System and Disable systemd-resolved
OS Prep

Ubuntu 22.04 and 24.04 both run systemd-resolved. This must be disabled before Pi-hole can bind to port 53. The procedure is identical to the Docker method above.

$ sudo apt update && sudo apt full-upgrade -y $ sudo apt install -y curl git net-tools # Disable systemd-resolved $ sudo systemctl stop systemd-resolved $ sudo systemctl disable systemd-resolved # Set a working DNS temporarily for the rest of this install $ sudo rm /etc/resolv.conf $ echo "nameserver 9.9.9.9" | sudo tee /etc/resolv.conf # Protect resolv.conf from being overwritten by NetworkManager $ sudo chattr +i /etc/resolv.conf

The chattr +i command makes /etc/resolv.conf immutable. After Pi-hole is running, it will handle your DNS. If you ever need to edit it, run sudo chattr -i /etc/resolv.conf first.

3
Set a Static IP
Networking

On Ubuntu 22.04/24.04, use Netplan to assign a static IP. Find your interface name first, then edit the Netplan config.

$ ip link show # note interface name — e.g. "ens33" or "eth0" $ sudo nano /etc/netplan/00-installer-config.yaml
NETPLAN CONFIG — REPLACE VALUES FOR YOUR NETWORK
network: version: 2 ethernets: ens33: # replace with your interface name dhcp4: no addresses: - 192.168.1.51/24 # choose a free IP on your subnet routes: - to: default via: 192.168.1.1 # your router/gateway IP nameservers: addresses: - 9.9.9.9 - 149.112.112.112
$ sudo netplan apply $ ip addr show ens33 # confirm static IP applied $ ping -c 3 9.9.9.9 # confirm connectivity
4
Run the Pi-hole Installer
Core Install

Identical to the Raspberry Pi install. The interactive installer detects Ubuntu and installs all required dependencies automatically.

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

Follow the same installer prompts as described in Phase 03, Step 4. Select your static interface (e.g. ens33), choose your upstream DNS, and enable the web interface. Note the admin password printed at the end.

# After install — verify $ pihole status $ dig @127.0.0.1 google.com $ dig @127.0.0.1 doubleclick.net # should return 0.0.0.0
⚙️

06 — Admin Panel: Initial Configuration

WEB UI

Open a browser and navigate to http://[pi-hole-ip]/admin or http://pi.hole/admin (the latter only works once your device is using Pi-hole as its DNS resolver). Log in with the password shown at the end of the installer.

1
Change the Admin Password
Security

The installer-generated password is random and long. Replace it with something you can remember — or keep it and store it in a password manager. Change via CLI:

$ pihole -a -p # Prompts: Enter New Password / Confirm Password # Leave blank and press Enter twice to REMOVE the password (not recommended for shared networks)
2
Explore the Dashboard
UI Overview

The admin dashboard provides real-time query metrics. Key elements after logging in:

Panel ElementWhat It Shows
Queries TodayTotal DNS queries handled since midnight. Click for a timeline breakdown.
Queries BlockedCount and percentage blocked by Gravity. A 10–25% block rate is typical on most home/office networks.
Domains on BlocklistTotal unique domains in the Gravity database across all enabled lists.
Top ClientsWhich devices are generating the most DNS queries. Useful for spotting beaconing or anomalous devices.
Top Blocked DomainsMost frequently sinkholed domains. Usually ad networks and telemetry endpoints.
Query LogReal-time per-query log with client IP, domain, result (Forwarded / Blocked / Cached), and upstream used.
📡

07 — Upstream DNS & Blocklists

CONFIGURATION
1
Configure Upstream DNS Resolvers
Settings → DNS

Navigate to Settings → DNS in the admin panel. Pi-hole ships with several upstream provider presets. The choice affects query privacy, DNSSEC support, and which threat feeds are available as upstream. DNSSEC is enabled by default on Quad9.

ProviderPrimarySecondaryFeatures
Cloudflare1.1.1.11.0.0.1Fast, no-log (1.1.1.1 policy), DNSSEC
Quad99.9.9.9149.112.112.112Threat-blocking upstream, DNSSEC, no-log
Google8.8.8.88.8.4.4Fast, widely tested, logs queries
OpenDNS208.67.222.222208.67.220.220Additional malware filtering upstream

Combining Pi-hole with Quad9 as upstream gives you two layers of malware blocking: Pi-hole's Gravity database (DNS sinkhole) and Quad9's threat feed (upstream resolver filter). These are complementary, not redundant.

2
Add Custom Blocklists to Gravity
Adlists

Navigate to Adlists in the sidebar. Add blocklist URLs — Pi-hole downloads these, deduplicates them, and imports them into the Gravity SQLite database. The curated Firebog lists are a well-maintained starting point used by most practitioners.

RECOMMENDED BLOCKLISTS — ADD EACH URL IN ADLISTS
  • 1
    StevenBlack Unified (included by default): https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts — ~220 K domains
  • 2
    Hagezi Multi Pro: https://raw.githubusercontent.com/hagezi/dns-blocklists/main/hosts/pro.txt — ~600 K domains, high accuracy
  • 3
    OISD Big: https://big.oisd.nl — 1 M+ domains, low false positive rate, actively maintained
  • 4
    Malware domains (Firebog): https://malware-filter.gitlab.io/malware-filter/urlhaus-filter-hosts.txt — URLhaus active malware hosting domains
  • 5
    Phishing Army: https://phishing.army/download/phishing_army_blocklist_extended.txt — active phishing domains updated daily
UPDATE GRAVITY AFTER ADDING LISTS
# Via admin panel: Tools → Update Gravity → Update # Or via CLI: $ pihole -g # Downloads all adlists, deduplicates, rebuilds gravity.db # Takes 1-5 minutes depending on list sizes and connection speed
Expected After Gravity Update
  • Domain count jumps from ~185 K (default StevenBlack) to 1–2 M+ with the lists above
  • Update runs without interrupting DNS — existing queries continue resolving during rebuild
  • Check Tools → Gravity for last update time and total domain count
3
Whitelist and Blacklist via CLI
Tuning

Blocklists will occasionally catch legitimate domains (false positives). Whitelist them immediately — blocked false positives break applications. Similarly, manually blacklist specific domains your chosen lists do not cover.

# Whitelist a domain (remove from blocklist, always allow) $ pihole -w example.com $ pihole -w cdn.example.com # whitelist subdomains separately if needed # Blacklist a domain (block even if not in any adlist) $ pihole -b malicious-domain.com # View current whitelist $ pihole -w -l # View current blacklist $ pihole -b -l # Remove from whitelist $ pihole -w -d example.com # Use regex for wildcard blocking (e.g. all subdomains of a tracker) $ pihole --regex '.+\.analytics\.com
🌐

08 — Router & Client DNS Configuration

NETWORK CONFIG

For Pi-hole to protect your entire network, every device must send DNS queries to Pi-hole's IP instead of your ISP's resolver. The cleanest approach is to change the DNS server in your router's DHCP settings — all devices that receive an IP from the router via DHCP will automatically use Pi-hole without individual configuration.

1
Configure Router DHCP DNS
Router Admin

Log into your router's admin panel (typically 192.168.1.1 or 192.168.0.1). Find the DHCP server settings — the location varies by router brand:

Router BrandDHCP DNS Setting Location
Ubiquiti UniFiNetworks → [LAN] → DHCP → DNS Server 1 / DNS Server 2
pfSense / OPNsenseServices → DHCP Server → DNS Servers
Asus (Merlin/stock)LAN → DHCP Server → DNS Server 1
TP-Link (stock)DHCP → DHCP Settings → Primary DNS
NetgearAdvanced → Setup → LAN Setup → Use these DNS Servers
Eeroeero app → Network Settings → DNS — set to Custom, enter Pi-hole IP

Set DNS Server 1 to your Pi-hole's static IP (e.g. 192.168.1.50). Leave DNS Server 2 blank or set it to a fallback (e.g. 9.9.9.9) — if you set a fallback, devices will bypass Pi-hole when it is unreachable. For full enforcement, leave the secondary blank and ensure Pi-hole runs with restart: unless-stopped.

Also disable your router's built-in DNS rebind protection for pi.hole and your local domain, or the router may intercept and modify Pi-hole's responses. In pfSense: Services → DNS Resolver → General Settings → Rebind protection exceptions.

2
Per-Device Configuration (Where Router Control Isn't Available)
Manual DNS

For devices on networks you do not control (corporate Wi-Fi), or for testing Pi-hole on a single machine, set DNS manually on the device:

PlatformLocation
Windows 11Settings → Network & internet → [adapter] → DNS server assignment → Manual → IPv4 DNS: [Pi-hole IP]
macOSSystem Settings → Network → [adapter] → Details → DNS → "+" → [Pi-hole IP]
Ubuntu DesktopSettings → Network → [adapter] → IPv4 → DNS: [Pi-hole IP] (disable Automatic DNS)
AndroidWi-Fi settings → long-press SSID → Modify network → Advanced → IP settings: Static → DNS 1: [Pi-hole IP]
iOS / iPadOSSettings → Wi-Fi → (i) next to SSID → Configure DNS → Manual → Add Server: [Pi-hole IP]

After changing DNS on any device, flush the local DNS cache: Windows: ipconfig /flushdns | macOS: sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder | Linux: sudo systemd-resolve --flush-caches (if systemd-resolved still running) or restart the browser.

3
Verify Network-Wide Blocking
Test

After configuring your router, reconnect a client device and confirm queries are routing through Pi-hole.

# From a Linux/macOS client on the network: $ nslookup doubleclick.net # Server should show your Pi-hole IP, result should be 0.0.0.0 $ nslookup google.com # Server should show Pi-hole IP, result should be a valid IP # Or from Windows: # PS> nslookup doubleclick.net # Should show Server: [Pi-hole IP], Address: 0.0.0.0

In the Pi-hole admin Query Log, you should now see queries arriving from multiple client IPs on your network, not just from the Pi-hole host itself.

🔧

09 — Advanced: Local DNS, DHCP & Conditional Forwarding

ADVANCED
1
Local DNS Records
Local DNS → DNS Records

Pi-hole can resolve custom hostnames for devices on your LAN — useful for accessing services by name instead of IP. Navigate to Local DNS → DNS Records in the admin panel.

  • 1
    Click Add. Enter the domain (e.g. nas.home) and the target IP (e.g. 192.168.1.100).
  • 2
    For subdomains, use Local DNS → CNAME Records to alias media.home → nas.home etc.
  • 3
    Devices using Pi-hole as DNS can now reach http://nas.home without mDNS or hosts file entries.
2
Conditional Forwarding
Settings → DNS

Conditional forwarding allows Pi-hole to resolve device hostnames by asking your router for its DHCP leases. Without it, the Query Log shows client IPs but not hostnames. Enable it in Settings → DNS → Conditional Forwarding.

  • 1
    Enable "Use Conditional Forwarding".
  • 2
    Enter your local network CIDR: e.g. 192.168.1.0/24.
  • 3
    Enter your router's IP address: e.g. 192.168.1.1.
  • 4
    Enter your local domain name if you use one: e.g. home.lan (leave blank if you do not).

After enabling, reverse DNS lookups for LAN IPs are forwarded to your router, which resolves them to device hostnames. These appear in the Query Log and Top Clients views.

3
Pi-hole as DHCP Server (Optional)
Settings → DHCP

You can disable your router's DHCP server and let Pi-hole hand out IP addresses instead. This ensures every device on the network automatically uses Pi-hole for DNS — no router DHCP configuration needed. Navigate to Settings → DHCP → DHCP Server.

Only enable Pi-hole's DHCP server after disabling your router's DHCP server. Running two DHCP servers on the same segment causes IP conflicts and network outages. Disable the router's DHCP first, wait 2 minutes, then enable Pi-hole's.

  • 1
    In your router, disable the DHCP server.
  • 2
    In Pi-hole: Settings → DHCP → Enable DHCP server. Set the range (e.g. 192.168.1.100 – 192.168.1.200) and gateway IP.
  • 3
    Set the lease time to 24 hours for a home network, 8 hours for a high-turnover environment.
  • 4
    Under DHCP → Static Leases, bind device MAC addresses to fixed IPs for servers and printers.
📊

10 — Monitoring & Maintenance

ONGOING OPS
1
Update Pi-hole (Bare Metal)
Bare Metal Only
# Update Pi-hole core, FTL, and web interface in one command $ pihole -up # Update Gravity (blocklists) separately — run weekly or via cron $ pihole -g # Check current versions $ pihole version # Schedule weekly Gravity update via cron (runs Sunday 3 AM) $ sudo crontab -e # Add this line: # 0 3 * * 0 pihole -g
2
Useful CLI Commands Reference
Reference
── STATUS & CONTROL ────────────────────────────────── $ pihole status # overall health check $ pihole enable # re-enable blocking $ pihole disable 300 # disable blocking for 300 seconds $ pihole restartdns # restart the DNS resolver (FTL) $ pihole reloaddns # reload blocklists without full restart ── QUERY TESTING ───────────────────────────────────── $ pihole -q google.com # test if domain resolves $ pihole -q -adlist ads.com # show which adlist blocks this domain $ dig @pi.hole google.com # direct DNS query to Pi-hole ── LOGS ────────────────────────────────────────────── $ pihole tail # live query log (like tail -f) $ pihole logging on # enable query logging $ pihole logging off # disable query logging (privacy mode) $ pihole flush # clear the DNS log ── BACKUP & RESTORE ────────────────────────────────── # In admin panel: Settings → Teleporter → Backup (downloads .tar.gz) # To restore: Settings → Teleporter → Restore → upload the .tar.gz # Backup includes: blocklists, whitelist, blacklist, regex, DHCP leases, settings
3
Diagnosing False Positives in the Query Log
Tuning

When an application breaks after deploying Pi-hole, the cause is almost always a false positive block. The Query Log is the fastest path to diagnosis.

  • 1
    Open Tools → Query Log. Filter by the device's IP address.
  • 2
    Look for domains marked Pi-holed (red) around the time the application broke.
  • 3
    Click the domain → select "Whitelist" to add it immediately.
  • 4
    Alternatively: use Tools → Whitelist to add domains in bulk.
  • 5
    Flush DNS cache on the affected device and retest the application.

Use the Long-term Data → Query Types and Clients views to identify devices generating unusual DNS query volumes — a device querying 500+ unique domains per hour while idle is worth investigating.

📚

11 — Sources & References

DOCUMENTATION
Pi-hole Official Documentation — Basic Installation (docs.pi-hole.net) Pi-hole Docker Image — Official Repository (github.com/pi-hole/docker-pi-hole) Pi-hole FTL DNS Resolver Documentation (docs.pi-hole.net) The Firebog — Curated Blocklist Collection (firebog.net) Hagezi DNS Blocklists — Multi Pro and above (github.com/hagezi/dns-blocklists) OISD Blocklist — 1 M+ domain unified list (oisd.nl) URLhaus — Abuse.ch Malware URL Feed (urlhaus.abuse.ch) Phishing Army — Daily-updated Phishing Domain Blocklist (phishing.army) Pi-hole CLI Command Reference (docs.pi-hole.net) Pi-hole + Unbound: Running a Local Recursive Resolver (docs.pi-hole.net)

◈ Extend Your DNS Security Further

Pi-hole blocks known-bad domains. Pair it with Unbound as a local recursive resolver to eliminate your upstream DNS provider as a trust boundary — your DNS queries never leave your network until the final authoritative nameserver lookup. CyberHawk Threat Intel covers the full Unbound + Pi-hole stack in the Courses section.

📚 Browse Courses 📝 More Guides

◈ Stay Connected

Follow CyberHawk Threat Intel for threat intelligence, deployment guides and hands-on SOC tooling content.

🌐 Website ▶️ YouTube ▶️ YouTube (2) 𝕏 Twitter / X ♪ TikTok ✈️ Telegram
🔍 IOC Scanner 🛠️ Live Tools 📚 Courses 🚨 Threat Intel 📝 Blog 📋 SOPs

"They can't exploit you if you are the Exploit."