Skip to content

A guide and config files for turning a Raspberry Pi into a powerful ad & malware blocker. This setup uses Pi-hole + Unbound for a private, secure, and self-hosted DNS solution that keeps your browsing history away from your ISP. 🛡️

Notifications You must be signed in to change notification settings

rish1keshh/ZeroShield

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 

Repository files navigation

ZeroShield: Privacy-Hardened Raspberry Pi DNS Resolver

This project documents the setup of a network-wide, privacy-focused DNS sinkhole on a Raspberry Pi Zero 2 W. It combines Pi-hole for ad and malware blocking, Unbound as a local recursive DNS resolver for maximum privacy, and Cloudflared as a secure DNS-over-HTTPS (DoH) fallback.

This setup is optimized for low-resource hardware and hardened to prioritize privacy and security over speed, ensuring that personal DNS data is never leaked to third parties during normal operation.


🏛️ Final Architecture

A client on the network makes a DNS request. The request is processed as follows:

  1. The query is sent to Pi-hole, which checks it against its blocklists.
  2. If not blocked, the query is forwarded to the primary upstream resolver, Unbound.
  3. Unbound resolves the query recursively by contacting the root DNS servers directly, validating each step with DNSSEC.
  4. If Unbound fails to respond, Pi-hole forwards the query to the secondary upstream resolver, Cloudflared.
  5. The strict-order configuration ensures that Cloudflared is only used in a true failure scenario, not in a "race" for the fastest response.
                      +-------------------+      +----------------+      +------------------+
Your Devices          |                   |      |                |      |                  |
(Laptop, Phone, IoT)  |      Pi-hole      |----->|     Unbound    |----->|  Root DNS Servers|
    |                 | (Ad/Malware Filter) |      | (Recursive DNS)|      |    (Authoritative) |
    |                 |  + strict-order   |      |  + DNSSEC      |      +------------------+
    |                 +-------------------+      +----------------+
    |                               ^
    |                               |
    +-------------------------------+
                                    | (Fallback on Failure Only)
                                    |
                                    v
                              +----------------+
                              |   Cloudflared  |
                              | (DNS-over-HTTPS)|
                              +----------------+

✨ Key Features

  • Ultimate Privacy: Unbound acts as a personal recursive resolver, meaning your DNS history is not sent to any third-party provider (like Google, OpenDNS, or even Cloudflare in normal operation).
  • Robust Security: Unbound performs DNSSEC validation on all queries, protecting against DNS spoofing and cache poisoning attacks. Pi-hole blocks known malware and phishing domains using curated security blocklists.
  • Network-Wide Control: Blocks ads and malicious domains for every device on the network, including smart TVs, game consoles, and IoT devices.
  • Resilient Design: Uses Cloudflared as a secure, encrypted DoH fallback in the event that the local Unbound resolver fails.

🚀 Repository Contents

This repository contains the key custom configuration files created for this project. To replicate this setup, you would first install Pi-hole, Unbound, and Cloudflared, and then apply these configurations.

1. Unbound Configuration

This file configures Unbound to run as a secure, recursive resolver optimized for a Raspberry Pi Zero 2 W.

File: unbound/pi-hole.conf (Place in /etc/unbound/unbound.conf.d/ on the Pi)

server:
    # Run as a less-privileged user
    username: "unbound"

    # The path to the root hints file
    root-hints: "/var/lib/unbound/root.hints"

    # Enable DNSSEC validation
    harden-glue: yes
    harden-dnssec-stripped: yes
    use-caps-for-id: no

    # Reduce logging verbosity
    verbosity: 0

    # Interface and port to listen on
    interface: 127.0.0.1
    port: 5335
    do-ip4: yes
    do-udp: yes
    do-tcp: yes

    # Allowed access control
    access-control: 127.0.0.0/8 allow

    # Optimization for Raspberry Pi Zero 2 W (512MB RAM)
    num-threads: 1
    msg-cache-size: 4m
    rrset-cache-size: 8m
    so-rcvbuf: 1m

    # Hide identity and version
    hide-identity: yes
    hide-version: yes

    # Prefetch popular DNS records to improve performance
    prefetch: yes

2. Dnsmasq (Pi-hole) Configuration

This critical file forces Pi-hole to use its upstream DNS servers in a strict order, solving the "DNS race" problem and ensuring Unbound is always prioritized.

File: dnsmasq/99-strict-order.conf (Place in /etc/dnsmasq.d/ on the Pi)

strict-order

3. Pi-hole FTL Configuration

This optional file optimizes Pi-hole's database by reducing the query retention period, saving memory and disk space.

File: pihole/pihole-FTL.conf (Place in /etc/pihole/ on the Pi)

MAXDBDAYS=7

4. System Swap Configuration

This change increases the system's swap file to 1GB to prevent out-of-memory crashes on the Raspberry Pi Zero 2 W.

File: /etc/dphys-swapfile (This is an existing file. Only the following line should be modified.)

# set size to absolute value, leaving empty (default) then uses computed value
#   you most likely don't want this, unless you have an special disk situation
# CONF_SWAPSIZE=100
CONF_SWAPSIZE=1024

🔧 Troubleshooting & Lessons Learned

During this project, we encountered and solved several key issues.

Problem 1: DNS Leak Test Showed Cloudflare IPs

  • Symptom: The initial DNS leak test showed Cloudflare servers, not our own public IP, even though Unbound was configured as the primary resolver.
  • Investigation: Using pihole -t and dig, we confirmed that Unbound was working perfectly on its own. The Pi-hole query log showed that queries were being consistently forwarded to Cloudflared (127.0.0.1#5053).
  • Root Cause: Pi-hole's default behavior is to forward queries to all upstream servers and use the response from the server that replies the fastest. Cloudflared was consistently winning this "DNS race," so Unbound was rarely being used.
  • Solution: We created the configuration file /etc/dnsmasq.d/99-strict-order.conf and added the strict-order directive. This forces Pi-hole to query its upstream servers in the order they are listed, only using the fallback if the primary fails.

Problem 2: Malware Test Site Was Not Blocked

  • Symptom: Test sites for malware were not being blocked by default.
  • Investigation: We concluded that Pi-hole's default blocklists are focused on ads and trackers, not comprehensive security threats.
  • Solution: We added a dedicated security blocklist to enhance protection.
    1. Navigated to Group Management > Adlists.
    2. Added the URL: https://phishing.army/download/phishing_army_blocklist_extended.txt
    3. Navigated to Tools > Update Gravity to apply the new list.

🔬 Demonstration & Verification

To verify that the system is working as intended, perform the following tests.

1. DNS Leak Test (Primary Goal)

  • Action: Visit dnsleaktest.com and run the Extended Test.
  • Expected Result: The test should show only one server, and its IP address should be your network's public IP address. This proves Unbound is handling all your queries.
DNS Leak Test

2. DNSSEC Validation Test

  • Action: From a client on the network (or the Pi itself), run the following dig commands.

  • Test 1 (Should Succeed):

    dig sigok.verteiltesysteme.net
    • Expected Result: status: NOERROR and the ad (Authenticated Data) flag in the header. sigok
  • Test 2 (Should Fail):

    dig sigfail.verteiltesysteme.net
    • Expected Result: status: SERVFAIL. The query should fail because Unbound rejects the invalid DNSSEC signature. sigfail

3. Ad Blocking Test

  • Action: Visit a modern testing tool like AdBlock Tester.
  • Expected Result: A high score, indicating that various types of ad-serving and tracking scripts are being successfully blocked at the DNS level.
image

4. Security Blocklist Test

  • Action: Test a domain directly from one of your security lists.
    1. View the source of the list we added: Phishing Army Blocklist.
    2. Pick any domain from that list.
    3. Attempt to navigate to that domain in your browser.
  • Expected Result: Your browser will display an error page, such as "This site can’t be reached" or "Secure Connection Failed." This is the correct and expected behavior, confirming the domain was blocked.. image image

🛡️ A Note on Layered Security

During testing, you may notice that ad-blocking tests (like AdBlock Tester) do not score a perfect 100%. This is expected.

Pi-hole is a DNS-level blocker. It can only block entire domains. It cannot block ads that are served from the same domain as the content you want to see (e.g., YouTube or Facebook ads).

For complete protection, a layered approach is recommended:

  1. Pi-hole (Network Layer): Blocks the vast majority of ad and malware domains for all devices on your network.
  2. Browser Extension (Client Layer): Use a reputable content blocker like uBlock Origin in your web browsers. This extension can inspect the content of a page and block the cosmetic ads that Pi-hole cannot, giving you a cleaner browsing experience and a near-perfect score on ad-blocking tests.

About

A guide and config files for turning a Raspberry Pi into a powerful ad & malware blocker. This setup uses Pi-hole + Unbound for a private, secure, and self-hosted DNS solution that keeps your browsing history away from your ISP. 🛡️

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published