Setup Unbound - a validating, recursive, caching DNS resolver

Software · 5 mins read

In the following guide we will install and configure our own instance of a validating, recursive, caching DNS resolver. We will opt for Unbound from NLnet Labs on a Debian based linux distro, but this same configuration can be used across kernels and other supported operating systems.

To proceed, open a terminal window and paste the following command:

sudo apt install unbound

During the installation process some error messages may appear. This is normal since there is no configuration file present in the system and thus Unbound will not be able to start. To proceed in generating the Unbound configuration file, create “example.conf” in the following directory:


You can use nano or any other file editor to copy and save the content below:


verbosity: 0

port: 5678
do-ip4: yes
do-udp: yes
do-tcp: yes
do-ip6: no
prefer-ip6: no

root-hints: "/var/lib/unbound/root.hints"

harden-glue: yes
harden-large-queries: yes
harden-dnssec-stripped: yes
harden-algo-downgrade: yes
harden-referral-path: no
harden-short-bufsize: yes

rrset-roundrobin: yes
unwanted-reply-threshold: 10000000

hide-identity: yes
hide-version: yes
identity: "Server"

deny-any: yes
do-daemonize: no
minimal-responses: yes
use-caps-for-id: no

prefetch: yes
prefetch-key: yes
cache-min-ttl: 300
cache-max-ttl: 28800
serve-expired: no
msg-cache-size: 50m
rrset-cache-size: 100m
edns-buffer-size: 1472
so-rcvbuf: 4m
so-sndbuf: 4m
neg-cache-size: 4m

so-reuseport: yes
qname-minimisation: yes
val-clean-additional: yes

num-threads: 1
msg-cache-slabs: 1
rrset-cache-slabs: 1
infra-cache-slabs: 1
key-cache-slabs: 1

log-queries: no
log-replies: no
log-servfail: no
log-local-actions: no
logfile: /dev/null

private-address: fd00::/8
private-address: fe80::/10

Next step will be to pull the root.hints file from the domain authority for the first time. Execute these two separate commands:

curl -so /var/lib/unbound/root.hints

sudo service unbound restart

The Unbound resolver is now up and running, and will now listen on localhost port 5678. You can change to another IP/port combination in the configuration file.

To make sure that the root.hints file is kept updated (changes rarely and infrequently so around 6 months is quite safe), we can create a cron job that will take care of that for us. Let’s use a separate script for customization sake. Paste the content below in a text editor, like nano, and give it the .sh extension:


test $(date +%m) -eq 2 || test $(date +%m) -eq 7 || exit
curl -so /var/lib/unbound/root.hints
service unbound restart

You can save that file to your home folder, or any other path of your choosing. Don’t forget to give the .sh file permissions to execute:

sudo chmod a+x /home/user/

Finally, let’s schedule a task using cron:

sudo crontab -e

Add this line in the end of the prompt/file and save it:

0 4 1 * * sh /home/user/

These steps will schedule an update of your root.hints at 4 AM every 1st of February and July, and restart the Unbound service to apply the changes.

To make sure your device(s) is(are) using your Unbound instance, make the TXT record query below.

On Unix:

dig +short TXT

On Windows:

nslookup -type=TXT

In the non-authoritative answer, the “ns” record is the unicast IP address of the requesting recursive resolver. You should get your IP if the Unbound instance is local, or your VPS IP if in the cloud. If not, your device is not using your Unbound resolver but some other DNS provider. Check your network/device for DNS leaks.

Share:  EMail · Reddit · Twitter · Telegram · Whatsapp · Threema

Back to previous page