Set Up Local DNS Resolver on Ubuntu 24.04 with BIND9
This tutorial will be showing you how to set up a local DNS resolver on Ubuntu 24.04 with the widely-used BIND9 DNS software. A DNS resolver is known by many names, some of which are listed below. They all refer to the same thing.
- full resolver (in contrast to stub resolver)
- DNS recursor
- recursive DNS server
- recursive resolver
Also, be aware that A DNS server can also be called a name server. Examples of DNS resolvers are 8.8.8.8
(Google public DNS server) and 1.1.1.1
(Cloudflare public DNS server). The operating system on your PC also has a resolver, which is called stub resolver due to its limited capability. A stub resolver is a small DNS client on the end user’s computer that receives DNS requests from applications such as Firefox and forward requests to a recursive resolver. Almost every resolver can cache DNS response to improve performance, so they are also called caching DNS server.
Why Run Your Own Local DNS Resolver
Normally, your computer or router uses your ISP’s DNS resolver to query DNS names, so why run your own DNS resolver?
- It can speed up DNS lookups, because the local DNS resolver only listens to your DNS requests and does not answer other people’s DNS requests, so you have a much higher chance of getting DNS answers directly from the cache on the resolver. Also, the network latency between your computer and DNS resolver is eliminated (almost zero), so DNS queries can be sent to root DNS servers more quickly.
- If you run a mail server and use DNS blacklists (DNSBL) to block spam, then you should run your own DNS resolver, because some DNS blacklists such as URIBL refuse requests from public DNS resolvers.
- If you run your own VPN server on a VPS (Virtual Private Server), it’s also a good practice to install a DNS resolver on the same VPS.
- You may also want to run your own DNS resolver if you don’t like your Internet browsing history being stored on a third-party server.
If you own a website and want your own DNS server to handle name resolution for your domain name instead of using your domain registrar’s DNS server, then you will need to set up an authoritative DNS server, which is different from a DNS resolver. BIND can act as an authoritative DNS server and a DNS resolver at the same time, but it’s a good practice to separate the two roles on different boxes.
This tutorial shows how to set up a local DNS resolver and because it will be used on localhost/local network, no encryption (DNS over TLS or DNS over HTTPS) is needed. Setting up a DoT resolver or DoH server will be discussed in a future article.
Hint: Local
doesn’t mean your home computer. Rather, it means the DNS resolver runs on the same box as the DNS client. You can install BIND DNS resolver on your home computer. It’s local to your home computer. You can install BIND DNS resolver on a cloud server, and it’s local to the cloud server.
Set Up a Local DNS Resolver on Ubuntu 24.04 with BIND9
BIND (Berkeley Internet Name Domain) is an open-source DNS server software widely used on Unix/Linux due to it’s stability and high quality. It’s originally developed by UC Berkeley, and later in 1994 its development was moved to Internet Systems Consortium, Inc (ISC).
Run the following command to install BIND 9 on Ubuntu 24.04 from the default repository. BIND 9 is the current version and BIND 10 is a dead project.
sudo apt update sudo apt install bind9 bind9utils bind9-doc bind9-host dnsutils
Check version.
named -v
Sample output:
BIND 9.18.21-0ubuntu1-Ubuntu (Extended Support Version) <id:>
To check the version number and build options, run
named -V
By default, BIND automatically starts after installation. You check its status with:
systemctl status named
If it’s not running, then start it with:
sudo systemctl start named
And enable auto start at boot time:
sudo systemctl enable named
The BIND server will run as the bind
user, which is created during installation, and listens on TCP and UDP port 53, as can be seen by running the following command:
sudo ss -lnptu | grep named
Usually DNS queries are sent to the UDP port 53. The TCP port 53 is for response sizes larger than 512 bytes.
The BIND daemon is called named. (A daemon is a piece of software that runs in the background.) The named
binary is installed by the bind9
package and there’s another important binary: rndc
, the remote name daemon controller, which is installed by the bind9utils
package. The rndc
binary is used to reload/stop and control other aspects of the BIND daemon. Communication is done over TCP port 953.
For example, we can check the status of the BIND name server.
sudo rndc status
Configurations for a Local DNS Resolver
/etc/bind/
is the directory that contains configurations for BIND.
- named.conf: the primary config file which includes configs of three other files.
- db.root: the root hints file used by DNS resolvers to query root DNS servers. There are 13 groups of root DNS servers, from
a.root-servers.net
tom.root-servers.net
. - db.127: localhost IPv4 reverse mapping zone file.
- db.local: localhost forward IPv4 and IPv6 mapping zone file.
- db.empty: an empty zone file
Out of the box, the BIND9 server on Ubuntu provides recursive service for localhost and local network clients only. Outside queries will be denied. So you don’t have to edit the configuration files. To get you familiar with BIND 9 configurations, I will show you how to enable recursion service anyway.
The main BIND configuration file /etc/bind/named.conf
sources the settings from 3 other files.
- /etc/bind/named.conf.options
- /etc/bind/named.conf.local
- /etc/bind/named.conf.default-zones
To enable recursion service, edit the first file.
sudo nano /etc/bind/named.conf.options
In the options
clause, add the following lines. Replace IP addresses in the allow-recursion
statement with your own local network addresses.
// hide version number from clients for security reasons. version "not currently available"; // optional - BIND default behavior is recursion recursion yes; // provide recursion service to trusted clients only allow-recursion { 127.0.0.1; 192.168.0.0/24; 10.10.10.0/24; }; // enable the query log querylog yes;
Save and close the file. Then test the config file syntax.
sudo named-checkconf
If the test is successful (indicated by a silent output), then restart BIND9.
sudo systemctl restart named
If you have a firewall running on the BIND server, then you need to open port 53 to allow LAN clients to send DNS queries.
sudo ufw allow in from 192.168.0.0/24 to any port 53
This will open TCP and UDP port 53 to the private network 192.168.0.0/24. Then from another computer in the same LAN, we can run the following command to query the A record of google.com. Replace 192.168.0.102 with the IP address of your BIND resolver.
dig A google.com @192.168.0.102
Now on the BIND resolver, check the query log with the following command.
sudo journalctl -eu named
This will show the latest log message of the bind9 service unit. I can found the following line in the log, which indicates that a DNS query for google.com’s A record has been received from port 57806 of 192.168.0.103.
named[1162]: client @0x7f4d2406f0f0 192.168.0.103#57806 (google.com): query: google.com IN A +E(0)K (192.168.0.102)
Setting the Default DNS Resolver on Ubuntu 24.04 Server
Systemd-resolved provides the stub resolver on Ubuntu 24.04. As mentioned in the beginning of this article, a stub resolver is a small DNS client on the end-user’s computer that receives DNS requests from applications such as Firefox and forward requests to a recursive resolver.
The default recursive resolver can be seen with this command.
resolvectl status
As you can see, BIND isn’t the default. If you run the following command on the BIND server,
dig A facebook.com
This DNS query can’t be found in BIND log. Instead, you need to explicitly tell dig to use BIND.
dig A facebook.com @127.0.0.1
To set BIND as the default resolver, open the systemd-resolved configuration file.
sudo nano /etc/systemd/resolved.conf
In the [Resolve]
section, add the following line. This will set a global DNS server for your server.
DNS=127.0.0.1
Save and close the file. Then restart systemd-resolved service.
sudo systemctl restart systemd-resolved
Now run the following command to check the default DNS resolver.
resolvectl status
Now perform a DNS query without specifying 127.0.0.1
.
dig A facebook.com
You will see the DNS query in BIND log, which means BIND is now the default recursive resolver. If you don’t see any queries in the BIND log, you might need to configure per-link DNS server.
Configure Per-Link DNS Server on Ubuntu 24.04
You can also configure per-link DNS server, which will override the global DNS server. There are two ways to configure per-link DNS servers:
- via systemd-resolved
- via netplan
systemd-resolved
List files under /etc/systemd/network/
directory.
ls /etc/systemd/network/
Sample output:
05-eth0.network 99-default.link
As you can see, I have two link configuration files. The 05-eth0.network
file is for my main network interface, so I edit this file.
sudo nano /etc/systemd/network/05-eth0.network
Your filename might be different. If there are no files under this directory, then your per-link DNS configuration is not controlled by systemd-resolved
.
Comment out the default DNS and Domain entry, and add your own DNS entry.
DNS=127.0.0.1
Save and close the file. Then restart systemd-resolved
and systemd-networkd
service.
sudo systemctl restart systemd-resolved systemd-networkd
netplan
Some Ubuntu servers might be using netplan to configure per-link networking. In this case, you need to configure DNS server in the .yaml
file under /etc/netplan/
directory. List files in this directory.
ls /etc/netplan/
Sample output:
01-netcfg.yaml
So I edit this file.
sudo nano /etc/netplan/01-netcfg.yaml
Set the DNS server address in the nameservers
section.
nameservers: search: [ invalid ] addresses: - 127.0.0.1
Save and close the file. Then apply the change.
sudo netplan apply
Note: If you see the following error message, then netplan can’t process the configuration file.
Invalid YAML at /etc/netplan/01-netcfg.yaml inconsistent indentation
You should fix the inconsistent indentation and run sudo netplan apply
command again.
Setting Default DNS Resolver on Client Computers
On Ubuntu desktop, you can follow the above instructions to set the default DNS resolver, but remember to replace 127.0.0.1 with the IP address of BIND server. The steps of setting default DNS resolver on MacOS and Windows can be found on the Internet.
How to Disable IPv6 in BIND
If you don’t use IPv6 in your network, then it’s a good idea to turn off IPv6 in BIND, otherwise there will be a lot of errors about IPv6 in BIND log like below.
network unreachable resolving 'mirrors.fedoraproject.org/A/IN': 2001:4178:2:1269:dead:beef:cafe:fed5#53 network unreachable resolving 'mirrors.fedoraproject.org/AAAA/IN': 2001:4178:2:1269:dead:beef:cafe:fed5#53 network unreachable resolving 'mirrors.fedoraproject.org/A/IN': 2610:28:3090:3001:dead:beef:cafe:fed5#53 network unreachable resolving 'mirrors.fedoraproject.org/AAAA/IN': 2610:28:3090:3001:dead:beef:cafe:fed5#53
To disable IPv6 in BIND on Ubuntu, simply open the /etc/default/bind9 file
sudo nano /etc/default/named
Add “-4” to the OPTIONS.
OPTIONS="-u bind -4"
Save and close the file. Then restart BIND and you are done.
sudo systemctl restart named
BIND SERVFAIL
If your BIND resolver can’t answer DNS queries (SERVFAIL), and you see the following line in the BIND log.
dnssec: warning: managed-keys-zone: Unable to fetch DNSKEY set '.': timed out
It’s probably because your server doesn’t have a working IPv6 connectivity. This happened to one of my servers. I thought IPv6 connectivity is working as usual, but it’s suddenly broken for reasons I didn’t know. Once I disabled IPv6 in BIND, DNS resolution is working again.
BIND max-cache-size
BIND can cache DNS results on the server to speed up DNS lookup for clients. BIND assumes you are running a dedicated DNS resolver, i.e, no other web services are running on the same host, so the default cache size (defined by max-cache-size
) is set to 90% of the total RAM to achieve best performance. You can see a line like below in the BIND log (sudo journalctl -eu bind9
) when BIND starts.
none:100: 'max-cache-size 90%' - setting to 7165MB (out of 7961MB)
Note that BIND will not use 90% of your RAM immediately. If there are only a few DNS requests, BIND uses only a small amount of RAM, because there’s not many DNS results to cache. If there are lots of DNS requests, then it will use lots of RAM to store the DNS cache.
If your RAM is limited, you might not want BIND to use 90% of your RAM for cache. Edit the BIND configuration file /etc/bind/named.conf.options
.
sudo nano /etc/bind/named.conf.options
Add the following directive in the options
clause. Change 50% to your preferred value.
max-cache-size 50%;
Restart BIND for the change to take effect.
sudo systemctl restart named
Conclusion
I hope this tutorial helped you set up a local DNS resolver on Ubuntu 24.04 with BIND9. As always, if you found this post useful, then subscribe to our free newsletter to get more tips and tricks. Take care 🙂
THANKS (I REQUESTED THIS)
This article is about running BIND as a DNS resolver, but I thought you wanted to use BIND as an authoritative DNS server?
Yes sorry, I just seen BIND and thought it was the one I was looking for lol
The article for BIND authoritative DNS server is now published. https://www.linuxbabe.com/ubuntu/set-up-authoritative-dns-server-ubuntu-18-04-bind9
please, check where says “sudo apt install resovlconf” instead “sudo apt install resolvconf”, at ubuntu 16
Thanks for pointing it out. The typo is now corrected.
This seems like a strange situation to me, but please pardon my limited knowledge.
After editing /etc/systemd/resolved.conf to put in my local network for the DNS entry (i did un-“comment” that line first) and then running ‘systemd-resolve –status’. I get the same DNS servers listed… but when I do a dig command without specifying where to resolve, the activity shows up in my ‘sudo journalctl -eu bind9’ command
just um… realized that i’m not very smart… everything worked fine, i was just looking at the wrong line in the readout of the journalctl command… it worked perfectly and you guys are awesome!! let me just say as somebody that is just learning.. your tutorials have been indispensable! thank you!
Hello,
I was doing fine until this command and the drive is empty?
sudo nano /etc/systemd/network/05-eth0.network
I don’t think I missed a step?
Any ideas?
List files in
/etc/systemd/network/
directory.Sample output:
As you can see, I have two link configuration files. The 05-eth0.network file is for my main network interface, so I edit this file.
Your filename might be different. If there are no files under this directory, that means all your links (aka network interfaces) are using the global network configuration, and you don’t need to configure per-link DNS server.
Really – sorry – as I was re-reading – I have just seen my error…. About to leave another note!
Such wonderful tutorial! Unfortunately I ran into a problem. After adding ‘DNS=127.0.0.1’ to /etc/systemd/resolved.conf as shown, and restarting the systemd-resolved service, the `systemd-resolve –status` output starts with what you show under Global (although at the end there are STILL the same ‘DNS Servers:’ shown for Link 2 (eth0). But when I do subsequently `dig A facebook.com` there is no (extra) output from that for `sudo journalctl -eu bind9`. It still isn’t using my local DNS resolver. How to fix this?
Have you tried setting DNS resolver for the eth0 link, as described in the “Configure Per-Link DNS Server” section?
As `/etc/systemd/network` is empty for me, I did not try this.
However, I am pretty sure that your `/etc/resolv.conf` also points to `/run/systemd/resolve/resolv.conf` does it not? I really think that is a requirement. As can be read in the manual page systemd-resolved(8) (http://manpages.ubuntu.com/manpages/bionic/man8/systemd-resolved.service.8.html#/etc/resolv.conf) this is a manual tweak that you pick. Using a symlink to `/run/systemd/resolve/stub-resolv.conf` leads to, as described in the man page (“This file lists the 127.0.0.53 DNS stub (see above) as the only DNS server.”) using the stub service that listens on 127.0.0.53. It is possible that that in turn uses the per-link configuration, I don’t know.
`systemd-resolve –status` gives:
Note that the latter two dns servers are (probably) the result of using DHCP, which by default fills this in. You can turn that off, but I kinda like having them as fall back.
/run/systemd/resolve/stub-resolv.conf reads:
/run/systemd/resolve/resolv.conf reads:
Thank you for your wonderful collection of HOWTO’s! It has greatly helped me.
I am currently trying to move my deluge setup from one machine to another (I might add comments there too later on, in an attempt to perhaps improve it).
There are two ways to configure per-link DNS server. If you don’t see any files in
/etc/sytemd/network/
directory, then check/etc/netplan/
directory. I just rewrote the “Configure Per-Link DNS Server” section to make it clear to follow and understand.No, my
/etc/resolv.conf
points to/run/systemd/resolve/stub-resolv.conf
, not/run/systemd/resolve/resolv.conf
.I basically found the answer is: https://askubuntu.com/a/1150294/493223
I searched high and low if there is a better way than to manually change that symlink, but it seems necessary. Mine was pointing to: /etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf
This must have been set by some application no? Oh well.
My `/etc/netplan` is empty too. I believe I do not have a per-link configuration set up at all (though I am using systemd-resolved, for sure). I think that what happens is that because I’m using DHCP – it is THAT which configures my eth0 (per link thus) to have those nameservers configured.
As a result I can not use `/run/systemd/resolve/stub-resolv.conf`. There are two solutions for that: either change the symlink `/etc/resolv.conf` or turn off configuration of DNS by the DHCP client. It should be possible to do this by either uncommenting `prepend domain-name-servers 127.0.0.1;` or removing `domain-name-servers` from the `request` line in `/etc/dhcp/dhclient.conf` altogether.
I want to rate this article, but the link to rate it is missing. Great article, thanks. I just discovered linuxbabe today and joined mailing list.
My mail server on VPS Vult, but Vultr using DHCP. How to “Set the DNS server address in the nameservers section.” Xiao?
Thank you.
is this correct?
Yes. It’s correct.
After restart my server, my server (nginx) can’t access anymore. I try this:
I got the error:
Can you help me Xiao? Thanks
Sorry XIao, now everything work fine 😀
Thanks a lot for this tuto.
To disable Ipv6 on Ubuntu 20.04, the file to use is /etc/default/named rather than bind9
To install and configure BIND DNS resolver on Ubuntu 20.04, follow the tutorial below.
https://www.linuxbabe.com/ubuntu/set-up-local-dns-resolver-ubuntu-20-04-bind9
Sometimes, this doesn’t resolve some domain like heroku.com or AWS. Switching the DNS server to Cloudflare works. But other times, the issue resolves itself.