Pi-hole as a Primary DNS Server

Beyond Ad Blocking

Pi-hole is best known for network-wide ad blocking, but it’s also a fully capable DNS server. This guide covers the DNS features — configuring Pi-hole as your network’s primary resolver with custom upstream servers, local DNS records, conditional forwarding, and DNSSEC. If you’ve already deployed Pi-hole for ad blocking, you already have a DNS server. This guide shows you how to use it.

For the ad blocking setup guide, see Pi-hole: Network-Wide Ad Blocking. For dedicated recursive DNS resolution, see Unbound.

Prerequisites

  • Pi-hole deployed and running (Pi-hole setup guide)
  • Docker and Docker Compose installed (guide)
  • Access to your router’s DHCP settings (to point clients at Pi-hole)
  • Understanding of DNS concepts (DNS Explained)

Docker Compose Configuration

If you haven’t deployed Pi-hole yet, here’s the Docker Compose focused on DNS functionality:

services:
  pihole:
    image: pihole/pihole:2025.03.0
    container_name: pihole
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "80:80/tcp"       # Web admin interface
    environment:
      TZ: "UTC"
      WEBPASSWORD: ${PIHOLE_PASSWORD}  # Set in .env
      PIHOLE_DNS_: "1.1.1.1;9.9.9.9"  # Upstream DNS (semicolon-separated)
      DNSSEC: "true"                    # Enable DNSSEC validation
      REV_SERVER: "true"                # Enable conditional forwarding
      REV_SERVER_DOMAIN: "home.lan"     # Your local domain
      REV_SERVER_TARGET: "192.168.1.1"  # Your router IP
      REV_SERVER_CIDR: "192.168.1.0/24" # Your LAN subnet
    volumes:
      - pihole-data:/etc/pihole
      - pihole-dnsmasq:/etc/dnsmasq.d
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "dig", "+norecurse", "+retry=0", "@127.0.0.1", "pi.hole"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 30s

volumes:
  pihole-data:
  pihole-dnsmasq:

Create the .env file:

cat > .env << 'EOF'
PIHOLE_PASSWORD=change-this-admin-password
EOF

Start Pi-hole:

docker compose up -d

Configuring Upstream DNS

Web UI Method

  1. Open http://your-server-ip/admin
  2. Go to Settings > DNS
  3. Select or enter your preferred upstream DNS servers

Environment Variable Method

Set upstream resolvers via PIHOLE_DNS_:

# Single provider
PIHOLE_DNS_: "1.1.1.1;1.0.0.1"

# Mixed providers
PIHOLE_DNS_: "1.1.1.1;9.9.9.9"

# Use Unbound as upstream (local recursive resolver)
PIHOLE_DNS_: "172.20.0.2#53"

Upstream Provider Comparison

ProviderIPsFeaturesPrivacy
Cloudflare1.1.1.1, 1.0.0.1Fastest, malware filtering optionsPurges logs in 24h
Quad99.9.9.9, 149.112.112.112Malware blocking built-inNon-profit, no logging
Google8.8.8.8, 8.8.4.4Most reliableLogs queries
UnboundYour server IPFull recursive, no third partyMaximum privacy
TechnitiumYour server IPRecursive + DNS-over-HTTPSSelf-controlled

For maximum privacy, pair Pi-hole with a local Unbound instance — see the “Pairing With Unbound” section below.

Local DNS Records

Pi-hole can serve custom DNS entries for your local network, eliminating the need to edit /etc/hosts on every device.

Via Web UI

  1. Go to Local DNS > DNS Records
  2. Add entries:
    • nas.home.lan192.168.1.100
    • proxmox.home.lan192.168.1.50
    • jellyfin.home.lan192.168.1.10

Via Configuration File

Create a custom dnsmasq configuration:

cat > /opt/pihole/custom-dns.conf << 'EOF'
# Local DNS entries
address=/nas.home.lan/192.168.1.100
address=/proxmox.home.lan/192.168.1.50
address=/jellyfin.home.lan/192.168.1.10
address=/.home.lan/192.168.1.10  # Wildcard: all *.home.lan → server
EOF

Mount it into the container:

volumes:
  - pihole-data:/etc/pihole
  - pihole-dnsmasq:/etc/dnsmasq.d
  - ./custom-dns.conf:/etc/dnsmasq.d/05-custom-dns.conf:ro

CNAME Records

For pointing subdomains to other local hostnames:

cat > /opt/pihole/custom-cname.conf << 'EOF'
cname=nextcloud.home.lan,docker.home.lan
cname=grafana.home.lan,docker.home.lan
EOF

Mount as /etc/dnsmasq.d/06-custom-cname.conf:ro.

Conditional Forwarding

Conditional forwarding lets Pi-hole resolve local hostnames (like mypc.home.lan) by forwarding reverse DNS lookups to your router:

environment:
  REV_SERVER: "true"
  REV_SERVER_DOMAIN: "home.lan"
  REV_SERVER_TARGET: "192.168.1.1"
  REV_SERVER_CIDR: "192.168.1.0/24"

This means when Pi-hole receives a query for 192.168.1.47, it asks your router’s DNS, which knows the hostname from DHCP. Without this, Pi-hole can only show IP addresses in its query log — not device names.

DNSSEC Validation

Enable DNSSEC to verify DNS response authenticity:

environment:
  DNSSEC: "true"

Pi-hole validates DNSSEC signatures on responses from upstream servers. If a response fails validation, Pi-hole returns SERVFAIL instead of a potentially spoofed answer.

Important: DNSSEC only works when your upstream DNS servers support it. Cloudflare (1.1.1.1) and Quad9 (9.9.9.9) both support DNSSEC. Google (8.8.8.8) supports it too. If using Unbound as upstream, it validates DNSSEC independently.

Pairing With Unbound (Recursive DNS)

The most private DNS setup: Pi-hole handles ad blocking, Unbound handles recursive resolution. No third-party DNS provider sees your queries.

Client → Pi-hole (ad blocking) → Unbound (recursive DNS) → Root servers

Deploy both with a shared Docker network:

services:
  pihole:
    image: pihole/pihole:2025.03.0
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "80:80/tcp"
    environment:
      PIHOLE_DNS_: "172.20.0.2#53"  # Unbound's IP on the shared network
      DNSSEC: "false"  # Unbound handles DNSSEC
    networks:
      dns:
        ipv4_address: 172.20.0.3
    volumes:
      - pihole-data:/etc/pihole
      - pihole-dnsmasq:/etc/dnsmasq.d
    restart: unless-stopped

  unbound:
    image: mvance/unbound:1.22.0
    networks:
      dns:
        ipv4_address: 172.20.0.2
    restart: unless-stopped

networks:
  dns:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/24

volumes:
  pihole-data:
  pihole-dnsmasq:

Disable DNSSEC in Pi-hole when using Unbound — Unbound validates DNSSEC independently, and double-validation can cause false failures.

See Network-Wide Ad Blocking for the full setup guide.

Making Pi-hole Your Network’s DNS

Router Configuration

The recommended approach — all devices automatically use Pi-hole:

  1. Open your router’s admin panel
  2. Find DHCP settings
  3. Set the primary DNS server to your Pi-hole server’s IP
  4. Remove or leave blank the secondary DNS (otherwise clients may bypass Pi-hole)
  5. Renew DHCP leases on clients (or reboot them)

Per-Device Configuration

For individual devices:

Linux:

echo "nameserver 192.168.1.10" | sudo tee /etc/resolv.conf

macOS: System Preferences > Network > Advanced > DNS > Add your server IP

Windows: Network adapter settings > IPv4 > DNS server addresses

iOS/Android: WiFi settings > Configure DNS > Manual > Add your server IP

Troubleshooting

Devices Can’t Resolve DNS After Setup

Symptom: Websites don’t load after pointing DNS at Pi-hole

Fix: Verify Pi-hole is reachable:

dig @192.168.1.10 google.com

If this works but devices can’t resolve, check your router’s DHCP settings are distributing the correct DNS IP.

Local DNS Entries Not Resolving

Symptom: Custom local DNS records return NXDOMAIN

Fix: Verify the custom config file is mounted correctly and Pi-hole can read it:

docker exec pihole cat /etc/dnsmasq.d/05-custom-dns.conf
docker exec pihole pihole restartdns

DNSSEC Causing Failures

Symptom: Some domains return SERVFAIL with DNSSEC enabled

Fix: Some domains have misconfigured DNSSEC records. Check a specific domain:

dig @127.0.0.1 example.com +dnssec

If legitimate sites fail, you may need to disable DNSSEC or switch to an upstream that handles DNSSEC validation (like Unbound).

Resource Requirements

ResourceValue
RAM~100 MB idle, ~200 MB with large blocklists
CPULow — dnsmasq is highly efficient
Disk~200 MB for container + logs grow over time
NetworkMinimal; all DNS traffic is tiny

Verdict

If you’re already running Pi-hole for ad blocking, you have 80% of a solid network DNS server. Adding local DNS records, conditional forwarding, and DNSSEC turns it into a complete solution. Pair it with Unbound for recursive resolution and you’ve built a fully self-hosted DNS stack that no third party touches.

For users who want DNS server features without the ad blocking, Technitium offers a similar web-managed experience focused purely on DNS. For maximum flexibility with plugin-driven configuration, CoreDNS is the way to go.

FAQ

What’s the difference between this guide and the Pi-hole ad blocking guide?

The Pi-hole setup guide covers initial Docker deployment and ad blocking configuration. This guide covers using Pi-hole specifically as a DNS server — upstream configuration, local DNS records, conditional forwarding, DNSSEC, and pairing with recursive resolvers.

Should I disable my router’s DNS if Pi-hole is my DNS server?

Point your router’s DHCP to distribute Pi-hole’s IP as the DNS server. Don’t set a secondary DNS to your router or a public provider — clients will use the secondary to bypass Pi-hole.

Can Pi-hole do DNS-over-HTTPS or DNS-over-TLS?

Pi-hole itself doesn’t natively support encrypted DNS protocols. Use AdGuard Home if you need built-in DoH/DoT support, or pair Pi-hole with an upstream that encrypts (like Unbound with DoT forwarding or Cloudflare’s DoH endpoint via cloudflared).

Comments