Unbound: Difference between revisions

From ArchWiki
(update interlanguage links (https://github.com/lahwaacz/wiki-scripts/blob/master/update-interlanguage-links.py))
(update status of external links)
 
(172 intermediate revisions by 33 users not shown)
Line 1: Line 1:
[[Category:Domain Name System]]
[[Category:Domain Name System]]
[[zh-cn:Unbound]]
[[ja:Unbound]]
[https://unbound.net/ Unbound] is a validating, recursive, and caching DNS resolver.
[[ru:Unbound]]
[[zh-hans:Unbound]]
{{Related articles start}}
{{Related|Domain name resolution}}
{{Related articles end}}
 
[https://unbound.net/ Unbound] is a validating, recursive, and caching DNS resolver. According to [[Wikipedia:Unbound (DNS Server)|Wikipedia]]:
:Unbound has supplanted the Berkeley Internet Name Domain ([[BIND]]) as the default, base-system name server in several open source projects, where it is perceived as smaller, more modern, and more secure for most applications.


== Installation ==
== Installation ==


Install the {{Pkg|unbound}} package from [[official repositories]].
[[Install]] the {{Pkg|unbound}} package.


Additionally, {{Pkg|expat}} is required for [[DNSSEC]] validation.
Additionally, the {{Pkg|expat}} package is required for [[#DNSSEC validation]].


== Configuration ==
== Configuration ==


''unbound'' is easy to configure. There is a sample config file {{ic|/etc/unbound/unbound.conf.example}}, which can be copied to {{ic|/etc/unbound/unbound.conf}} and with the adjustments to the file for your own needs it is enough to run on both IPv4 and IPv6 without access restrictions.
A default configuration is already included at {{ic|/etc/unbound/unbound.conf}}. The following sections highlight different settings for the configuration file. See {{man|5|unbound.conf}} for other settings and more details.
 
Unless otherwise specified, any options listed in this section are to be placed under the {{ic|server}} section in the configuration like so:


=== Access control ===
{{hc|/etc/unbound/unbound.conf|
server:
  ...
  ''setting'': ''value''
  ...
}}
 
=== Local DNS server ===


You can specify the interfaces to answer queries from by IP address. To listen on ''localhost'', use:
If you want to use ''unbound'' as your local DNS server, set your nameserver to the loopback addresses {{ic|::1}} and {{ic|127.0.0.1}} in {{ic|/etc/resolv.conf}}:


interface: 127.0.0.1
{{hc|/etc/resolv.conf|
nameserver ::1
nameserver 127.0.0.1
options trust-ad
}}


To listen on all interfaces, use:
Make sure to protect {{ic|/etc/resolv.conf}} from modification as described in [[Domain name resolution#Overwriting of /etc/resolv.conf]].


interface: 0.0.0.0
{{Tip|A simple way to do this is to install [[openresolv]] and configure {{ic|/etc/resolvconf.conf}}:


Access can be further configured via the {{ic|access-control}} option:
{{hc|/etc/resolvconf.conf|2=
name_servers="::1 127.0.0.1"
resolv_conf_options="trust-ad"
}}


access-control: ''subnet'' ''action''
Then run {{ic|resolvconf -u}} to generate {{ic|/etc/resolv.conf}}.
}}


For example:
See [[Domain name resolution#Lookup utilities]] on how to test your settings.


access-control: 192.168.1.0/24 allow
Check specifically that the server being used is {{ic|::1}} or {{ic|127.0.0.1}} after making permanent changes to [[resolv.conf]].


''action'' can be one of {{ic|deny}} (drop message), {{ic|refuse}} (polite error reply), {{ic|allow}} (recursive ok), or {{ic|allow_snoop}} (recursive and nonrecursive ok). By default everything is refused except for localhost.
You can now setup ''unbound'' such that it is [[#Forwarding queries]], perhaps all queries, to the DNS servers of your choice.


=== Root hints ===
=== Root hints ===


For querying a host that is not cached as an address the resolver needs to start at the top of the server tree and query the root servers to know where to go for the top level domain for the address being queried. Therefore it is necessary to put a ''root hints'' file into the ''unbound'' config directory. The simplest way to do this is to run the command:
For recursively querying a host that is not cached as an address, the resolver needs to start at the top of the server tree and query the root servers, to know where to go for the top level domain for the address being queried. Unbound comes with default builtin hints. Therefore, if the package is updated regularly, no manual intervention is required. Otherwise, it is good practice to use a root-hints file since the builtin hints may become outdated.
 
First point ''unbound'' to the {{ic|root.hints}} file:
 
root-hints: root.hints
 
Then, put a ''root hints'' file into the ''unbound'' configuration directory. The simplest way to do this is to run the command:
 
{{bc|<nowiki># curl --output /etc/unbound/root.hints https://www.internic.net/domain/named.cache</nowiki>}}
 
When actually using this file, and not the builtin hints, it is a good idea to update {{ic|root.hints}} every six months or so in order to make sure the list of root servers is up to date. This can be done manually or by using a [[systemd timer]]. See [[#Roothints systemd timer]] for an example.


{{bc|<nowiki># wget ftp://FTP.INTERNIC.NET/domain/named.cache -O /etc/unbound/root.hints</nowiki>}}
=== DNSSEC validation ===


It is a good idea to run this every six months or so in order to make sure the list of root servers is up to date. This can be done manually or by setting up a [[cron]] job for the task.
To use [[DNSSEC]] validation, the following setting for the server trust anchor should be under {{ic|server:}}:


Point ''unbound'' to the {{ic|root.hints}} file:
{{hc|/etc/unbound/unbound.conf|
  trust-anchor-file: trusted-key.key}}


root-hints: "/etc/unbound/root.hints"
This setting is done by default[https://github.com/archlinux/svntogit-community/commit/79f1ebebd72b53d3b597f6dc48b84f3d76dd9a0c/trunk/conf]{{Dead link|2024|03|03|status=406}}. {{ic|/etc/unbound/trusted-key.key}} is copied from {{ic|/etc/trusted-key.key}}, which is provided by the {{Pkg|dnssec-anchors}} dependency, whose [[PKGBUILD]] generates the file with {{man|8|unbound-anchor}}.


=== Set /etc/resolv.conf to use the local DNS server ===
DNSSEC validation will only be done if the DNS server being queried supports it. If general [[#Forwarding queries]] have been set to DNS servers that do not support DNSSEC, their answers, whatever they are, should be considered insecure since no DNSSEC validation could be preformed.


Edit {{ic|/etc/resolv.conf}} (See also [[resolv.conf]]):
{{Note|Including DNSSEC checking significantly increases DNS lookup times for initial lookups before the address is cached.}}


nameserver 127.0.0.1
==== Testing validation ====


Also if you want to be able to use the hostname of local machine names without the fully qualified domain names, then add a line with the local domain such as:
To test if DNSSEC is working, after [[starting]] {{ic|unbound.service}}, do:


  domain localdomain.com
  $ unbound-host -C /etc/unbound/unbound.conf -v go.dnscheck.tools
nameserver 127.0.0.1


That way you can refer to local hosts such as mainmachine1.localdomain.com as simply mainmachine1 when using the ssh command, but the drill command below still requires the fully qualified domain names in order to perform lookups.
The response should be the ip address with the word {{ic|(secure)}} next to it.


Testing the server before making it default can be done using the drill command from the {{Pkg|ldns}} package with examples from internal and external forward and reverse addresses:
$ unbound-host -C /etc/unbound/unbound.conf -v badsig.go.dnscheck.tools


$ drill @127.0.0.1 www.cnn.com
Here the response should include {{ic|(BOGUS (security failure))}}.
$ drill @127.0.0.1 localmachine.localdomain.com
$ drill @127.0.0.1 -x w.x.y.z


where {{ic|w.x.y.z}} can be a local or external IP address and the {{ic|-x}} option requests a reverse lookup. Once all is working, and you have {{ic|/etc/resolv.conf}} set to use {{ic|127.0.0.1}} as the nameserver then you no longer need the {{ic|@127.0.0.1}} in the ''drill'' command, and you can test again that it uses the default DNS server - check that the server used as listed at the bottom of the output from each of these commands shows it is {{ic|127.0.0.1}} being queried.
Additionally you can use ''drill'' to test the resolver as follows:


=== Logging ===
$ drill badsig.go.dnscheck.tools
$ drill go.dnscheck.tools


If you will want logging for ''unbound'', then create a log file which can also be in the same directory, but you can choose any location. One way is then to do as root:
The first command should give an {{ic|rcode}} of {{ic|SERVFAIL}}. The second should give an {{ic|rcode}} of {{ic|NOERROR}}.


# touch /etc/unbound/unbound.log
=== Forwarding queries ===
# chown unbound:unbound /etc/unbound/unbound.log


Then you can include the logging parameter when you set up the main {{ic|unbound.conf}} file as below.
If you only want to forward queries to an external DNS server, skip ahead to [[#Forward all remaining requests]].


=== DNSSEC validation ===
==== Allow local network to use DNS ====
 
===== Using openresolv =====
 
If your network manager supports [[openresolv]], you can [https://roy.marples.name/projects/openresolv/configuration/ configure it] to provide local DNS servers and search domains to Unbound:
 
{{hc|/etc/resolvconf.conf|2=
...
private_interfaces="*"
 
# Write out unbound configuration file
unbound_conf=/etc/unbound/resolvconf.conf
}}
 
Run {{ic|resolvconf -u}} to generate the file.
 
Configure Unbound to read the openresolv's generated file and allow replies with [[Wikipedia:Private network|private IP address ranges]][https://roy.marples.name/projects/openresolv/configuration/resolvers/unbound/]:


You will need the root server trust key anchor file. It is provided by the {{Pkg|dnssec-anchors}} package (already installed as a dependency), however, ''unbound'' needs read and write access to the file. The {{ic|unbound.service}} service accomplishes this by copying the {{ic|/etc/trusted-key.key}} file to {{ic|/etc/unbound/trusted-key.key}}.  You just need to point ''unbound'' to this file:
{{hc|/etc/unbound/unbound.conf|
{{hc|/etc/unbound/unbound.conf|
include: "/etc/unbound/resolvconf.conf"
...
server:
server:
  ...
...
  trust-anchor-file: trusted-key.key
private-domain: "intranet"
  ...
private-domain: "internal"
private-domain: "private"
private-domain: "corp"
private-domain: "home"
private-domain: "lan"
 
unblock-lan-zones: yes
insecure-lan-zones: yes
...
}}
}}


Also make sure that if a general [[#Forwarding queries|forward]] to the Google servers had been in place, then comment them out otherwise DNS queries will fail. DNSSEC validation will be done if the DNS server being queried supports it.
Additionally you may want to disable DNSSEC validation for private DNS namespaces (see [[RFC:6762#appendix-G|RFC 6762 Appendix G]]):


{{Note|Including DNSSEC checking significantly increases DNS lookup times for initial lookups. Once an address is cached locally, then the lookup is virtually instantaneous.}}
{{hc|/etc/unbound/unbound.conf|
...
server:
...
domain-insecure: "intranet"
domain-insecure: "internal"
domain-insecure: "private"
domain-insecure: "corp"
domain-insecure: "home"
domain-insecure: "lan"
...
}}


You can now test if DNSSEC is working, using ''drill'' in {{Pkg|ldns}} (installed as dependency):
===== Exclude local subnets from answers =====


drill sigfail.verteiltesysteme.net # should return rcode: SERVFAIL
Will be useful to exclude local networks from DNS answers because it would protect against [[Wikipedia:DNS rebinding|DNS rebinding]] attacks. By default this feature is not active but you can add any subnet you want in configuration file:
drill sigok.verteiltesysteme.net  # should return rcode: NOERROR


=== Forwarding queries ===
private-address: ''local_subnet/subnet_mask''


If you have a local network which you wish to have DNS queries for and there is a local DNS server that you would like to forward queries to then you should include this line:
You can add all [[Wikipedia:Private network|private and link-local]] subnets by this strings:


  private-address: ''local_subnet/subnet_mask''
  private-address: 10.0.0.0/8
private-address:  172.16.0.0/12
private-address:  192.168.0.0/16
private-address:  169.254.0.0/16
private-address:  fd00::/8
private-address:  fe80::/10


for example:
{{Note|Blocking subnet 127.0.0.0/8 would affect some application as spam or advertising blocklists. Adding ::ffff:0:0/96 stops IPv4-mapped IPv6 addresses from bypassing the filter.}}


private-address: 10.0.0.0/24
Note that ''Unbound'' may have adresses from excluded subnets in answers if they belong to domains from {{ic|private-domain}} or specifed by {{ic|local-data}}, so you need to define {{ic|private-domain}} how described at [[#Using openresolv]] to able query local domains adresses.


{{note|You can use private-address to protect against DNS Rebind attacks. Therefore you may enable RFC1918 networks (10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 169.254.0.0/16 fd00::/8 fe80::/10). Unbound may enable this feature by default in future releases.}}
===== Include local DNS server =====


To include a local DNS server for both forward and reverse local addresses a set of lines similar to these below is necessary with a forward and reverse lookup (choose the IP address of the server providing DNS for the local network accordingly by changing 10.0.0.1 in the lines below):
To include a local DNS server for both forward and reverse local addresses a set of lines similar to these below is necessary with a forward and reverse lookup (choose the IP address of the server providing DNS for the local network accordingly by changing 10.0.0.1 in the lines below):
Line 114: Line 186:
  forward-zone:
  forward-zone:
  name: "mynetwork.com."
  name: "mynetwork.com."
  forward-addr: 10.0.0.1       # Home DNS
  forward-addr: 10.0.0.1


  forward-zone:
  forward-zone:
Line 133: Line 205:
  local-data: "1.0.0.127.in-addr.arpa. 10800 IN PTR localhost."
  local-data: "1.0.0.127.in-addr.arpa. 10800 IN PTR localhost."


Then to use specific servers for default forward zones that are outside of the local machine and outside of the local network (i.e. all other queries will be forwarded to them, and then cached) add this to the configuration file (and in this example the first two addresses are the fast google DNS servers):
==== Forward all remaining requests ====
 
===== Using openresolv =====
 
If your network manager supports [[openresolv]], you can [https://roy.marples.name/projects/openresolv/configuration/ configure it] to provide upstream DNS servers to Unbound.
 
{{hc|/etc/resolvconf.conf|2=
...
# Write out unbound configuration file
unbound_conf=/etc/unbound/resolvconf.conf
}}
 
Run {{ic|resolvconf -u}} to generate the file.
 
Finally configure Unbound to read the openresolv's generated file[https://roy.marples.name/projects/openresolv/configuration/resolvers/unbound/]:
 
include: "/etc/unbound/resolvconf.conf"
 
===== Manually specifying DNS servers =====
 
To use specific servers for default forward zones that are outside of the local machine and outside of the local network add a forward zone with the name {{ic|.}} to the configuration file. In this example, all requests are forwarded to Google's DNS servers:


  forward-zone:
  forward-zone:
Line 139: Line 231:
   forward-addr: 8.8.8.8
   forward-addr: 8.8.8.8
   forward-addr: 8.8.4.4
   forward-addr: 8.8.4.4
  forward-addr: 208.67.222.222
  forward-addr: 208.67.220.220


This will make ''unbound'' use Google and OpenDNS servers as the forward zone for external lookups.
==== Forwarding using DNS over TLS ====


{{Note|OpenDNS strips DNSSEC records from responses. Do not use the above forward zone if you want to enable [[#DNSSEC validation]].}}
To use [[DNS over TLS]], you will need to enable the {{ic|tls-system-cert}} option, allow unbound to forward TLS requests and also specify any number of servers that allow DNS over TLS.
 
For each server you will need to specify the connection port using {{ic|@}} and its domain name with {{ic|#}}. The domain name is required for TLS authentication and also allows setting stub-zones and using the {{ic|unbound-control forward control}} command with domain names. There should not be any spaces in the {{ic|forward-addr}} specification.
 
{{hc|/etc/unbound/unbound.conf|
...
server:
...
tls-system-cert: yes
...
forward-zone:
        name: "."
        forward-tls-upstream: yes
        forward-addr: 1.1.1.1@853#cloudflare-dns.com
}}
 
=== Access control ===
 
You can specify the interfaces to answer queries from by IP address. The default, is to listen on ''localhost''.
 
To listen on all interfaces, use the following:
 
interface: 0.0.0.0
 
To control which systems can access the server by IP address, use the {{ic|access-control}} option:
 
access-control: ''subnet'' ''action''
 
For example:
 
access-control: 192.168.1.0/24 allow
 
''action'' can be one of {{ic|deny}} (drop message), {{ic|refuse}} (polite error reply), {{ic|allow}} (recursive ok), or {{ic|allow_snoop}} (recursive and nonrecursive ok). By default everything is refused except for localhost.


== Usage ==
== Usage ==
Line 150: Line 272:
=== Starting Unbound ===
=== Starting Unbound ===


The ''unbound'' package provides {{ic|unbound.service}}, just [[start]] it. You may want to ''enable'' it so that it starts at boot.
[[Start/enable]] the {{ic|unbound.service}} systemd service.


=== Remotely control Unbound ===
=== Remotely control Unbound ===
Line 166: Line 288:
which will generate a self-signed certificate and private key for the server, as well as the client. These files will be created in the {{ic|/etc/unbound}} directory.
which will generate a self-signed certificate and private key for the server, as well as the client. These files will be created in the {{ic|/etc/unbound}} directory.


2) After that, edit {{ic|/etc/unbound/unbound.conf}} and put the following contents in that. The '''control-enable: yes''' option is necessary, the rest can be adjusted as required.
2) After that, edit {{ic|/etc/unbound/unbound.conf}} and put the following contents in that. The {{ic|control-enable: yes}} option is necessary, the rest can be adjusted as required.


  remote-control:
  remote-control:
Line 205: Line 327:
   # unbound-control reload
   # unbound-control reload


Please refer to {{ic|man 8 unbound-control}} for a detailed look at the operations it supports.
Please refer to {{man|8|unbound-control}} for a detailed look at the operations it supports.


== Adding an authoritative DNS server ==
== Tips and tricks ==


For users who wish to run both a validating, recursive, caching DNS server as well as an authoritative DNS server on a single machine then it may be useful to refer to the wiki page [[nsd]] which gives an example of a configuration for such a system.  Having one server for authoritative DNS queries and a separate DNS server for the validating, recursive, caching DNS functions gives increased security over a single DNS server providing all of these functions. Many users have used bind as a single DNS server, and some help on migration from bind to the combination of running nsd and bind is provided in the [[nsd]] wiki page.
=== Domain blacklisting ===


== WAN facing DNS ==
To blacklist a domain, use {{ic|local-zone: "''domainname''" always_refuse}}.
 
Save the blacklist as a separate file (e.g. {{ic|/etc/unbound/blacklist.conf}}) for ease of management and include it from {{ic|/etc/unbound/unbound.conf}}. For example:
 
{{hc|/etc/unbound/blacklist.conf|
local-zone: "blacklisted.example" always_refuse
local-zone: "anotherblacklisted.example" always_refuse
}}
 
{{hc|/etc/unbound/unbound.conf|
server:
...
  include: /etc/unbound/blacklist.conf
}}
 
{{Tip|
* In order to return some OK statuses on those hosts, you can change the 127.0.0.1 redirection to a server you control and have that server respond with empty 204 replies, see [https://www.shadowandy.net/2014/04/adblocking-nginx-serving-1-pixel-gif-204-content.htm this page]
* To convert a hosts file from another source to the unbound format do: {{bc|$ grep '^0\.0\.0\.0' ''hostsfile'' {{!}} awk '{print "local-zone: \""$2"\" always_refuse"}' > /etc/unbound/blacklist.conf}}
* A list of potential sources for the blacklist can be found in [https://github.com/openwrt/packages/blob/master/net/adblock/files/README.md OpenWrt's adblock package's README].
}}
 
=== Adding an authoritative DNS server ===
 
{{Accuracy|Running two DNS servers is not inherently more secure than running one providing all features.|section=Two DNS servers are not inherently more secure than one}}
 
For users who wish to run both a validating, recursive, caching DNS server as well as an authoritative DNS server on a single machine then it may be useful to refer to the wiki page [[NSD]] which gives an example of a configuration for such a system.  Having one server for authoritative DNS queries and a separate DNS server for the validating, recursive, caching DNS functions gives increased security over a single DNS server providing all of these functions. Many users have used Bind as a single DNS server, and some help on migration from Bind to the combination of running NSD and Bind is provided in the [[NSD]] wiki page.
 
=== WAN facing DNS ===


It is also possible to change the configuration files and interfaces on which the server is listening so that DNS queries from machines outside of the local network can access specific machines within the LAN. This is useful for web and mail servers which are accessible from anywhere, and the same techniques can be employed as has been achieved using bind for many years, in combination with suitable port forwarding on firewall machines to forward incoming requests to the right machine.
It is also possible to change the configuration files and interfaces on which the server is listening so that DNS queries from machines outside of the local network can access specific machines within the LAN. This is useful for web and mail servers which are accessible from anywhere, and the same techniques can be employed as has been achieved using bind for many years, in combination with suitable port forwarding on firewall machines to forward incoming requests to the right machine.


== Issues concerning num-threads ==
=== Roothints systemd timer ===
 
Here is an example systemd service and timer that update {{ic|root.hints}} monthly using the method in [[#Root hints]]:
 
{{hc|1=/etc/systemd/system/roothints.service|2=
[Unit]
Description=Update root hints for unbound
After=network.target
 
[Service]
ExecStart=/usr/bin/curl -o /etc/unbound/root.hints <nowiki>https://www.internic.net/domain/named.cache</nowiki>
}}
 
{{hc|1=/etc/systemd/system/roothints.timer|2=
[Unit]
Description=Run root.hints monthly
 
[Timer]
OnCalendar=monthly
Persistent=true
[Install]
WantedBy=timers.target}}
 
[[Start/enable]] the {{ic|roothints.timer}} systemd timer.
 
=== Keeping DNS cache always up to date ===
 
unbound supports prefetching where cached DNS entries are automatically updated before they expire to keep the cache always up to date. To quote the {{man|5|unbound.conf}} man page, turning it on gives about 10 percent more traffic and load on the machine, but popular items do not expire from the cache. This is particularly useful on mobile links with high RTT.
 
To enable prefetching, add this under the {{ic|server}} section:
 
prefetch: yes
 
== Troubleshooting ==
 
=== Issues concerning num-threads ===


The man page for {{ic|unbound.conf}} mentions:
{{man|5|unbound.conf|outgoing~2}} mentions:


       outgoing-range: <number>
       outgoing-range: <number>
Line 227: Line 412:
         # num-threads: 1
         # num-threads: 1


However it is not possible to arbitrarily increase {{ic|num-threads}} above {{ic|1}} without causing ''unbound'' to start with warnings in the logs about exceeding the number of file descriptors. In reality for most users running on small networks or on a single machine it should be unnecessary to seek performance enhancement by increasing {{ic|num-threads}} above {{ic|1}}. If you do wish to do so then refer to [http://www.unbound.net/documentation/howto_optimise.html official documentation] and the following rule of thumb should work:
However it is not possible to arbitrarily increase {{ic|num-threads}} above {{ic|1}} without causing ''unbound'' to start with warnings in the logs about exceeding the number of file descriptors. In reality for most users running on small networks or on a single machine it should be unnecessary to seek performance enhancement by increasing {{ic|num-threads}} above {{ic|1}}. If you do wish to do so then refer to [https://nlnetlabs.nl/documentation/unbound/howto-optimise/ official documentation] and the following rule of thumb should work:


:''Set {{ic|num-threads}} equal to the number of CPU cores on the system. E.g. for 4 CPUs with 2 cores each, use 8.''
:Set {{ic|num-threads}} equal to the number of CPU cores on the system. E.g. for 4 CPUs with 2 cores each, use 8.


Set the {{ic|outgoing-range}} to as large a value as possible, see the sections in the referred web page above on how to overcome the limit of {{ic|1024}} in total. This services more clients at a time. With 1 core, try {{ic|950}}. With 2 cores, try {{ic|450}}. With 4 cores try {{ic|200}}. The {{ic|num-queries-per-thread}} is best set at half the number of the {{ic|outgoing-range}}.  
Set the {{ic|outgoing-range}} to as large a value as possible, see the sections in the referred web page above on how to overcome the limit of {{ic|1024}} in total. This services more clients at a time. With 1 core, try {{ic|950}}. With 2 cores, try {{ic|450}}. With 4 cores try {{ic|200}}. The {{ic|num-queries-per-thread}} is best set at half the number of the {{ic|outgoing-range}}.  

Latest revision as of 11:47, 3 March 2024

Unbound is a validating, recursive, and caching DNS resolver. According to Wikipedia:

Unbound has supplanted the Berkeley Internet Name Domain (BIND) as the default, base-system name server in several open source projects, where it is perceived as smaller, more modern, and more secure for most applications.

Installation

Install the unbound package.

Additionally, the expat package is required for #DNSSEC validation.

Configuration

A default configuration is already included at /etc/unbound/unbound.conf. The following sections highlight different settings for the configuration file. See unbound.conf(5) for other settings and more details.

Unless otherwise specified, any options listed in this section are to be placed under the server section in the configuration like so:

/etc/unbound/unbound.conf
server:
  ...
  setting: value
  ...

Local DNS server

If you want to use unbound as your local DNS server, set your nameserver to the loopback addresses ::1 and 127.0.0.1 in /etc/resolv.conf:

/etc/resolv.conf
nameserver ::1
nameserver 127.0.0.1
options trust-ad

Make sure to protect /etc/resolv.conf from modification as described in Domain name resolution#Overwriting of /etc/resolv.conf.

Tip: A simple way to do this is to install openresolv and configure /etc/resolvconf.conf:
/etc/resolvconf.conf
name_servers="::1 127.0.0.1"
resolv_conf_options="trust-ad"

Then run resolvconf -u to generate /etc/resolv.conf.

See Domain name resolution#Lookup utilities on how to test your settings.

Check specifically that the server being used is ::1 or 127.0.0.1 after making permanent changes to resolv.conf.

You can now setup unbound such that it is #Forwarding queries, perhaps all queries, to the DNS servers of your choice.

Root hints

For recursively querying a host that is not cached as an address, the resolver needs to start at the top of the server tree and query the root servers, to know where to go for the top level domain for the address being queried. Unbound comes with default builtin hints. Therefore, if the package is updated regularly, no manual intervention is required. Otherwise, it is good practice to use a root-hints file since the builtin hints may become outdated.

First point unbound to the root.hints file:

root-hints: root.hints

Then, put a root hints file into the unbound configuration directory. The simplest way to do this is to run the command:

# curl --output /etc/unbound/root.hints https://www.internic.net/domain/named.cache

When actually using this file, and not the builtin hints, it is a good idea to update root.hints every six months or so in order to make sure the list of root servers is up to date. This can be done manually or by using a systemd timer. See #Roothints systemd timer for an example.

DNSSEC validation

To use DNSSEC validation, the following setting for the server trust anchor should be under server::

/etc/unbound/unbound.conf
  trust-anchor-file: trusted-key.key

This setting is done by default[1][dead link 2024-03-03 ⓘ]. /etc/unbound/trusted-key.key is copied from /etc/trusted-key.key, which is provided by the dnssec-anchors dependency, whose PKGBUILD generates the file with unbound-anchor(8).

DNSSEC validation will only be done if the DNS server being queried supports it. If general #Forwarding queries have been set to DNS servers that do not support DNSSEC, their answers, whatever they are, should be considered insecure since no DNSSEC validation could be preformed.

Note: Including DNSSEC checking significantly increases DNS lookup times for initial lookups before the address is cached.

Testing validation

To test if DNSSEC is working, after starting unbound.service, do:

$ unbound-host -C /etc/unbound/unbound.conf -v go.dnscheck.tools

The response should be the ip address with the word (secure) next to it.

$ unbound-host -C /etc/unbound/unbound.conf -v badsig.go.dnscheck.tools

Here the response should include (BOGUS (security failure)).

Additionally you can use drill to test the resolver as follows:

$ drill badsig.go.dnscheck.tools
$ drill go.dnscheck.tools

The first command should give an rcode of SERVFAIL. The second should give an rcode of NOERROR.

Forwarding queries

If you only want to forward queries to an external DNS server, skip ahead to #Forward all remaining requests.

Allow local network to use DNS

Using openresolv

If your network manager supports openresolv, you can configure it to provide local DNS servers and search domains to Unbound:

/etc/resolvconf.conf
...
private_interfaces="*"

# Write out unbound configuration file
unbound_conf=/etc/unbound/resolvconf.conf

Run resolvconf -u to generate the file.

Configure Unbound to read the openresolv's generated file and allow replies with private IP address ranges[2]:

/etc/unbound/unbound.conf
include: "/etc/unbound/resolvconf.conf"
...
server:
...
	private-domain: "intranet"
	private-domain: "internal"
	private-domain: "private"
	private-domain: "corp"
	private-domain: "home"
	private-domain: "lan"

	unblock-lan-zones: yes
	insecure-lan-zones: yes
...

Additionally you may want to disable DNSSEC validation for private DNS namespaces (see RFC 6762 Appendix G):

/etc/unbound/unbound.conf
...
server:
...
	domain-insecure: "intranet"
	domain-insecure: "internal"
	domain-insecure: "private"
	domain-insecure: "corp"
	domain-insecure: "home"
	domain-insecure: "lan"
...
Exclude local subnets from answers

Will be useful to exclude local networks from DNS answers because it would protect against DNS rebinding attacks. By default this feature is not active but you can add any subnet you want in configuration file:

private-address: local_subnet/subnet_mask

You can add all private and link-local subnets by this strings:

private-address:  10.0.0.0/8
private-address:  172.16.0.0/12
private-address:  192.168.0.0/16
private-address:  169.254.0.0/16
private-address:  fd00::/8
private-address:  fe80::/10
Note: Blocking subnet 127.0.0.0/8 would affect some application as spam or advertising blocklists. Adding ::ffff:0:0/96 stops IPv4-mapped IPv6 addresses from bypassing the filter.

Note that Unbound may have adresses from excluded subnets in answers if they belong to domains from private-domain or specifed by local-data, so you need to define private-domain how described at #Using openresolv to able query local domains adresses.

Include local DNS server

To include a local DNS server for both forward and reverse local addresses a set of lines similar to these below is necessary with a forward and reverse lookup (choose the IP address of the server providing DNS for the local network accordingly by changing 10.0.0.1 in the lines below):

local-zone: "10.in-addr.arpa." transparent

This line above is important to get the reverse lookup to work correctly.

forward-zone:
name: "mynetwork.com."
forward-addr: 10.0.0.1
forward-zone:
name: "10.in-addr.arpa."
forward-addr: 10.0.0.1
Note: There is a difference between forward zones and stub zones - stub zones will only work when connected to an authoritative DNS server directly. This would work for lookups from a BIND DNS server if it is providing authoritative DNS - but if you are referring queries to an unbound server in which internal lookups are forwarded on to another DNS server, then defining the referral as a stub zone in the machine here will not work. In that case it is necessary to define a forward zone as above, since forward zones can have daisy chain lookups onward to other DNS servers. i.e. forward zones can refer queries to recursive DNS servers. This distinction is important as you do not get any error messages indicating what the problem is if you use a stub zone inappropriately.

You can set up the localhost forward and reverse lookups with the following lines:

local-zone: "localhost." static
local-data: "localhost. 10800 IN NS localhost."
local-data: "localhost. 10800 IN SOA localhost. nobody.invalid. 1 3600 1200 604800 10800"
local-data: "localhost. 10800 IN A 127.0.0.1"
local-zone: "127.in-addr.arpa." static
local-data: "127.in-addr.arpa. 10800 IN NS localhost."
local-data: "127.in-addr.arpa. 10800 IN SOA localhost. nobody.invalid. 2 3600 1200 604800 10800"
local-data: "1.0.0.127.in-addr.arpa. 10800 IN PTR localhost."

Forward all remaining requests

Using openresolv

If your network manager supports openresolv, you can configure it to provide upstream DNS servers to Unbound.

/etc/resolvconf.conf
...
# Write out unbound configuration file
unbound_conf=/etc/unbound/resolvconf.conf

Run resolvconf -u to generate the file.

Finally configure Unbound to read the openresolv's generated file[3]:

include: "/etc/unbound/resolvconf.conf"
Manually specifying DNS servers

To use specific servers for default forward zones that are outside of the local machine and outside of the local network add a forward zone with the name . to the configuration file. In this example, all requests are forwarded to Google's DNS servers:

forward-zone:
  name: "."
  forward-addr: 8.8.8.8
  forward-addr: 8.8.4.4

Forwarding using DNS over TLS

To use DNS over TLS, you will need to enable the tls-system-cert option, allow unbound to forward TLS requests and also specify any number of servers that allow DNS over TLS.

For each server you will need to specify the connection port using @ and its domain name with #. The domain name is required for TLS authentication and also allows setting stub-zones and using the unbound-control forward control command with domain names. There should not be any spaces in the forward-addr specification.

/etc/unbound/unbound.conf
...
server:
...
	tls-system-cert: yes
...
forward-zone:
        name: "."
        forward-tls-upstream: yes
        forward-addr: 1.1.1.1@853#cloudflare-dns.com

Access control

You can specify the interfaces to answer queries from by IP address. The default, is to listen on localhost.

To listen on all interfaces, use the following:

interface: 0.0.0.0

To control which systems can access the server by IP address, use the access-control option:

access-control: subnet action

For example:

access-control: 192.168.1.0/24 allow

action can be one of deny (drop message), refuse (polite error reply), allow (recursive ok), or allow_snoop (recursive and nonrecursive ok). By default everything is refused except for localhost.

Usage

Starting Unbound

Start/enable the unbound.service systemd service.

Remotely control Unbound

unbound ships with the unbound-control utility which enables us to remotely administer the unbound server. It is similar to the pdnsd-ctl command of pdnsd.

Setting up unbound-control

Before you can start using it, the following steps need to be performed:

1) Firstly, you need to run the following command

# unbound-control-setup

which will generate a self-signed certificate and private key for the server, as well as the client. These files will be created in the /etc/unbound directory.

2) After that, edit /etc/unbound/unbound.conf and put the following contents in that. The control-enable: yes option is necessary, the rest can be adjusted as required.

remote-control:
    # Enable remote control with unbound-control(8) here.
    # set up the keys and certificates with unbound-control-setup.
    control-enable: yes
   
    # what interfaces are listened to for remote control.
    # give 0.0.0.0 and ::0 to listen to all interfaces.
    control-interface: 127.0.0.1
   
    # port number for remote control operations.
    control-port: 8953
   
    # unbound server key file.
    server-key-file: "/etc/unbound/unbound_server.key"
   
    # unbound server certificate file.
    server-cert-file: "/etc/unbound/unbound_server.pem"
   
    # unbound-control key file.
    control-key-file: "/etc/unbound/unbound_control.key"
   
    # unbound-control certificate file.
    control-cert-file: "/etc/unbound/unbound_control.pem"

Using unbound-control

Some of the commands that can be used with unbound-control are:

  • print statistics without resetting them
 # unbound-control stats_noreset
  • dump cache to stdout
 # unbound-control dump_cache
  • flush cache and reload configuration
 # unbound-control reload

Please refer to unbound-control(8) for a detailed look at the operations it supports.

Tips and tricks

Domain blacklisting

To blacklist a domain, use local-zone: "domainname" always_refuse.

Save the blacklist as a separate file (e.g. /etc/unbound/blacklist.conf) for ease of management and include it from /etc/unbound/unbound.conf. For example:

/etc/unbound/blacklist.conf
local-zone: "blacklisted.example" always_refuse
local-zone: "anotherblacklisted.example" always_refuse
/etc/unbound/unbound.conf
server:
...
  include: /etc/unbound/blacklist.conf
Tip:
  • In order to return some OK statuses on those hosts, you can change the 127.0.0.1 redirection to a server you control and have that server respond with empty 204 replies, see this page
  • To convert a hosts file from another source to the unbound format do:
    $ grep '^0\.0\.0\.0' hostsfile | awk '{print "local-zone: \""$2"\" always_refuse"}' > /etc/unbound/blacklist.conf
  • A list of potential sources for the blacklist can be found in OpenWrt's adblock package's README.

Adding an authoritative DNS server

The factual accuracy of this article or section is disputed.

Reason: Running two DNS servers is not inherently more secure than running one providing all features. (Discuss in Talk:Unbound#Two DNS servers are not inherently more secure than one)

For users who wish to run both a validating, recursive, caching DNS server as well as an authoritative DNS server on a single machine then it may be useful to refer to the wiki page NSD which gives an example of a configuration for such a system. Having one server for authoritative DNS queries and a separate DNS server for the validating, recursive, caching DNS functions gives increased security over a single DNS server providing all of these functions. Many users have used Bind as a single DNS server, and some help on migration from Bind to the combination of running NSD and Bind is provided in the NSD wiki page.

WAN facing DNS

It is also possible to change the configuration files and interfaces on which the server is listening so that DNS queries from machines outside of the local network can access specific machines within the LAN. This is useful for web and mail servers which are accessible from anywhere, and the same techniques can be employed as has been achieved using bind for many years, in combination with suitable port forwarding on firewall machines to forward incoming requests to the right machine.

Roothints systemd timer

Here is an example systemd service and timer that update root.hints monthly using the method in #Root hints:

/etc/systemd/system/roothints.service
[Unit]
Description=Update root hints for unbound
After=network.target

[Service]
ExecStart=/usr/bin/curl -o /etc/unbound/root.hints https://www.internic.net/domain/named.cache
/etc/systemd/system/roothints.timer
[Unit]
Description=Run root.hints monthly

[Timer]
OnCalendar=monthly
Persistent=true
 
[Install]
WantedBy=timers.target

Start/enable the roothints.timer systemd timer.

Keeping DNS cache always up to date

unbound supports prefetching where cached DNS entries are automatically updated before they expire to keep the cache always up to date. To quote the unbound.conf(5) man page, turning it on gives about 10 percent more traffic and load on the machine, but popular items do not expire from the cache. This is particularly useful on mobile links with high RTT.

To enable prefetching, add this under the server section:

prefetch: yes

Troubleshooting

Issues concerning num-threads

unbound.conf(5) § outgoing~2 mentions:

     outgoing-range: <number>
             Number of ports to open. This number of file  descriptors  can  be  opened  per thread.

and some sources suggest that the num-threads parameter should be set to the number of cpu cores. The sample unbound.conf.example file merely has:

       # number of threads to create. 1 disables threading.
       # num-threads: 1

However it is not possible to arbitrarily increase num-threads above 1 without causing unbound to start with warnings in the logs about exceeding the number of file descriptors. 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. If you do wish to do so then refer to official documentation and the following rule of thumb should work:

Set num-threads equal to the number of CPU cores on the system. E.g. for 4 CPUs with 2 cores each, use 8.

Set the outgoing-range to as large a value as possible, see the sections in the referred web page above on how to overcome the limit of 1024 in total. This services more clients at a time. With 1 core, try 950. With 2 cores, try 450. With 4 cores try 200. The num-queries-per-thread is best set at half the number of the outgoing-range.

Because of the limit on outgoing-range thus also limits num-queries-per-thread, it is better to compile with libevent, so that there is no 1024 limit on outgoing-range. If you need to compile this way for a heavy duty DNS server then you will need to compile the programme from source instead of using the unbound package.

See also