Programster's Blog

Tutorials focusing on Linux, programming, and open-source

Debian 12 - Deploy Unbound, the Recursive DNS Resolver

Introduction

Unbound is a DNS resolver, meaning it's designed to resolve domain names to IP addresses by querying the DNS hierarchy, starting from the root servers. This means that you do not need to configure it with an upstream like you do with stubby. This tutorial will show you how to install Unbound, before then also showing you how you can configure it to act as a forwarding resolver and why you may wish to do so.

Steps

Install

sudo apt update \
  && sudo apt install unbound unbound-anchor -y

This installed version 1.17.1 at the time of writing this.

Get Version

Test the installation was successful by outputting the version of Unbound with:

sudo unbound -v

Configuring Unbound To Be A Forwarding Resolver

Explanation

At this point unbound is working as a recursive DNS resolver, and you could just use it as such by pointing your devices to use it as your DNS server (that also performs caching).

However, with regards to encryption and privacy, unbound supports clients connecting to it over an encrypted method (DoT/DoH) but it does not use encryption when it performs the normal recursive lookups. This effectively means that if you were trying to hide your traffic from your ISP, you haven't achieved anything. If you just wanted a caching DNS resolver, so that you didn't need to rely on other resolvers out there like Google, Quad9, or Cloudflare, then this was a good enough solution and you can stop here.

If you are concerned about privacy, and want to hide your DNS lookups from your ISP, then you need to reconfigure Unbound to be a forwarding DNS resolver, rather than a recursive DNS resolver. This effectively makes unbound itself a client to another server out there that acts like Unbound, but the key thing being that now you can use an encrypted connection to the remote server. Thus, your ISP can't look at the DNS queries, only the server you are forwarding your requests to (Google, Quad9, Cloudflare etc).

Side Note - DoT and Not DoH

Unfortunately, Unbound does not support connecting to the upstream with DNS over HTTPS (DoH), only DNS over TLS (still encrypted). The only downside to this is that your ISP will be able to guess that you are performing encrypted DNS queries, and where they are being sent to. They can't tell what those queries actually are. If you were in an authoritarian state trying to control the internet, they would likely block this port, but would probably not be able to block off the HTTPS port 443, which is why DoH is useful. In such a scenario, you would likely need to create an Unbound server outside the country, that you could then connect to using another Unbound server, using DoH, from inside the country.

Actual Configuration

To perform the necessary configuration changes create a backup of the original unbound configuration before creating a replacement.

sudo mv -i /etc/unbound/unbound.conf /etc/unbound/unbound.conf.bak
sudo editor /etc/unbound/unbound.conf

Paste in the following YAML configuration and adjust if required. The area you probably care most about is the bottom, which is currently configured to only use Cloudflare, but you may use to use someone else instead or in addition to. You may also wish to reduce the verbosity/logging levels for less logs.

This configuration also adds DNSSEC configurations for security to prevent invalid DNS results coming back from upstream. Refer here for more information about the various parameters.

# Commenting this out, as one of the files sets auto-trust-anchor-file
# and other things, but wish to have everything explicitly set here.
#include-toplevel: "/etc/unbound/unbound.conf.d/*.conf"

# Allow control through a socket file. You will need this if you want to 
# run the command to get statistics etc.
remote-control:
  control-enable: yes
  # by default the control interface is is 127.0.0.1 and ::1 and port 8953
  # it is possible to use a unix socket too
  control-interface: /run/unbound.ctl

server:
    # Listen for external requests
    interface: 0.0.0.0

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

    tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt


    # One thread should be sufficient, can be increased on beefy 
    # machines. In reality for most users running on small networks or on a 
    # single machine it should be unnecessary to seek performance enhancement 
    # by increasing num-threads above 1.
    num-threads: 2

    # Specify which LAN IPs can connect to query us.
    access-control: 192.168.0.0/16 allow
    access-control: 172.16.0.0/12 allow
    access-control: 10.0.0.0/8 allow

    # Trust glue only if it is within the servers authority
    harden-glue: yes

    # Require DNSSEC data for trust-anchored zones, if such data is absent, the zone becomes BOGUS
    harden-dnssec-stripped: yes

    harden-below-nxdomain: yes
    harden-referral-path: yes
    harden-algo-downgrade: no
    hide-identity: yes
    hide-version: yes

    # Don't use Capitalization randomization as it known to cause DNSSEC issues sometimes
    # see https://discourse.pi-hole.net/t/unbound-stubby-or-dnscrypt-proxy/9378 for further details
    use-caps-for-id: no

    # Caching
    prefetch: yes
    prefetch-key: yes
    msg-cache-size: 128k
    msg-cache-slabs: 2
    rrset-cache-size: 8m
    rrset-cache-slabs: 2
    key-cache-size: 32m
    key-cache-slabs: 2
    #cache-min-ttl: 600

    # logging
    use-syslog: yes
    verbosity: 3
    val-log-level: 2
    log-time-ascii: yes
    log-queries: yes
    log-tag-queryreply: yes
    log-replies: yes

forward-zone:
    name: "."
    forward-tls-upstream: yes
    forward-addr: 1.1.1.1@853
    forward-addr: 1.0.0.1@853

Get Trust Anchor

The configuration above enables DNSSEC, which needs to set up a trust anchor as it allows the verification of the integrity of the responses to the queries you send. To automatically generate the anchor file, run the following command:

sudo unbound-anchor

Related docs

Restart Unbound

Now let's restart unbound in order to apply our configuration:

sudo service unbound restart

Extra

Watch Unbound Logs

If you used the configuration above, which tells unbound to use the syslog, then you can watch the logs outputted from unbound by running the following command:

sudo journalctl -f -u unbound

Get Statistics

sudo unbound-control stats

References

Last updated: 9th March 2025
First published: 9th March 2025

This blog is created by Stuart Page

I'm a freelance web developer and technology consultant based in Surrey, UK, with over 10 years experience in web development, DevOps, Linux Administration, and IT solutions.

Need support with your infrastructure or web services?

Get in touch