Skip to content

Building a Pi-hole with Raspberry Pi for Enhanced Home Network Security

Take control of your digital privacy and network security. This comprehensive guide walks you through deploying Pi-hole as a network-wide DNS sinkhole, integrating it with Unbound for private recursive queries, and setting up encrypted DNS transport to secure all home devices from ads, tracking, and malware.

/ ARTICLE
[ FIG. 1 ]
Pi-hole with Raspberry Pi

Why DNS Is the Most Overlooked Security Layer in Your Home Network

Put a Pi-hole on a normal home network and watch the query log for ten minutes with nothing running. The television you switched off two hours ago is still resolving domains. So is the thermostat, the printer, and a phone sitting face-down on a table. Most people’s first reaction to that log is not “I am blocking ads” — it is “what is all of this, and how long has it been happening?”

That visibility is the real product. Every connection any device makes starts with a DNS query, and by default those queries go in plaintext to whatever resolver your ISP handed out over DHCP. Your ISP sees every domain. Anyone on the path can see them too. And because the response is unauthenticated, a forged one redirects you somewhere else entirely without a single warning in the browser.

Pi-hole puts a resolver you control in that position. Every device sends queries to it, it checks each domain against blocklists, and requests to known ad, tracking and malware infrastructure get a dead answer instead of a real one. Nothing is installed on the devices themselves — which is the point, because you cannot install anything on a smart TV.

Set expectations honestly, though. Pi-hole blocks by domain name, so anything served from the same hostname as the content you want survives it: YouTube’s in-stream ads, most first-party analytics, and anything an app hardcodes to an IP address. It is a strong privacy and telemetry control and a genuine malware layer. It is not a replacement for uBlock Origin in your browser, and the two do different jobs.


How DNS Sinkholing Works

A browser ad blocker lets the page load and then hides the parts you did not want. Pi-hole works a layer earlier: the device asks for tracker.example.com, gets 0.0.0.0 back, and never opens a socket at all. No TCP handshake, no TLS negotiation, no request — so the tracking server never learns your IP address, and no code from it ever runs.

The practical consequence is that blocked things fail rather than disappear. A blocked ad slot leaves a gap; a blocked analytics call may make a page’s JavaScript hang waiting for a response that resolves instantly to nowhere. Most of the time this is invisible. Occasionally it is a login button that does nothing, and the fix is a single whitelisted domain rather than switching the whole thing off.

%%{init: {'theme': 'dark', 'themeVariables': {'primaryColor': '#1e293b', 'primaryTextColor': '#e2e8f0', 'primaryBorderColor': '#475569', 'lineColor': '#0284c7', 'secondaryColor': '#0f172a', 'tertiaryColor': '#1e293b', 'background': '#0f172a', 'mainBkg': '#1e293b', 'nodeBorder': '#475569', 'clusterBkg': '#0f172a', 'titleColor': '#e2e8f0', 'edgeLabelBackground': '#1e293b'}}}%% graph TD Client["Client Device (PC/Phone/IoT)"] -->|1. DNS Request: 'tracker.evil.com'| PH["Pi-hole (Local DNS Resolver)"] PH -->|2. Check Blocklists (Gravity) & Regex| Decision{"Is Domain Blocked?"} Decision -->|Yes| Sink["Return 0.0.0.0 (Sinkhole)"] Sink -->|3. Connection Dropped Immediately| Client Decision -->|No| Cache{"Is Query in Local Cache?"} Cache -->|Yes| CachedResp["Return Cached IP Address"] CachedResp -->|3. Load Safe Service| Client Cache -->|No| Upstream["Forward to Upstream DNS (e.g., Unbound/Quad9)"] Upstream -->|4. Resolve Name & Cache| PH PH -->|5. Return Resolved IP| Client

Because the connection is never made, you save the bandwidth and the round trips, and pages that were waiting on six tracking domains load noticeably faster. The security argument is stronger than the speed one, though: malvertising works by getting hostile JavaScript delivered through a legitimate ad network onto a legitimate site. Code that never loads cannot run, and that protection covers every device on the network — including the ones where you have no way to install anything.


Hardware Options

Pi-hole barely uses any hardware — it runs comfortably on a Pi Zero 2 W. Choose based on the thing that actually matters: this box becomes a single point of failure for your entire household’s internet. When it stops resolving, nothing works, and the person who did not build it will be the one discovering this while you are out.

PlatformDeployment StyleWhat to Know
Raspberry Pi (Zero 2 W, 3, 4, 5)Dedicated physical deviceBest practice: use wired Ethernet. Wi-Fi adds latency and is vulnerable to interference.
Docker ContainerRuns on a home server or NASRequires binding host port 53 (TCP/UDP). Use network_mode: host or configure port mappings carefully.
Proxmox VE (LXC Container)Lightweight VM in a home labSupports snapshots and easy backup. Ideal if you want to run a secondary Pi-hole for redundancy.

Minimum requirements:

  • RAM: 512 MB (1 GB or more recommended for large blocklists or busy networks)
  • Storage: 8 GB MicroSD (Class 10 or better), or an SSD for more reliable long-term operation
  • Network: Wired Ethernet preferred for a device acting as your DNS server

The microSD card is the component that will actually kill this deployment. Pi-hole writes query logs continuously, cheap cards wear out under that pattern, and the failure is rarely a clean death — you get a filesystem that has quietly gone read-only, a Pi that still answers pings, and DNS that has stopped working for reasons no dashboard is telling you. Boot from a USB SSD if you can. If you cannot, make the Teleporter backup described at the end of this article non-negotiable.


Advertisement

Step-by-Step Deployment

1. Prepare the Operating System

If you’re using a Raspberry Pi, start with Raspberry Pi OS Lite (64-bit). Use the Raspberry Pi Imager to flash it, and take advantage of the advanced options to configure a custom user account, enable SSH, and set up SSH key authentication before you even boot the device.

Assign a static IP address. Every device on your network will be configured to send DNS to a specific address, so if that address ever changes, the whole network loses name resolution at once — with no error message anywhere that says why. Do this before anything else.

A DHCP reservation on the router, keyed to the Pi’s MAC address, is the cleanest option: the configuration lives in one place and survives a rebuild of the Pi. Setting it on the device itself works too, and is the better choice if your router’s DHCP server is the thing you are least confident in. Note that the snippet below is the older dhcpcd method, which is what Raspberry Pi OS used through Bullseye:

# Static IP configuration for eth0 (legacy dhcpcd method)
interface eth0
static ip_address=192.168.1.50/24
static routers=192.168.1.1
static domain_name_servers=127.0.0.1

Raspberry Pi OS Bookworm moved to NetworkManager, so on a current image this file is ignored — silently, with no warning that the static address you configured is not in effect. Check with ip addr after a reboot rather than assuming. On NetworkManager systems, nmcli is the tool; on systemd-networkd, a .network unit in /etc/systemd/network/.

2. Install Pi-hole

The official install is a shell script, and nearly every guide tells you to pipe it straight from a URL into bash as root. Think about what that actually is: executing whatever that server returns, with full privileges, sight unseen. The Pi-hole project is trustworthy and the script is fine — that is not the point. The point is that “curl to root shell” is a habit, and the habit is what gets you eventually, on some other project, on some other day. Download it, look at it, then run it:

# Download the installer locally
curl -sSL https://install.pi-hole.net -o basic-install.sh

# Inspect it before running
less basic-install.sh

# Run the installer
sudo bash basic-install.sh

During the interactive setup:

  • Interface: Select your active network interface (eth0 for wired Ethernet).
  • Upstream DNS: Choose a privacy-respecting upstream resolver. Quad9 (9.9.9.9 / 149.112.112.112) offers built-in malicious domain blocking. Cloudflare (1.1.1.1) is fast and privacy-focused. You’ll replace this with Unbound later if you want full recursive resolution.
  • Web Interface: Enable it — the dashboard is genuinely useful for monitoring and managing blocklists.
  • Query Logging: Turn this on. It is what makes the whole thing diagnostic rather than decorative — a compromised IoT device beaconing to a domain registered last week is obvious in the query log and invisible everywhere else. Be aware of what you have built, though: a complete, timestamped, per-device record of every domain anyone in the household visits, sitting on a Pi in a cupboard. That is a more sensitive dataset than most home servers hold, and it is the reason the admin interface should never be exposed to the internet.

After installation, Pi-hole will display an admin password. Copy it immediately, then set a custom one:

# Pi-hole v5 and earlier
pihole -a -p

# Pi-hole v6+
pihole setpassword

Advanced Security Configurations

1. Local Recursive Resolution with Unbound

Pi-hole filters, but it still has to ask someone. Point it at Cloudflare or Google and you have moved the log from your ISP to a company with a better privacy policy — which is an improvement, and is not the same as nobody having the log.

Unbound removes the middleman. It talks to the root servers directly and walks the hierarchy itself: root, then the .com servers, then the domain’s authoritative nameservers. No single party ever sees your complete query stream. It also validates DNSSEC signatures locally, which means a forged response has to survive cryptographic verification on your own hardware rather than being trusted because an upstream resolver said it was fine.

The costs are worth knowing before you commit. Cold lookups are slower — you are making three or four round trips where a public resolver would have answered from its cache in one — and the first visit to an unfamiliar domain is noticeably laggy until Unbound’s own cache warms up. You also lose Quad9’s malicious-domain blocking, which was doing real work; your blocklists now have to cover that ground. And DNSSEC validation is strict, so a domain whose owner has broken their own signing setup becomes unreachable for you while it still resolves for everyone else. That is technically correct behaviour and it will still read as “the internet is broken” to whoever reports it.

%%{init: {'theme': 'dark', 'themeVariables': {'primaryColor': '#1e293b', 'primaryTextColor': '#e2e8f0', 'primaryBorderColor': '#475569', 'lineColor': '#0284c7', 'secondaryColor': '#0f172a', 'tertiaryColor': '#1e293b', 'background': '#0f172a', 'mainBkg': '#1e293b', 'nodeBorder': '#475569', 'clusterBkg': '#0f172a', 'titleColor': '#e2e8f0', 'edgeLabelBackground': '#1e293b'}}}%% graph LR Client["Client Device"] -->|DNS Query| PH["Pi-hole (DNS Filter)"] PH -->|Forward Safe Query (Port 5335)| UB["Unbound (Local Resolver)"] UB -->|1. Query Root Servers| Root["Root Zone Servers (.)"] UB -->|2. Query TLD Servers| TLD["Top-Level Domain (e.g., .com)"] UB -->|3. Query Authoritative DNS| Auth["Authoritative Name Servers"] Auth -->|Resolved IP| UB UB -->|Return IP| PH PH -->|Return IP| Client

Install Unbound:

sudo apt update && sudo apt install unbound -y

Create the Pi-hole configuration file:

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

Paste the following hardened configuration:

server:
    verbosity: 1
    interface: 127.0.0.1
    port: 5335
    do-ip4: yes
    do-udp: yes
    do-tcp: yes
    do-ip6: no

    # Root hints file for bootstrapping recursive resolution
    root-hints: "/var/lib/unbound/root.hints"

    # DNSSEC validation
    auto-trust-anchor-file: "/var/lib/unbound/root.key"

    # Buffer and cache sizing
    so-rcvbuf: 4m
    so-sndbuf: 4m
    msg-cache-size: 64m
    rrset-cache-size: 128m
    infra-cache-numhosts: 10000

    # Security hardening
    harden-glue: yes
    harden-dnssec-stripped: yes
    use-caps-for-id: no
    edns-buffer-size: 1232
    prefetch: yes
    num-threads: 1

    # Block private IP responses from public DNS (DNS rebinding protection)
    private-address: 192.168.0.0/16
    private-address: 169.254.0.0/16
    private-address: 172.16.0.0/12
    private-address: 10.0.0.0/8

Restart Unbound:

sudo service unbound restart

A few lines in that config are doing more than they look like. interface: 127.0.0.1 binds Unbound to loopback only, so it is not an open resolver the rest of the internet can abuse for amplification attacks — leave that alone. The private-address block is DNS rebinding protection: it discards any answer from a public nameserver that points at an RFC 1918 address, which is precisely the trick used to make a browser attack a device on your LAN. And do-ip6: no disables IPv6 resolution, which is right if your network has no IPv6 and wrong the moment it does.

Point Pi-hole at Unbound: in the Admin Console, go to Settings > DNS, remove every public upstream, and enable Custom 1 (IPv4) with 127.0.0.1#5335. Removing the public resolvers matters as much as adding the local one — leave one selected and Pi-hole will keep sending a share of your queries there, and you will believe you are running a private resolver while half your traffic goes to Cloudflare.


Advertisement

2. Curated Threat Intelligence Blocklists

The default list targets advertising. Malware domains, command-and-control infrastructure and IoT telemetry need lists maintained by people tracking those specifically.

Firebog’s Curated Lists is the usual starting point, and the colour coding is the useful part: the green lists are the ones vetted as unlikely to break normal browsing. Start with those only.

The temptation is to add everything and end up with three million blocked domains, which feels productive and is the most common way people ruin their own setup. Every list you add is a maintainer you are trusting, and aggressive lists break things in ways that are hard to attribute — a payment page that fails at checkout, an app that will not sign in, a delivery notification that never arrives. Weeks later nobody connects it to the blocklist added on a Sunday afternoon, and the household conclusion is that the Pi-hole is the problem. Add lists one at a time and live with each for a week.

To add a list:

  1. Open the Pi-hole Admin Console and go to Adlists (or Group Management > Adlists in newer versions).
  2. Paste the list URL and click Add.
  3. Update the blocklist database:
    pihole -g
    

Run pihole -g on a schedule — weekly is fine. Phishing and malware infrastructure rotates through newly registered domains constantly, so a list you downloaded six months ago is covering campaigns that ended. Nothing tells you this has gone stale; the dashboard keeps showing a healthy block percentage, because the ad domains it is still catching have not moved.

3. Blocking Smart TV and IoT Telemetry with Regex

Smart devices phone home relentlessly, and they do it across dozens of rotating subdomains, so adding entries one at a time is a losing game. Regex blocking lets you take out a whole family in one rule. It is also the sharpest tool here — a pattern broader than you intended blocks things you never inspected, and because regex matches are less obvious in the query log than a named blocklist entry, they are the hardest blocks to debug later.

In the web panel, go to Domains, select the RegEx filter tab, and add patterns like these:

# Samsung Smart TV telemetry
^(.+[_.-])?samsungcloudplatform\.com$

# LG smart ad tracking
^(.+[_.-])?ad\.lgsmartad\.com$

# Windows diagnostic telemetry
^(.+[_.-])?telemetry\.microsoft\.com$

Do not copy these blindly — write your own from evidence. Filter the query log by the device’s IP address, watch what it actually asks for over a day, and build the pattern from that. It is also worth knowing that some devices treat blocked telemetry as a fault and retry aggressively, so a rule that works can produce a device generating far more DNS traffic than before. And a handful of appliances, televisions especially, refuse to complete setup or degrade features when they cannot reach their telemetry endpoint. When that happens the honest options are to unblock it or replace the device; there is no third answer.


Configuring Your Router

Pi-hole only sees queries that are sent to it. Everything above is irrelevant for any device that resolves elsewhere — and there are more of those than you expect. Handing out the Pi-hole address via DHCP covers the ordinary case; the exceptions are covered after it.

  1. Log into your router’s admin panel (usually 192.168.1.1 or 192.168.0.1).
  2. Find the DHCP settings for your LAN — not the WAN DNS settings.
  3. Set DNS 1 to Pi-hole’s static IP (e.g., 192.168.1.50).
  4. Do not add a public fallback DNS. This is the mistake that quietly defeats the entire setup. Set 8.8.8.8 as a secondary and clients will not treat it as a backup — most operating systems query whichever server answers first, or alternate between them, so a large share of your traffic bypasses Pi-hole while the dashboard happily reports a healthy block rate on the rest. If you need redundancy, run a second Pi-hole and point DNS 2 at that.
  5. Renew leases on connected devices by restarting them or toggling flight mode on phones. On Windows, ipconfig /flushdns. Then confirm it worked by checking that the query log shows traffic from more than one client IP — if you only ever see the router’s address, your router is proxying DNS and you have lost all per-device visibility.

Three things will still route around this. Some devices — Chromecasts and various smart TVs are the usual culprits — ignore DHCP-supplied DNS entirely and hardcode 8.8.8.8; the only fix is a firewall rule redirecting or dropping outbound port 53 to anything other than the Pi-hole. Browsers increasingly enable DNS-over-HTTPS by default, which sends queries to the browser vendor’s resolver over 443 where you cannot see or block them, so turn DoH off in the browser or configure it to use the Pi-hole. And any device on a VPN is resolving through that tunnel, as designed. None of these produce an error. They just silently stop appearing in your logs.


Maintenance and Troubleshooting

Debug from the query log, not from guesses. When something breaks after you add a list, open the site, watch the log live, and look for the red entries appearing as it loads. That takes thirty seconds and tells you the exact domain. Whitelist that one domain — never disable the blocklist, and never use the “disable blocking for 5 minutes” button as a diagnosis, because it confirms Pi-hole is involved without telling you which rule did it.

Never expose the admin interface. It is an unauthenticated-by-default-ish web panel sitting in front of a complete record of your household’s browsing, and port-forwarding it is how that record ends up somewhere else. Use Tailscale or WireGuard on the Pi for remote administration. The bonus is that a phone connected to that VPN also resolves through Pi-hole while you are out, which is the one configuration that extends the filtering beyond your front door.

Watch for the silent failure. The genuinely dangerous state is not Pi-hole crashing — that is loud, because the internet stops. It is Pi-hole running while the SD card has gone read-only, or pihole -g failing every week against a list URL that has moved. Both leave the dashboard looking perfectly normal. pihole status and a glance at the gravity update output every month or two is enough to catch either.

Useful CLI commands:

# Check Pi-hole status
pihole status

# Generate a diagnostic debug log
pihole -d

# Restart the DNS service
pihole restartdns

# Update Pi-hole itself
pihole -up

Wrapping Up

An afternoon of work buys you something unusual: a control that covers every device on the network, including the ones you cannot install software on, and a log that turns “my network” from an assumption into something you can actually look at.

Build it in that order — Pi-hole first with a conservative list, Unbound once that is stable, regex rules last and only from evidence in your own query log. Doing all three at once means that when something breaks, you will not know which of the three did it.

And accept the operational reality you have signed up for. You are now the DNS server for your household. Anything you break, everyone notices, immediately. Write the static IP address on a label and stick it to the Pi, so that whoever has to fix this while you are unreachable has somewhere to start.

Before anything breaks your setup: Use the Teleporter tool in Settings > Teleporter to export your configuration and blocklists. SD cards fail, and being able to restore your Pi-hole in minutes rather than hours is worth the two minutes it takes to make a backup.


Share article

Subscribe to my newsletter

Receive my case study and the latest articles on my WhatsApp Channel.

Warning

Ask CyberROX AI