Mastering DNS Privacy: Pi-hole + Unbound. (part 1)
Pi-hole is a powerful network-wide ad blocker that also functions as a DNS sinkhole. It blocks unwanted content, enhances privacy, and speeds up your browsing experience by preventing ads, trackers, and malicious domains from even loading.

Pi-hole + Unbound enhances privacy by blocking ads, trackers, and malicious domains while preventing ISP snooping, DNS hijacking, and censorship. Unlike third-party resolvers such as Google DNS, Cloudflare, or ISP-provided DNS, Unbound operates recursively, ensuring complete independence and security. With DNSSEC validation and intelligent caching, browsing becomes faster, safer, and free from manipulation—delivering seamless, private, and reliable connectivity.
Step 1: Get Started
- Update your system packages:
$ sudo apt update && sudo apt upgrade -y
- Install necessary dependencies:
$ sudo apt install curl git -y
Step 2: Install Pi-hole v6
- Run the automated installation script:
$ curl -sSL https://install.pi-hole.net | bash
During installation, follow the prompts to configure settings such as upstream DNS providers and blocklists.
- Follow the installation prompts:
- Choose your preferred upstream DNS provider (e.g., Google, OpenDNS, Quad9).
- Select the network interface (typically eth0 for wired or wlan0 for Wi-Fi).
- Set a static IP address (recommended for consistent network behavior).
- Confirm installation of the web admin interface and logging settings.
Step 3. Access Pi-hole Admin Interface
- After installation, access the web interface using the device's IP address:
1. http://[Your Pi-hole IP]/admin
2. After installing Pi-hole for the first time,
a password is generated and displayed to the user.
The password cannot be retrieved later on, but it is possible
to set a new password (or explicitly disable the password by
setting an empty password) using the command
$ sudo pihole setpassword

Step 4. Install Unbound
Unbound will be configured as a recursive DNS resolver.
$ sudo apt install unbound -y
1. Configure Unbound
Create a new configuration file for Unbound:
$ sudo nano /etc/unbound/unbound.conf.d/pi-hole.conf
2. Add the following configuration
server:
# Allow requests only from local network and VPN
access-control: 127.0.0.0/24 allow # Allow DNS queries from localhost (IPv4 loopback range)
access-control: ::1 allow # Allow DNS queries from localhost (IPv6 loopback)
access-control: 192.168.1.0/24 allow # Allow DNS queries from local network devices
access-control: 10.8.0.0/24 allow # Allow DNS queries from VPN clients (e.g., WireGuard or OpenVPN)
# Listen on these interfaces
interface: 127.0.0.1 # Listen on the local loopback interface (for Pi-hole integration)
interface: 192.168.1.xxx # Listen on the local network interface (your device's IP on LAN)
interface: 10.8.0.1 # Listen on the VPN interface (VPN gateway address)
port: 5353 # Use port 5353 to avoid conflicts with other DNS services
# IPv4 and Protocol Settings
do-ip4: yes # Enable IPv4 DNS resolution
do-udp: yes # Allow DNS queries over UDP (faster for short queries)
do-tcp: yes # Allow DNS queries over TCP (required for large responses)
# Privacy settings
hide-identity: yes # Hide server identity to enhance privacy
hide-version: yes # Hide Unbound version for security reasons
qname-minimisation: yes # Minimize query names to improve privacy and reduce tracking risks
harden-glue: yes # Harden against malicious or incorrect glue records in DNS responses
harden-dnssec-stripped: yes # Ensure DNSSEC validation for domains supporting it
use-caps-for-id: yes # Use random capitalization in queries for better security (anti-spoofing)
# Cache settings
cache-min-ttl: 3600 # Minimum Time to Live (TTL) of 1 hour for cached DNS responses
cache-max-ttl: 86400 # Maximum TTL of 24 hours for cached DNS responses
# Security and DNSSEC
trust-anchor-file: "/var/lib/unbound/root.key" # Path to DNSSEC root key for validating DNS responses
root-hints: "/var/lib/unbound/root.hints" # Path to root server hints file for recursive DNS resolution
Notes:
• The access-control and interface settings ensure that only trusted devices (from local and VPN networks) can use Unbound for DNS resolution, enhancing security.
• The port: 5353 setting avoids conflicts with Pi-hole, which typically uses port 53.
3. Download and Update root.hints
Root Hints:
Root hints are a list of authoritative IP addresses for root DNS servers that guide recursive resolvers (like Unbound) to the name servers for top-level domains (TLDs) such as .com and .net.
How It Works:
1. Unbound checks the root hints file if a query isn't in its cache.
2. It asks the nearest root server for the TLD's authoritative name servers.
3. The root server points to the TLD's servers.
4. Unbound continues querying until it finds the authoritative server with the domain's IP address.
Get the latest version from the official source managed by IANA:
$ sudo wget -O /var/lib/unbound/root.hints https://www.internic.net/domain/named.root
This file needs to be periodically updated to ensure accurate DNS resolution because the root servers' IP addresses can change over time.
Initialize and keep root.hints Updated
Since the IP addresses of root DNS servers can change occasionally, it's essential to keep the root.hints file up-to-date every 3 to 6 months to maintain accurate DNS resolution.
$ sudo curl -o /var/lib/unbound/root.hints https://www.internic.net/domain/named.cache
Or automate the update with a cron job.
$ sudo crontab -e
and add this line (Once a Month: To run on the 1st of every month at 2:30 AM)
# Update root.hints every 3 months
0 0 1 */3 * wget -O /var/lib/unbound/root.hints https://www.internic.net/domain/named.cache
This schedule runs the update on the first day of every third month at midnight, ensuring consistent accuracy.
4. Set Correct Permissions
Ensure Unbound can read the file:
$ chown unbound:unbound /var/lib/unbound/root.hints
$ chmod 644 /var/lib/unbound/root.hints
5. View Root Hints File
$ cat /var/lib/unbound/root.hints
This displays the list of IP addresses and domain names for the root servers, ensuring your Unbound server can accurately resolve DNS queries.
; This file holds the information on root name servers needed to
; initialize cache of Internet domain name servers
; (e.g. reference this file in the "cache . <file>"
; configuration file of BIND domain name servers).
;
; This file is made available by InterNIC
; under anonymous FTP as
; file /domain/named.cache
; on server FTP.INTERNIC.NET
; -OR- RS.INTERNIC.NET
;
; last update: January 29, 2025
; related version of root zone: 2025012901
;
; FORMERLY NS.INTERNIC.NET
;
. 3600000 NS A.ROOT-SERVERS.NET.
A.ROOT-SERVERS.NET. 3600000 A 198.41.0.4
A.ROOT-SERVERS.NET. 3600000 AAAA 2001:503:ba3e::2:30
;
; FORMERLY NS1.ISI.EDU
;
. 3600000 NS B.ROOT-SERVERS.NET.
B.ROOT-SERVERS.NET. 3600000 A 170.247.170.2
B.ROOT-SERVERS.NET. 3600000 AAAA 2801:1b8:10::b
;
; FORMERLY C.PSI.NET
- Update DNSSEC root.Key (Trust Anchor)
What is the root.key?
The DNSSEC root key, also known as the trust anchor, is a cryptographic key used by Unbound to validate the authenticity and integrity of DNS responses. It ensures that DNS queries are protected from tampering or spoofing.
Since the root key occasionally changes during a "key rollover" managed by ICANN, it's crucial to keep it up-to-date for continued DNSSEC validation.
How It Works:
1. Unbound checks the DNS response's digital signature against the root key.
2. If it matches, the response is verified as authentic.
3. This validation continues down the DNS hierarchy, ensuring trust at each level.
Initialize and keep the root.key Updated
Since ICANN occasionally changes the root key during a "key rollover," it's essential to keep it up-to-date every 3 to 6 months to maintain reliable DNSSEC validation.
$ sudo unbound-anchor -a "/var/lib/unbound/root.key"
Or automate the update with a cron job.
$ sudo crontab -e
and add this line (Once a Month: To run on the 1st of every month at 2:30 AM)
30 2 1 * * unbound-anchor -a "/var/lib/unbound/root.key"
This runs the update at 2:30 AM on the 1st day of every month.
- Check Unbound Configuration Before Restarting
To validate the Unbound settings and ensure there are no syntax errors before restarting the service, use:
$ sudo unbound-checkconf
If no errors are found, it returns "no errors in configuration file" otherwise it displays the line number and details of the issue.
- Apply Changes and Enable Unbound
$ sudo systemctl restart unbound
$ sudo systemctl enable unbound
Don't stop now! [Part 2 awaits.]
Pi-hole provides powerful network-wide ad blocking and DNS management, enhancing privacy, security, and browsing speed. Paired with Unbound as a recursive DNS resolver, it bypasses third-party DNS providers, ensuring greater privacy and independence. Pi-hole filters ads at the DNS level, giving you control over domain access and detailed insights into network activity. Regularly updating blocklists maintains ongoing protection. With this setup, you gain full control over your network's security and digital experience.
Stay secure. Stay curious.
Stay SNUBbed!