Pi-hole Ad Blocker Tutorial

Pi-hole Ad Blocker Tutorial

I deployed Pi-hole on my home network six months ago, and I've blocked over 18 million ad requests since then. It's one of the highest-impact self-hosting projects you can tackle—one DNS server protecting every device on your network, from phones to smart TVs, without installing anything on each individual machine. In this guide, I'll walk you through installing Pi-hole in Docker, configuring your network to use it, and avoiding the common pitfalls that waste hours of troubleshooting.

What Pi-hole Actually Does

Pi-hole is a network-wide ad blocker that operates at the DNS level. Instead of your devices asking external DNS servers to resolve ad domains (like doubleclick.net or analytics.google.com), Pi-hole intercepts those requests and blocks them before they even leave your network. The result: faster browsing, reduced tracking, and zero ads on devices you can't easily install ad blockers on—like your smart TV or Alexa device.

I prefer Pi-hole over traditional browser-based ad blockers because it works everywhere, simultaneously, without configuring anything on individual devices. It also blocks malware and phishing domains using community blocklists, and you get real-time insights into what your network is doing.

Hardware and Prerequisites

You can run Pi-hole on any Linux system—a Raspberry Pi 4, an old laptop, a VPS, or a dedicated homelab box. I run it on a 2GB RAM VM in my homelab, and it handles 200+ devices without breaking a sweat. You'll need:

If you're starting from scratch, I recommend a small VPS or a Raspberry Pi 4 with at least 2GB RAM. For affordable VPS options, RackNerd's KVM VPS plans cost $6–$12/year and include enough resources for Pi-hole plus other services.

Installing Pi-hole with Docker Compose

Docker Compose makes this trivial. Create a directory for Pi-hole and save this configuration:

mkdir -p ~/pi-hole && cd ~/pi-hole

Create a docker-compose.yml file with this content:

version: '3'
services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    restart: unless-stopped
    environment:
      TZ: 'America/New_York'
      WEBPASSWORD: 'change_me_to_strong_password'
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "80:80/tcp"
      - "443:443/tcp"
    volumes:
      - './etc-pihole/:/etc/pihole/'
      - './etc-dnsmasq.d/:/etc/dnsmasq.d/'
    networks:
      - pihole_network

networks:
  pihole_network:
    driver: bridge

Replace the timezone and password. Then start it:

docker-compose up -d

Pi-hole will be available at http://YOUR_SERVER_IP/admin within 30 seconds. Log in with username admin and the password you set.

Watch out: Port 53 (DNS) must be available on your host. If you're running another DNS service (like systemd-resolved on Ubuntu), you'll get a bind error. Disable it with: sudo systemctl disable systemd-resolved && sudo systemctl stop systemd-resolved, then edit /etc/resolv.conf to point to your router's primary DNS temporarily.

Configuring Your Network

Pi-hole won't block anything until your devices use it for DNS. You have two options:

Option 1: DHCP Configuration (Easiest)

Log into your router and change the DHCP DNS settings to your Pi-hole server's IP address. On most routers, this is under Settings → DHCP or LAN Settings. Set both primary and secondary DNS to your Pi-hole's IP. When devices renew their DHCP lease (happens automatically within minutes), they'll start using Pi-hole.

Option 2: Manual DNS Configuration

On devices that support it, manually set DNS to your Pi-hole IP. On Android, go to WiFi Settings → Advanced → DHCP → Static IP, then set DNS. On iOS, go to Settings → WiFi → Your Network → Configure DNS → Manual.

I use Option 1 for most devices (phones, laptops) and Option 2 for anything that should bypass Pi-hole, like my guest WiFi network.

Configuring Blocklists

Pi-hole ships with some default blocklists, but I add community-maintained ones for better coverage. Go to Adlists in the admin panel and add these URLs:

After adding, go to Gravity and click "Update Gravity" to pull the latest lists. This happens automatically once per week in production.

Tip: If you block too aggressively, websites break. Start with the StevenBlack list and add others gradually. Check your query log if sites stop loading—you can whitelist broken domains individually.

Monitoring and Maintenance

The dashboard shows real-time DNS queries, blocked domains, and network stats. I check it weekly to see what's being blocked and occasionally add custom whitelists for legitimate services that get caught too aggressively.

Update Pi-hole monthly by pulling the latest image:

cd ~/pi-hole && docker-compose pull && docker-compose down && docker-compose up -d

This takes 30 seconds and maintains your settings—nothing breaks.

Advanced: Conditional Forwarding and Split DNS

If you want Pi-hole to resolve internal hostnames on your network (like nas.local or homelab.local), enable conditional forwarding in Settings → DNS. Enter your router's local network subnet and gateway. This lets devices query each other by hostname without external DNS lookups.

For split DNS (some queries go to one resolver, others to another), use the gravity database. Stop Pi-hole, edit the SQLite database directly, or use the regex filters in the dashboard to forward specific domains to custom resolvers.

Next Steps

Once Pi-hole is stable, consider pairing it with Unbound (a recursive DNS resolver) to avoid sending queries to external providers like Google or Cloudflare. I'll cover that in a future guide. Also, set up automated backups of your Pi-hole settings—the config files in ./etc-pihole/ are all you need to restore everything.

If you don't have a home server yet, Pi-hole is the perfect first project. It's low-stakes, high-reward, and teaches you DNS fundamentals. Need a VPS to run it on? RackNerd's affordable VPS options are reliable and well-suited to long-running DNS services.

```