Set Up Local DNS Resolver on Ubuntu 22.04/20.04 with BIND9

This tutorial will be showing you how to set up a local DNS resolver on Ubuntu 22.04/20.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 resolver are (Google public DNS server) and (Cloudflare public DNS server). The OS on your computer also has a resolver, although it’s 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.

Set Up Local DNS Resolver on Ubuntu 20.04 with BIND9

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 a local 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. 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 resolver 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 Local DNS Resolver on Ubuntu 22.04/20.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 22.04/20.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-dnsutils bind9-doc bind9-host

Check version.

named -v

Sample output:

BIND 9.16.1-Ubuntu (Stable Release) <id:d497c32>

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 netstat -lnptu | grep named

ubuntu 20.04 bind9 setup

Usually DNS queries are sent to the UDP port 53. The TCP port 53 is for responses 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

rndc the remote name daemon controller ubuntu 20.04

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.127: localhost IPv4 reverse mapping zone file.
  • db.local: localhost forward IPv4 and IPv6 mapping zone file.
  • db.empty: an empty zone file

The bind9 package on Ubuntu 22.04/20.04 doesn’t ship with a db.root file, it now uses the root hints file at /usr/share/dns/root.hints. The root hints file is used by DNS resolvers to query root DNS servers. There are 13 groups of root DNS servers, from to

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 {;;; };

 // enable the query log
 querylog yes;

enable-recursion-service-in-bind9-ubuntu 20.04

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 UFW 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 to any port 53

This will open TCP and UDP port 53 to the private network Then from another computer in the same LAN, we can run the following command to query the A record of Replace with the IP address of your BIND resolver.

dig A @

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 found the following line in the log, which indicates that a DNS query for’s A record has been received from port 57806 of

named[1162]: client @0x7f4d2406f0f0 ( query: IN A +E(0)K (

Setting the Default DNS Resolver on Ubuntu 22.04/20.04 Server

Systemd-resolved provides the stub resolver on Ubuntu 22.04/20.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.

systemd-resolve --status


Hint: If the above command doesn’t quit immediately, you can make it quit by pressing the Q key.

As you can see, BIND isn’t the default. If you run the following command on the BIND server,

dig A

This DNS query can’t be found in BIND log. Instead, you need to explicitly tell dig to use BIND.

dig A @

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.


bind dns resolver

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.

systemd-resolve --status


Now perform a DNS query without specifying

dig A

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 22.04/20.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


List files under /etc/systemd/network/ directory.

ls /etc/systemd/network/

Sample output:

As you can see, I have two link configuration files. The file is for my main network interface, so I edit this file.

sudo nano /etc/systemd/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.


Save and close the file. Then restart systemd-resolved and systemd-networkd service.

sudo systemctl restart systemd-resolved systemd-networkd


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:


So I edit this file.

sudo nano /etc/netplan/01-netcfg.yaml

Set the DNS server address in the nameservers section.

        search: [ invalid ]

Configure Per-Link DNS Server on Ubuntu

You can specify multiple DNS resolvers like below, which can reduce the chance of DNS failure.

        search: [ invalid ]

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.


Check the content of /etc/resolv.conf.

cat /etc/resolv.conf

resolvconf set default dns resolver Ubuntu 20.04

As you can see, (BIND) is default DNS resolver. If you see a different value, that means BIND is still not your default DNS resolver. You can use the resolveconf utility to set BIND as default resolver.

Install the resolvconf package

sudo apt install resolvconf

Then start the named-resolvconf service.

sudo systemctl start named-resolvconf.service

Enable auto-start at boot time.

sudo systemctl enable named-resolvconf.service

Now check the /etc/resolv.conf file again. BIND should be the default DNS resolver on your Ubuntu server now.

cat /etc/resolv.conf

Note that some hosting providers like Linode may use a network helper to auto-generate the /etc/resolv.conf file. To change the default DNS resolver, you need to disable that network helper in the hosting control panel.

If this method still doesn’t work, perhaps it’s due to the fact the /etc/resolv.conf file on your Ubuntu server is not a symbolic link to /run/resolvconf/resolv.conf. You need to delete the /etc/resolv.conf file and create a symbolic link.

sudo rm /etc/resolv.conf

sudo ln -s /run/resolvconf/resolv.conf /etc/resolv.conf

You can also manually create this file and make it read-only to prevent overwritten by other applications on the same server.

sudo rm /etc/resolv.conf

echo "nameserver" | sudo tee /etc/resolv.conf

sudo chmod 444 /etc/resolv.conf

systemd-resolved isn’t running

If you see the following error after executing the systemd-resolve --status command,

Failed to get global data: Unit dbus-org.freedesktop.resolve1.service not found.

It might be systemd-resolved isn’t running. Start it with:

sudo systemctl status systemd-resolved

Enable auto-start.

sudo systemctl enable systemd-resolved

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 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 '': 2001:4178:2:1269:dead:beef:cafe:fed5#53
network unreachable resolving '': 2001:4178:2:1269:dead:beef:cafe:fed5#53
network unreachable resolving '': 2610:28:3090:3001:dead:beef:cafe:fed5#53
network unreachable resolving '': 2610:28:3090:3001:dead:beef:cafe:fed5#53

To disable IPv6 in BIND on Ubuntu, simply open the /etc/default/named 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


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.


If you can find the following errors in the BIND logs, it means BIND has a problem trusting the DNSSEC keys.

named[2194196]: managed-keys-zone: DNSKEY set for zone '.' could not be verified with current keys
named[2194196]: validating ./NS: no valid signature found
named[2194196]: no valid RRSIG resolving './NS/IN':
named[2194196]: validating ./NS: no valid signature found
named[2194196]: no valid RRSIG resolving './NS/IN':
named[2194196]: validating ./NS: no valid signature found
named[2194196]: no valid RRSIG resolving './NS/IN':
named[2194196]: validating ./NS: no valid signature found
named[2194196]: no valid RRSIG resolving './NS/IN':
named[2194196]: validating ./NS: no valid signature found

To make it work properly, we can rebuild the managed key database with the following commands.

sudo rndc managed-keys destroy
sudo rdnc reconfig

Named Automatic Restart

If for any reason your Named process is killed, you need to run the following command to restart it.

sudo systemctl restart named

Instead of manually typing this command, we can make Named automatically restart by editing the named.service systemd service unit. To override the default systemd service configuration, we create a separate directory.

sudo mkdir -p /etc/systemd/system/named.service.d/

Then create a file under this directory.

sudo nano /etc/systemd/system/named.service.d/restart.conf

Add the following lines in the file, which will make Named automatically restart 5 seconds after a failure is detected.


Save and close the file. Then reload systemd.

sudo systemctl daemon-reload

To check if this would work, kill Named with:

sudo pkill named

Then check Named status. You will find Named automatically restarted.

systemctl status named

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 named) 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

Note: When you restart BIND, its entire cache will be flushed.

No servers could be reached

If you see the following error when using the dig command on client computers

;; connection timed out; no servers could be reached

It could be that

  • Your firewall rule is wrong. Check your firewall log.
  • The BIND resolver isn’t running.
  • BIND isn’t listening on a network interface.
  • Can you ping from the DNS client to the DNS resolver?


I hope this tutorial helped you set up a local DNS resolver on Ubuntu 22.04/20.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 🙂

Rate this tutorial
[Total: 9 Average: 4.8]

42 Responses to “Set Up Local DNS Resolver on Ubuntu 22.04/20.04 with BIND9

  • Dear Xiao,

    Sometimes you can set up local dns resolver with UnBound.


  • error
    Apr 24 23:49:06 named[588]: managed-keys-zone: Unable to fetch DNSKEY set ‘.’: failure
    [email protected]:/etc/apt# sudo systemctl enable bind9
    Failed to enable unit: Refusing to operate on alias name or linked unit file: bind9.service

    nice job I regularly use your tutorial, thank you very much, for your help.

  • Mohcine
    2 years ago

    Thank you for all what you do

  • Cyberian
    2 years ago

    Hello, thanks. When I add IPv4 of the server as the manual DNS server on my ipad, it does not resolve. What else needs to be opened?

  • One question… can Pi hole work over this setup?

  • Mike Nordyke
    2 years ago

    Thanks for this straight forward tutorial. I would like to know if there is a tutorial on setting up a slave DNS server.

    • You don’t need to set up Master-Slave between two DNS resolvers. If you want to run a backup DNS resolver, simply use the same steps to set up the second instance.

      If you use response policy zone on your DNS resolver, then you need to set up master-slave, the process of which is described in the linked article.

  • dns not working, names is running ok bind ubuntu, i need help!


  • [email protected]:/$ sudo netstat -lnptu | grep named
    [sudo] password for armazem:
    tcp        0      0  *               LISTEN      10645/named
    tcp        0      0 *               LISTEN      10645/named
    tcp6       0      0 ::1:953                 :::*                    LISTEN      10645/named
    udp   196736      0    *                           10645/named
    udp        0      0  *                           10645/named

    but my external ip does not appear

  • where I insert the public ip?

  • Kevin Hanrahan
    2 years ago

    I get this funny warning when I test facebook on the DNS server:

    ; <> DiG 9.16.1-Ubuntu <> A @
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: REFUSED, id: 15406
    ;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
    ;; WARNING: recursion requested but not available

    Does this mean that the DNS resolver isn’t working? If so, how do I fix it? FYI, the Global settings don’t list Nameservers, just the Link2.

    Link 2 (enp4s0)
          Current Scopes: DNS           
    DefaultRoute setting: yes           
           LLMNR setting: yes           
    MulticastDNS setting: no            
      DNSOverTLS setting: no            
          DNSSEC setting: no            
        DNSSEC supported: no            
      Current DNS Server: x.x.x.x
    • If you run dig command on the DNS server itself, you can specify the DNS server as

      dig A @

      If run dig command on another box, be sure to add the client’s IP address to the firewall whitelist and the BIND allow-recursion list.
      Per-link settings override global settings, so your server is fine.

  • I followed a lot of your tutorials & they’ve been great & much appreciated.

    I’m get an “rndc: connect failed: connection refused” error when attemping: rndc status

    Would this be a permission error on the /etc/bind folder or a UFW firewall issue?


    • To answer my own question, it was a file permission.
      I had been adding my blacklist zone for ads & malware domains but made a mess.
      I then restored a backup on the bind folder without the permissions.

      To anyone else who may get the same error, most of the files in /etc/bind should have ownership for root:bind.

  • alireza
    2 years ago

    hello friend
    can you create a tutorial for build a public doh or dns(like or

  • Hi,

    Is there an easy way to check how many clients are currently connected to bind?

  • Hello Xiao,

    I’ve got this warning

    /var/spool/postfix/etc/resolv.conf and /etc/resolv.conf differ

    after performing this article.

    • Restart Postfix.

      sudo systemctl restart postfix

      Postfix will copy the file /etc/resolv.conf to /var/spool/postfix/etc/resolv.conf when it restarts.

      • Hello Xiao,

        – Only after rebooting, I’ve got this warning: /var/spool/postfix/etc/resolv.conf and /etc/resolv.conf differ.

        – So I need to reboot and after that perform a “sudo systemctl restart postfix”?

        Thank you

    • Make sure you have enabled the named-resolvconf.service and systemd-resolved.service.

      sudo systemctl enable named-resolvconf.service systemd-resolved.service

      Then create a directory for Postfix to store your customizations.

      sudo mkdir -p /etc/systemd/system/postfix.service.d/

      Create a start.conf file.

      sudo nano /etc/systemd/system/postfix.service.d/start.conf

      Add the following two lines in this file.

      After=systemd-resolved.service named-resolvconf.service

      Save and close the file.

      This way, postfix.service will start after named-resolvconf.service and systemd-resolved.service

  • Hi Xiao,

    Thanks so much for the amazing guides. I’ve set up a static website using Jekyll, and thanks to you have a fully functioning mail server with DMARC, DKIM and all the spam measures. Very pleased!

    I have a single cloud server with Digital Ocean which I’m using to run both the mail server and website. I don’t seem to have any issues with DO blocking SMTP at the moment but if I do, then I’ll rebuild elsewhere so not too worried. The server is mostly for learning, but as I’m going to be hosting a live website, I also want to be secure and try and maintain uptime.

    I’ve come across this guide and I’m at a cross roads. Would it be ill-advised to now also set up a local DNS resolver on this too or is that exactly what you’re suggesting? Locally would be out of the question, as the minute my machine is off then the site wouldn’t be able to use it for spam blacklists etc so I assume that just leaves me with it being on production or skipping entirely.

    In case it makes any difference, I’m likely to also end up setting up a VPN on there so I can VPN onto the server and get the static IP. Above you’ve said that you’d recommend this installed on there if I’m doing that. I don’t want to get the wrong end of the stick though.

    I’ve set up virtual machines which I’ve used as named servers before but never set up a local resolver, and definitely not done it on a ‘production’ server, so I don’t want to make my server vulnerable if I can help it.

    Thanks in advance,

    • “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.

  • Ursan Bogdan
    1 year ago


    thanks for the tutorial, i have used it for setting up DNS service on my VPS with openVPN.

    keep up the work.

  • when i run sudo named-checkconf i get out put /etc/bind/named.conf.options:32: ‘′: address/prefix length mismatch ’24’

    • Arafat877
      1 year ago

      have you resolved this issue ??? if yes please share the solution

      • oh man be sure you replace the right IP in allow-recursion {;;; }; you should replace your server IP is with your IP you can check it by IP addr

    1 year ago

    I have this error message Xiao Guoan:

    none:100: 'max-cache-size 90%' - setting to 1756MB (out of 1951MB)

    (look at on the attach file), can you help me? Thank you..

  • in this case // provide recursion service to trusted clients only
    allow-recursion {;;; };
    which IP I should replace in and

  • Thanks for the tutorial; it works awesomely!

Leave a Comment

  • Comments with links are moderated by admin before published.
  • Your email address will not be published.
  • Use <pre> ... </pre> HTML tag to quote the output from your terminal/console.
  • Please use the community ( for questions unrelated to this article.
  • I don't have time to answer every question. Making a donation would incentivize me to spend more time answering questions.

The maximum upload file size: 2 MB. You can upload: image. Links to YouTube, Facebook, Twitter and other services inserted in the comment text will be automatically embedded. Drop file here