Setting up Unbound from scratch

on Ubuntu Server xenial or artful

Preliminary Step

Make sure you do NOT have those installed: dnsmasq, resolvconf, NetworkManager. If so, disable or remove them.


Either install some binary package,

apt install unbound

Or build from scratch as follows.

Install a few required libraries,

apt install libevent-dev libexpat1-dev

Note. libevent is optional but as stated in the README, it may be useful in case of using many outgoing ports (1000+). Use with --with-libevent at compilation time.

Package description (apt show libevent-dev) says,

Description: Asynchronous event notification library (development files)
 Libevent is an asynchronous event notification library that provides a
 mechanism to execute a callback function when a specific event occurs
 on a file descriptor or after a timeout has been reached.
 This package includes development files for compiling against libevent.

Fetch the latest version of Unbound and compile it,

#SHA256 checksum: e297aa1229015f25bf24e4923cb1dadf1f29b84f82a353205006421f82cc104e
sha256sum unbound-1.6.5.tar.gz
tar xzf unbound-1.6.5.tar.gz
cd unbound-1.6.5/
./configure --with-libevent
make install

Create a system user for Unbound to drop its priviledges,

useradd -r unbound
grep unbound /etc/passwd
grep unbound /etc/group

Generate the TLS key files for the unbound-control tool to work,

ls -lhF /usr/local/etc/unbound/unbound*.{key,pem}


Check how many cores you have got,

grep ^processor /proc/cpuinfo

Setup the caching name server,

#cd /etc/
#ln -s /usr/local/etc/unbound
cd /etc/unbound/
grep -Ev '^[[:space:]]*(#|$)' unbound.conf
ls -l /var/lib/unbound/root.key
mkdir trash/
mv unbound.conf unbound.conf.d/ trash/
vi unbound.conf #new file

        verbosity: 1
        #verbosity: 3
        num-threads: HOW_MANY_CORES
        interface: ::0
        access-control: allow
        access-control: ::/0 allow
        pidfile: "/var/run/"
        root-hints: "named.cache"
        hide-identity: yes
        hide-version: yes
        #rrset-roundrobin: yes
        qname-minimisation: yes
        auto-trust-anchor-file: "/var/lib/unbound/root.key"

        do-not-query-localhost: no
        domain-insecure: "example.local"
        domain-insecure: ""
        #local-zone: "example.local" transparent
        #local-zone: "" transparent

        control-enable: yes

        name: "example.local"
        stub-addr: ::1@5353

        name: ""
        stub-addr: ::1@5353


Always watch the logs in another window,

tail -F /var/log/syslog

Check the configuration,

unbound-checkconf /etc/unbound/unbound.conf

Run the daemon,

#unbound-control start
systemctl restart unbound

Check the status and see if port 53 is used,

unbound-control status
ls -alhF /var/run/
cat /var/run/
ps auxfw | grep ^unbound
netstat -antupe --inet --inet6 | grep -E ':53[[:space:]]'

To load the configuration changes,

unbound-control reload

To flush the cache against a specific zone,

unbound-control flush_zone example.local

to flush the cache overall, not sure reload is enough, but stop/start will do for sure.

Print some stats,

unbound-control stats_noreset


Testing local-zone,

host localhost localhost
host localhost

Testing cached public zone,

host localhost
host localhost

Testing cashed stub-zone,

host example.local localhost
host pxe.example.local localhost
host INTERNAL_IP localhost


If Unbound service is listening but refusing to answer queries, fix access-control: as shown in the example above.

With verbosity 3, if you get,

configured stub servers failed -- returning SERVFAIL

==> check do-not-query-localhost

Against a stub zone too, if you get,

info: query response was nodata ANSWER

==> if it is not signed, domain-insecure helps.


man 5 unbound.conf /


unbound/doc/ old

[Unbound-users] reverse lookup stub zone

Unbound DNS Server Cache Control

Nethence | Doc | Pub | Lab | Pbraun | SNE Russia | xhtml