Pi-hole Ad-Blocking DNS Server Installation

Pi-hole is a network-wide ad-blocking DNS server that filters advertisements and tracking domains at the DNS level for every device on your network. This guide covers installing Pi-hole on Linux, managing blocklists and whitelists, configuring DHCP, and customizing the dashboard.

Prerequisites

  • Ubuntu 22.04/Debian 12, CentOS/Rocky 9, or Raspberry Pi OS
  • Static IP address on the server
  • Root or sudo access
  • Port 53 (DNS), 80 (web dashboard), 67 (DHCP if used) available
  • At least 512 MB RAM and 2 GB disk space

Install Pi-hole

Pi-hole provides an automated installer:

# Ensure static IP is set before installing
ip addr show

# Install via the official script
curl -sSL https://install.pi-hole.net | sudo bash

The installer provides an interactive menu. Key choices:

  • Select your network interface (e.g., eth0)
  • Choose an upstream DNS provider (Cloudflare, Google, or custom)
  • Install the web admin interface: Yes
  • Enable logging: Yes

For automated/unattended installation:

# Download and run non-interactively
curl -sSL https://install.pi-hole.net -o pi-hole-install.sh
chmod +x pi-hole-install.sh

# Create an answers file for unattended install
cat > /etc/pihole/setupVars.conf << 'EOF'
WEBPASSWORD=YourDashboardPasswordHash
PIHOLE_INTERFACE=eth0
IPV4_ADDRESS=192.168.1.100/24
IPV6_ADDRESS=
QUERY_LOGGING=true
INSTALL_WEB_SERVER=true
INSTALL_WEB_INTERFACE=true
LIGHTTPD_ENABLED=true
CACHE_SIZE=10000
DNS_FQDN_REQUIRED=false
DNS_BOGUS_PRIV=true
DNSMASQ_LISTENING=local
PIHOLE_DNS_1=1.1.1.1
PIHOLE_DNS_2=1.0.0.1
DNS_SEC=true
EOF

sudo bash pi-hole-install.sh --unattended

Post-Installation Configuration

After installation, set the admin password and configure basic settings:

# Set the web admin password
sudo pihole -a -p YourNewPassword

# Check service status
pihole status
sudo systemctl status pihole-FTL

# Test DNS resolution through Pi-hole
dig @192.168.1.100 google.com
dig @192.168.1.100 ads.doubleclick.net   # Should return 0.0.0.0

The web dashboard is available at http://your-server-ip/admin.

Update Pi-hole to the latest version:

sudo pihole -up

Blocklist Management

Pi-hole uses Adlists (block lists fetched from URLs) to filter domains:

# Update blocklists from configured adlist sources
sudo pihole -g

# Check current blocklist statistics
pihole -c   # console summary
pihole -q example-blocked-domain.com  # query a domain

# View current gravity database stats
sqlite3 /etc/pihole/gravity.db "SELECT COUNT(*) FROM gravity;"

Add popular community blocklists via the web interface or CLI:

# Add adlists via the database directly
sudo sqlite3 /etc/pihole/gravity.db << 'EOF'
INSERT INTO adlist (address, enabled, comment) VALUES
  ('https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts', 1, 'StevenBlack Unified'),
  ('https://adguard.com/kb/general/ad-filtering/adguard-filters/', 1, 'AdGuard Base'),
  ('https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/data/hosts/spy.txt', 1, 'Windows Spy Blocker'),
  ('https://hostfiles.frogeye.fr/firstparty-trackers-hosts.txt', 1, 'Tracker Hosts');
EOF

# Regenerate gravity after adding new adlists
sudo pihole -g

Recommended starting blocklists:

  • https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts (ads + malware)
  • https://raw.githubusercontent.com/nicehash/NiceHashAdBlock/master/adlist.txt

Whitelist and Blacklist Configuration

# Add a domain to the whitelist (won't be blocked even if on a blocklist)
sudo pihole -w example.com
sudo pihole -w cdn.example.com
sudo pihole -w api.legitimate-service.com

# Remove from whitelist
sudo pihole -w -d example.com

# Add a domain to the blacklist (always blocked)
sudo pihole -b ads.sneaky-tracker.com
sudo pihole -b tracking.analytics-company.io

# Remove from blacklist
sudo pihole -b -d ads.sneaky-tracker.com

# Add a wildcard to block entire domains including subdomains
# Use regex entries in the web interface, or:
sudo pihole --regex '(^|\.)doubleclick\.net$'
sudo pihole --regex '(^|\.)googleadservices\.com$'

# List whitelist
pihole -w -l

# List blacklist
pihole -b -l

Configure DHCP

Pi-hole includes a built-in DHCP server, useful when you want to automatically set Pi-hole as the DNS server for all clients:

Disable your router's DHCP server first, then enable Pi-hole DHCP:

# Via web interface: Settings > DHCP > Enable DHCP server
# Or edit the config file:

sudo tee -a /etc/dnsmasq.d/02-pihole-dhcp.conf << 'EOF'
dhcp-range=192.168.1.50,192.168.1.200,24h
dhcp-option=option:router,192.168.1.1
dhcp-option=option:dns-server,192.168.1.100
EOF

sudo systemctl restart pihole-FTL

# Assign static DHCP leases to specific hosts
sudo pihole -a -s eth0  # enable DHCP in setupVars

# View active DHCP leases
cat /etc/pihole/dhcp.leases

Dashboard Customization

The Pi-hole web dashboard shows query statistics and blocking effectiveness:

# Access the dashboard at:
# http://192.168.1.100/admin

# Change the admin password
sudo pihole -a -p NewPassword

# Configure the dashboard to show more history
sudo nano /etc/pihole/pihole-FTL.conf
# /etc/pihole/pihole-FTL.conf
MAXDBDAYS=90              # Keep 90 days of query logs
DBINTERVAL=1.0            # Flush to DB every 1 minute
MAXNETAGE=365             # Keep network device records for 1 year
PRIVACYLEVEL=0            # 0=full logging, 3=anonymous
MAXLOGAGE=24.0            # Hours of log data shown on dashboard
sudo systemctl restart pihole-FTL

Upstream DNS and Privacy Settings

Configure upstream resolvers for Pi-hole to forward queries to:

# View current upstream settings
cat /etc/pihole/setupVars.conf | grep PIHOLE_DNS

# Change upstream DNS via web interface:
# Settings > DNS > Upstream DNS Servers

# Or edit setupVars.conf directly:
sudo sed -i 's/PIHOLE_DNS_1=.*/PIHOLE_DNS_1=9.9.9.9/' /etc/pihole/setupVars.conf
sudo sed -i 's/PIHOLE_DNS_2=.*/PIHOLE_DNS_2=149.112.112.112/' /etc/pihole/setupVars.conf

# If using Unbound as upstream recursive resolver:
echo "PIHOLE_DNS_1=127.0.0.1#5335" | sudo tee -a /etc/pihole/setupVars.conf

sudo pihole restartdns

For maximum privacy, pair Pi-hole with a local Unbound resolver:

# Install Unbound alongside Pi-hole
sudo apt install -y unbound

# Configure Unbound to listen on port 5335
sudo tee /etc/unbound/unbound.conf.d/pi-hole.conf << 'EOF'
server:
    interface: 127.0.0.1
    port: 5335
    do-ip4: yes
    do-udp: yes
    do-tcp: yes
    root-hints: "/var/lib/unbound/root.hints"
    harden-glue: yes
    harden-dnssec-stripped: yes
    hide-identity: yes
    hide-version: yes
    cache-min-ttl: 0
    prefetch: yes
    qname-minimisation: yes
    auto-trust-anchor-file: "/var/lib/unbound/root.key"
EOF

sudo curl -o /var/lib/unbound/root.hints https://www.internic.net/domain/named.cache
sudo systemctl enable --now unbound

# Test Unbound on port 5335
dig pi.hole @127.0.0.1 -p 5335

# Set Pi-hole to use Unbound as upstream
# In web interface: Settings > DNS > Custom 1: 127.0.0.1#5335

Troubleshooting

Pi-hole not blocking ads:

# Check if DNS is pointing to Pi-hole
nslookup doubleclick.net 192.168.1.100
# Should return 0.0.0.0

# Rebuild the gravity database
sudo pihole -g

# Check if the domain is whitelisted
pihole -q doubleclick.net

FTL service not starting:

sudo systemctl status pihole-FTL
sudo journalctl -u pihole-FTL -n 50 --no-pager

# Check for port conflicts
sudo ss -tlnup | grep -E ":53|:80|:67"

Dashboard not accessible:

# Check lighttpd status
sudo systemctl status lighttpd
sudo systemctl restart lighttpd

# Verify port 80 is not blocked
sudo ufw allow 80/tcp

Slow DNS resolution:

# Test resolution time
time dig @192.168.1.100 google.com

# Increase cache size in web interface:
# Settings > DNS > Cache size (default: 10000)

Conclusion

Pi-hole provides network-wide ad and tracker blocking by acting as the DNS server for your entire network, requiring no configuration on individual devices. The gravity blocklist system, combined with per-device query logging and a clean dashboard, makes it easy to identify blocked domains and whitelist false positives. Pairing Pi-hole with a local Unbound resolver provides full recursive DNS resolution without relying on external upstream providers, delivering both ad blocking and DNS privacy in a single stack.