Skip to content

Unbound DNS

Patrick Haney edited this page Feb 26, 2023 · 5 revisions

Setting up Unbound DNS with a Pi-hole installation allows you to operate your own tiny, recursive DNS server instead of relying on (and sending data to) the big players like Google or Cloudflare.

Unbound is a validating, recursive, caching DNS resolver. It is designed to be fast and lean and incorporates modern features based on open standards.

Installing Unbound

To install Unbound on the Raspberry Pi:

sudo apt install unbound

Note: If you've installed Pi-hole first and then Unbound as I have here, you might see some errors during installation of the latter, specifically Job for unbound.service failed because the control process exited with error code. After some research, I decided to continue on with the Pi-hole guide to setting up Unbound, which seemed to work fine. I'm not sure what causes the errors, but I've decided not to investigate further at this time.

Verify the Installation

Despite the error(s), you can check to see if Unbound was installed successfully (and the version that was installed) using the following command:

unbound -V

Download Root Server List

Next we'll need to download a root.hints file to replace the built-in root server hints:

wget -O root.hints https://www.internic.net/domain/named.root

Then move the root.hints file to the Unbound configuration directory:

sudo mv root.hints /var/lib/unbound/

Configure Unbound DNS

Unbound includes a lot of different configuration options that you can adjust and try out. Feel free to scan the Unbound configuration file documentation for details about each option. You can also check the latest Unbound documentation for more details.

To get started, edit the Unbound configuration file for Pi-hole:

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

and remove the contents of the file (there is likely nothing there yet) before copying and pasting the contents of the sample pi-hole.conf configuration file in this repository. When you're done, exit and save the file.

Unbound Configuration File

Configuration Details

The default port for Unbound is 53 but we're changing it to 5353 here. Feel free to change it to whatever you like, but you'll need to remember it later when we tell Pi-hole where to send upstream DNS requests:

port: 5353

This points to the root.hints file you just downloaded:

# Use this only when you downloaded the list of primary root servers!
root-hints: "/var/lib/unbound/root.hints"

Here we're refusing connections to all interfaces and then we're allowing anything from this device (your Raspberry Pi) and anything from our local subnet (be sure to change 192.168.x.0 to whatever your local subnet is):

# IPs authorized to access the DNS Server
access-control: 0.0.0.0/0 refuse
access-control: 127.0.0.1 allow
access-control: 192.168.x.0/24 allow

If your router creates a "Guest Network" with a separate SSID and DHCP range, devices connecting to that wireless network will not be able to connect to the internet unless you grant access to that subnet. Uncomment one of the lines below or add your own based on your guest network's DHCP range:

# If you have a guest network with a separate DHCP range
#access-control: 172.16.1.0/24 allow
#access-control: 10.0.0.0/24 allow

Note: Devices connected to an AirPort guest network will not be able to use Pi-hole since your Raspberry Pi is on a separate DHCP range. They also will not have access to a DNS resolver, so they won't be able to connect to much of anything unless each device is set to manually connect to an outside DNS server, such as 1.1.1.1.

You can adjust the cache settings if you like. Instead of the default of not caching, here we set the minimum TTL (Time To Live) to 1 hour, afterwards the DNS will do another lookup of the cached data:

# Time To Live (in seconds) for DNS cache. Set cache-min-ttl to 0 remove caching (default).
# Max cache default is 86400 (1 day).
cache-min-ttl: 3600
cache-max-ttl: 86400

When Pi-hole was doing DNS, it created this custom record for http://pi.hole so we could easily reach the Web Interface without typing in the static IP address of the Raspberry Pi. Now that Unbound is our DNS, we'll need to create this custom record in the Unbound configuration file. Be sure to replace 192.168.x.x with the static IP address of your Raspberry Pi:

# Create DNS record for Pi-hole Web Interface
private-domain: "pi.hole"
local-zone: "pi.hole" static
local-data: "pi.hole IN A 192.168.x.x"

Test the Configuration File for Errors

Once the configuration file is saved, use the unbound-checkconf command to quickly check your unbound.conf for errors. The console should return:

unbound-checkconf: no errors in /etc/unbound/unbound.conf

Otherwise, check your configuration file and make sure there aren't any extra line breaks, missing colons, or other bad characters.

Running Unbound for the First Time

Now that we have a customized configuration file, start the Unbound DNS server in the background:

sudo service unbound start

Then use dig (a command-line tool to query a nameserver for DNS records) to make sure the Unbound DNS is running (be sure to use the port you set above):

dig pi-hole.net @127.0.0.1 -p 5353

Which should return some information, including a QUESTION SECTION and an ANSWER SECTION that includes pi-hole.net and an IP address. For example:

; <<>> DiG 9.16.37-Debian <<>> pi-hole.net @127.0.0.1 -p 5353
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 47691
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1472
;; QUESTION SECTION:
;pi-hole.net.			IN	A

;; ANSWER SECTION:
pi-hole.net.		3600	IN	A	X.XX.XXX.XX

;; Query time: 91 msec
;; SERVER: 127.0.0.1#5353(127.0.0.1)
;; WHEN: Sun Feb 19 09:03:06 EST 2023
;; MSG SIZE  rcvd: 56

Testing DNSSEC Validation

To make sure the Unbound DNS server is secure, use the dig command to verify DNSSEC records. Cloudflare has a set of tools for doing just that, including the brokendnssec.net domain.

To check a domain with DNSSEC enabled (Cloudflare in this case), run the following command with dig:

dig cloudflare.com @127.0.0.1 -p 5353

Which should return a status of NOERROR and an ANSWER SECTION:

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: XXXXX
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

But if we run dig with a domain that doesn't have DNSSEC enabled (another Cloudflare domain for testing purposes):

dig brokendnssec.net @127.0.0.1 -p 5353

This should return a status of SERVFAIL and no ANSWER SECTION:

;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: XXXXX
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

For more on DNSSEC and additional testing you can do, check out Cloudflare's Troubleshooting DNSSEC information.

Allow Pi-hole to Use Unbound DNS

Now that your Unbound recursive DNS resolver is running locally, we'll force Pi-hole to use it for DNS rather than an outside source like Google (8.8.8.8) or Cloudflare (1.1.1.1) and keep all of our network traffic contained. Any traffic on your network will be sent to Pi-hole, which in turn will use Unbound for DNS resolution before blocking the appropriate domains and returning data.

Update Pi-hole DNS Settings

Open the Pi-hole Web Interface in a web browser while connected to your local network. Then go to Settings > DNS and uncheck any third party Upstream DNS Servers you had selected during setup. Then check the Custom 1 (IPv4) box and then add the following custom DNS Server IP and port to the text input below it:

127.0.0.1#5353

Where 127.0.0.1 points the Pi-hole server (the Raspberry Pi) to itself on port 5353. If you changed the port in your Unbound configuration file, use that port here instead.

Pi-hole DNS Settings

Next, uncheck the Never forward non-FQDN A and AAAA queries and Never forward reverse lookups for private IP ranges options, as they may interfere with accessing local hostnames since Pi-hole is not going to be used as our DHCP server. Do not check Use DNSSEC as Pi-hole will be using your Unbound DNS server, which already enables DNSSEC (Domain Name System Security Extensions).

Pi-hole Advanced DNS Settings

Then check Use Conditional Forwarding and adjust the following settings:

  • For Local network in CIDR notation, follow the Classless Inter-Domain Routing method by specifying the IP addresses available on your network, which in this case is likely xxx.xxx.xxx.1 through xxx.xxx.xxx.255. The notation in this case should be 192.168.1.0/24 if your router's IP is 192.168.1.1
  • Enter your router’s IP address in (typically something like x.x.x.1 on your subnet) in the IP address of your DHCP server (router) text input
  • Optionally add your local domain name (this can sometimes be set on your router, usually under the DHCP settings, to something like home)

Pi-hole Conditional Forwarding

When you're done, don't forget to save your settings.

Verify DNSSEC Signatures

DNSSEC Test

To ensure that Unbound is configured correctly, visit this DNSSEC Tools test in a web browser using a device that's currently within your network and using your Raspberry Pi as a DNS server. If you see a thumbs up image, Unbound is validating DNSSEC signatures properly.

If Unbound DNS Doesn't Start on Reboot

If your Raspberry Pi setup includes WireGuard VPN functionality, the Unbound service may not start properly when you reboot your Pi. Likely this is due to WireGuard not completing its setup on restart before Unbound tries to finish its own. In order to force Unbound to wait for WireGuard, edit the unbound.service file:

sudo nano /etc/systemd/system/multi-user.target.wants/unbound.service

And modify the After=network.target line to read:

After=network.target [email protected]

Save the file and exit nano. Reboot your Raspberry Pi with sudo reboot and check to make sure Unbound is running once it's back online:

dig pi-hole.net @127.0.0.1 -p 5353

Note: You can always manually start the Unbound DNS service with sudo service unbound start.

Buy Me a Coffee?

When I first started tinkering with my Raspberry Pi, I had no idea how much time I would invest in getting it up and running. I'm happy to share my findings with the community here for free, but if you'd like to say thanks, a free coffee (or beer) is always welcome.

ko-fi

Clone this wiki locally