Pi-hole — Service Documentation

Network-wide DNS ad blocking configuration and notes.

Image placeholder — Suggested: "Pi-hole admin dashboard overview screenshot"

Overview & Requirements

Pi-hole is a network-wide DNS sink that blocks ads and tracking by answering DNS queries for known ad domains locally. Deploy it as a small Linux service, inside an LXC, or as a Docker container.

  • OS: Debian/Ubuntu recommended
  • Network: Static IP or DHCP reservation
  • Resources: 1 CPU, 512MB RAM, 1GB disk
  • Access: Web admin via port 80/443; DNS on 53/udp

Network Planning

  • Assign a static IP or DHCP reservation to Pi-hole
  • Decide if Pi-hole will be your primary DNS (router points to Pi-hole)
  • Plan conditional forwarding to your router for local names
  • Keep a fallback DNS (secondary Pi-hole or upstream) to avoid outages

Install (Bare Metal)

On Debian/Ubuntu:

sudo apt update && sudo apt upgrade -y
curl -sSL https://install.pi-hole.net | sudo bash
          

During setup:

  • Select upstream DNS (see DNS section)
  • Choose blocklists (default is fine; add later)
  • Enable IPv6 if your network supports it
  • Set static IP or confirm DHCP reservation

Install (Unprivileged LXC)

Proxmox LXC baseline (Debian 12 recommended):

  • Unprivileged: enabled; CPU: 1; RAM: 512 MB; Disk: 4–8 GB
  • Network: static IP or DHCP reservation configured in Proxmox
  • Proxmox Firewall: allow from LAN to 53/udp, 53/tcp, 80/tcp if enabled

Inside the container:

sudo apt update && sudo apt upgrade -y
sudo apt install -y curl gnupg ca-certificates lsb-release

# Ubuntu-only: free port 53 from systemd-resolved if enabled
if command -v systemd-resolve &>/dev/null; then \
  sudo sed -i 's/^#\?DNSStubListener=.*/DNSStubListener=no/' /etc/systemd/resolved.conf; \
  sudo systemctl restart systemd-resolved || true; \
fi

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

Pi-hole will listen on port 53 (DNS) and 80 (admin UI). For HTTPS, place a reverse proxy in front or terminate TLS locally.

Post-Install Setup

Access admin UI:

http://<pihole-ip>/admin
          
  • Set a strong WEBPASSWORD (environment variable or pihole -a -p)
  • Update blocklists (use curated lists; avoid overblocking)
  • Enable Query logging only if needed; consider privacy
  • Configure DNSSEC when using a validating upstream or Unbound

Quick Verify

# Inside the LXC
sudo pihole status
dig +short @127.0.0.1 example.com

# From a LAN client (replace <pihole-ip>)
nslookup example.com <pihole-ip>
nslookup google.com <pihole-ip>
          

Blocklists

Use a small set of curated lists to avoid false positives and keep lookups fast. You can assign lists to specific groups for granular control.

Add Lists via Web UI

  1. Open Admin → Group Management → Adlists
  2. Paste a list URL, add a short Comment, choose a Group (default if unsure), then Save
  3. Repeat for each list you want to include
  4. Run an update: Admin → Tools → Update Gravity (or CLI below)

Recommended Starting Lists

  • StevenBlack hosts (consolidated, widely used): https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
  • OISD Basic (balanced): https://big.oisd.nl/domainswild
  • 1Hosts Lite (lightweight): https://raw.githubusercontent.com/badmojr/1Hosts/master/Lite/adblock.txt

Tip: Start small, test for a few days, then add more if needed. Aggressive lists can break sign‑ins, media casting, and smart TVs.

Per-Group Assignments

  • Create groups (e.g., Kids, Workstations, IoT) under Group Management → Groups
  • Assign lists to specific groups in Group Management → Adlists
  • Associate clients with groups under Group Management → Clients

Update & Tuning

# Refresh gravity after adding/removing lists
sudo pihole -g

# Whitelist a domain that was blocked by a list
sudo pihole -w example.com

# Temporarily disable blocking (5 minutes)
sudo pihole disable 300

# Re-enable blocking
sudo pihole enable
          

Consider enabling regex-based filters sparingly (Group Management → Domains → Regex) and prefer domain-level allowlists for breakages you encounter.

DNS & Upstreams

  • Start with upstreams: Cloudflare (1.1.1.1), Quad9 (9.9.9.9), Google (8.8.8.8)
  • Prefer Unbound locally for privacy and validation
  • Optional: DoT/DoH via cloudflared or stubby
  • Enable Conditional Forwarding to your router for local hostnames

DHCP & Router

  • Option A: Keep router DHCP, set DNS to Pi-hole (primary/secondary)
  • Option B: Enable Pi-hole DHCP and disable router DHCP
  • Reserve static IP for Pi-hole to avoid DNS flapping
  • For VLANs, ensure inter-VLAN DNS is permitted

Clients & Policies

  • Create groups (e.g., Kids, Workstations, IoT) with tailored blocklists
  • Use per-client or per-group assignments for granular control
  • Add regex filters for aggressive trackers (careful to avoid false positives)
  • Maintain whitelist entries for necessary services

Local Resolver (Unbound)

Recommended for privacy and validation:

sudo apt install -y unbound
sudo wget -O /etc/unbound/unbound.conf.d/pi-hole.conf \
  https://raw.githubusercontent.com/pi-hole/pi-hole/master/adlists/unbound.conf
sudo systemctl enable --now unbound
          

Set Pi-hole upstream to 127.0.0.1#5335. Enable DNSSEC in Pi-hole when Unbound is validating.

Security & Hardening

  • Restrict admin UI to LAN; add reverse proxy for HTTPS
  • Use strong WEBPASSWORD and rotate periodically
  • Limit Pi-hole to listen only on required interfaces
  • Keep OS and Pi-hole updated; consider unattended upgrades

Redundancy / High Availability

  • Deploy a secondary Pi-hole and set router DNS to both
  • Sync gravity lists via pihole -g and export/import
  • Optionally use Keepalived or DNS load balancing

Monitoring & Backups

  • Export settings: Teleporter (admin → Settings → Teleporter)
  • Backup /etc/pihole and /etc/dnsmasq.d regularly
  • Monitor health via Grafana/Prometheus or simple pihole -t logs

Troubleshooting

  • DNS not resolving: check pihole-FTL status and upstreams
  • Clients bypassing Pi-hole: enforce DNS via firewall or router settings
  • Slow lookups: disable heavy lists; prefer Unbound over remote upstream
  • Logging too verbose: adjust Query Logging and privacy levels