Running your own DNS server at home used to be the territory of sysadmins with racks of hardware. Today, a ten-dollar Raspberry Pi or a spare Linux box can serve DNS for your entire network, block ads before they reach any device, enforce custom domain names for local services, and give you complete visibility into what every device on your network is actually resolving. If you have been relying on your ISP's resolvers or even a public alternative like 8.8.8.8, you are handing over a detailed log of every domain your household visits. A private DNS server changes that equation entirely.

Why Run a Private DNS Server

There are three solid reasons to host your own resolver rather than using someone else's.

  • Privacy: Your ISP's DNS resolver logs every query. Google and Cloudflare publish privacy policies, but you still have no way to audit them. When you control the resolver, the logs stay on your hardware.
  • Ad and tracker blocking: Tools like Pi-hole intercept DNS queries for known ad and tracking domains and return NXDOMAIN or a local IP before any connection is made. This works on every device, including smart TVs and IoT gadgets that ignore browser extensions.
  • Local DNS entries: You can create internal hostnames like nas.home or printer.home that resolve to LAN addresses without touching a public registrar or a hosts file on every device.

Choosing the Right Software

Two tools dominate the home private DNS space and they can be combined.

Pi-hole

Pi-hole is a DNS sinkhole that doubles as a recursive resolver or a forwarder. Its web interface makes blocklist management straightforward. It runs on Raspberry Pi OS, Ubuntu, Debian, and inside Docker. Pi-hole handles the filtering layer and the local DNS records, but it is not a full recursive resolver by itself — it forwards upstream queries to whatever you configure (8.8.8.8, 1.1.1.1, or your own Unbound instance).

Unbound

Unbound is a validating, recursive, caching DNS resolver. Instead of forwarding your queries to an upstream server, it walks the DNS tree from the root nameservers itself. No third party ever sees the full picture of your queries. Combining Pi-hole with Unbound is the gold-standard home setup: Pi-hole handles blocking and the UI; Unbound handles resolution without an upstream dependency.

AdGuard Home

AdGuard Home is a single-binary alternative that bundles both the filtering and the resolver. It supports DNS-over-HTTPS and DNS-over-TLS out of the box with less configuration than the Pi-hole plus Unbound stack. Good choice if you want encrypted upstream queries quickly.

Hardware Requirements

You do not need anything powerful. A Raspberry Pi Zero 2 W, Pi 3, or Pi 4 will run Pi-hole and Unbound comfortably while drawing under five watts. If you already have a home server or NAS running Ubuntu or Debian, you can run everything there. The only real requirement is that the machine stays on. DNS downtime means the internet stops working for your whole network, so avoid using your main workstation.

Step-by-Step: Installing Pi-hole and Unbound

Step 1: Prepare the OS

Start with a fresh Raspberry Pi OS Lite (64-bit) image or a minimal Ubuntu Server install. Update the system first.

sudo apt update && sudo apt upgrade -y

Give the machine a static IP address on your LAN. Edit /etc/dhcpcd.conf on Raspberry Pi OS:

interface eth0 static ip_address=192.168.1.2/24 static routers=192.168.1.1 static domain_name_servers=127.0.0.1

Reboot after saving. On Ubuntu Server, use Netplan instead — edit /etc/netplan/00-installer-config.yaml and run sudo netplan apply.

Step 2: Install Pi-hole

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

The installer walks you through an ncurses interface. When it asks for an upstream DNS provider, pick any option — you will override it with Unbound in a moment. Note the admin password shown at the end of the install. The web interface will be available at http://192.168.1.2/admin (replace with your actual static IP).

Step 3: Install Unbound

sudo apt install unbound -y

Create the Pi-hole configuration file for Unbound:

sudo nano /etc/unbound/unbound.conf.d/pi-hole.conf

Paste the following configuration block:

server: verbosity: 0 interface: 127.0.0.1 port: 5335 do-ip4: yes do-udp: yes do-tcp: yes do-ip6: no prefer-ip6: no harden-glue: yes harden-dnssec-stripped: yes use-caps-for-id: no edns-buffer-size: 1472 prefetch: yes num-threads: 1 so-rcvbuf: 1m private-address: 192.168.0.0/16 private-address: 172.16.0.0/12 private-address: 10.0.0.0/8 private-address: 169.254.0.0/16 private-address: fd00::/8 private-address: fe80::/10

Start and enable Unbound:

sudo systemctl enable unbound sudo systemctl restart unbound

Test that Unbound is resolving correctly on port 5335:

dig dnschecker.ca @127.0.0.1 -p 5335

You should see a valid A record in the ANSWER section with status NOERROR.

Step 4: Point Pi-hole at Unbound

Log in to the Pi-hole web interface at http://192.168.1.2/admin. Navigate to Settings > DNS. Uncheck every upstream DNS server listed. In the Custom 1 (IPv4) field enter:

127.0.0.1#5335

Scroll down and save. Pi-hole will now forward all non-blocked queries to your local Unbound instance, which resolves them recursively without involving any upstream provider.

Step 5: Configure Your Router

Point your router's DHCP server at the Pi-hole IP so every device on the network uses it automatically. The exact path depends on your router brand.

  • ASUS routers (admin at asusrouter.com or 192.168.1.1): LAN > DHCP Server > DNS Server 1 field.
  • TP-Link routers (admin at tplinkwifi.net): Advanced > Network > DHCP Server > Primary DNS.
  • Netgear routers (admin at routerlogin.net or 192.168.0.1): Advanced > Setup > Internet Setup, or DHCP settings depending on firmware version.
  • Generic routers at 192.168.1.1 or 192.168.0.1: Look for DHCP or LAN settings and set the DNS server field to your Pi-hole IP.

Set the primary DNS to 192.168.1.2 (your Pi-hole). Set the secondary DNS to something like 1.1.1.1 only if you want a fallback when Pi-hole is down — though leaving it blank forces all queries through Pi-hole and avoids clients bypassing it.

Adding Local DNS Records

One of the most practical benefits of a private DNS server is creating internal hostnames. In the Pi-hole interface go to Local DNS > DNS Records. Add entries like:

  • nas.home → 192.168.1.10
  • printer.home → 192.168.1.20
  • camera.home → 192.168.1.30

Any device that gets its DNS from your DHCP server will now resolve these names instantly without modifying hosts files anywhere.

After making changes to your DNS setup, use the DNS Propagation Checker to confirm your public domain's records are still resolving correctly from multiple global vantage points. Local DNS changes do not affect public resolution, but it is worth verifying if you have made any upstream changes.

Configuring Blocklists

Pi-hole ships with one default blocklist (Steven Black's hosts). You can add more through Group Management > Adlists. Some well-maintained lists:

  • HaGeZi Multi Pro: https://raw.githubusercontent.com/hagezi/dns-blocklists/main/adblock/pro.txt
  • OISD Big: https://big.oisd.nl
  • Steven Black Unified: https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts

After adding lists, go to Tools > Update Gravity and click the button. Pi-hole will download and compile all lists. A combined count of 500,000 to 1,000,000 domains is reasonable without causing performance issues on modern hardware.

Enabling DNSSEC Validation

Because Unbound validates DNSSEC signatures during recursion, you get DNSSEC for free. Verify it is working:

dig sigfail.verteiltesysteme.net @127.0.0.1 -p 5335

This domain deliberately has a broken DNSSEC signature. Unbound should return SERVFAIL. If it does, validation is active. Then confirm a valid domain still works:

dig dnssec.works @127.0.0.1 -p 5335

You should get a clean NOERROR response.

How to Verify Everything Is Working

Run these checks from a client machine on your network after updating the DHCP settings and renewing your lease (ipconfig /release && ipconfig /renew on Windows, sudo dhclient -r && sudo dhclient on Linux).

nslookup dnschecker.ca nslookup doubleclick.net

The first should return a valid IP. The second — a major ad domain — should return 0.0.0.0 or NXDOMAIN if your blocklists are active. On Windows you can also run:

ipconfig /all

Look for the DNS Servers line in the output for your active adapter. It should show your Pi-hole IP address, not your ISP's servers or 8.8.8.8.

For public-facing records, use the DNS Lookup tool to confirm your domain resolves correctly from outside your network — your private resolver handles internal queries only and should not interfere with public DNS for your domain.

Running Pi-hole in Docker

If you prefer containers, Pi-hole publishes an official Docker image. Create a docker-compose.yml file:

version: "3" services: pihole: image: pihole/pihole:latest container_name: pihole network_mode: host environment: TZ: America/Toronto WEBPASSWORD: your_secure_password PIHOLE_DNS_: 127.0.0.1#5335 volumes: - ./etc-pihole:/etc/pihole - ./etc-dnsmasq.d:/etc/dnsmasq.d restart: unless-stopped

Note that using network_mode: host is the easiest way to bind Pi-hole to port 53 on the host without NAT complications. Run docker compose up -d to start it. Unbound would be a separate container or a host-level install on port 5335 as described earlier.

Common Problems and Fixes

Port 53 Already in Use

On modern Ubuntu and Debian systems, systemd-resolved binds to port 53. Disable its stub listener:

sudo sed -i 's/#DNSStubListener=yes/DNSStubListener=no/' /etc/systemd/resolved.conf sudo systemctl restart systemd-resolved

Then restart Pi-hole or Unbound and confirm port 53 is now free with sudo ss -tulpn | grep :53.

Devices Ignoring Pi-hole DNS

Some smart TVs and Android devices hard-code DNS servers like 8.8.8.8. Block outbound port 53 traffic to external IPs on your router firewall, then redirect it to your Pi-hole. On OpenWrt:

iptables -t nat -A PREROUTING -i br-lan ! -d 192.168.1.2 -p udp --dport 53 -j DNAT --to 192.168.1.2 iptables -t nat -A PREROUTING -i br-lan ! -d 192.168.1.2 -p tcp --dport 53 -j DNAT --to 192.168.1.2

Pi-hole Blocking Legitimate Sites

Navigate to Tools > Querylog and search for the domain. Click the red circle icon next to it and choose Whitelist domain. The query log is your best debugging tool — check it first whenever something stops loading.

Keeping It Maintained

A private DNS server needs minimal ongoing work, but do not fully ignore it.

  • Update Pi-hole monthly: pihole -up from the command line.
  • Update Gravity (blocklists) automatically by enabling the built-in cron job in Pi-hole settings under Settings > API/Web Interface.
  • Keep the underlying OS patched: sudo apt update && sudo apt upgrade -y at least monthly.
  • Monitor the dashboard occasionally. A sudden spike in queries from one device can indicate malware.

A well-configured home DNS server is one of the highest-value infrastructure changes you can make to a home network. It cuts ads, protects privacy, gives you local hostname resolution, and provides a detailed audit trail of network activity — all for the cost of a small device that draws less power than a phone charger.