Setting up Bind9 as a forwarding DNS server

Last Updated:

I recently installed named/bind9 on one of my Raspberry Pis to use as a DNS server for my local network. Although initially written for my Raspberry Pi install, this has since been tested on Ubuntu as well. It should also work on any system you can run bind/named on, although you may need to find the appropriate packages via your distribution’s package manager if you’re running something other than a Debian-based system.

The most recent version this guide has been tested on is: BIND 9.18.18-0ubuntu0.22.04.2-Ubuntu

Here’s my notes from the setup:

Installing BIND9 & Utils

sudo apt install bind9 bind9utils bind9-doc dnsutils

Configuring as a Forwarder

Configuration files for “named” / bind(9) are located in the /etc/bind directory. We can edit the named.conf.options file to configure our server as a forwarder.

// This is the local lan access control list (acl), configure to your subnet.
acl local-lan {

options {
  directory "/var/cache/bind";

  // If there is a firewall between you and nameservers you want
  // to talk to, you may need to fix the firewall to allow multiple
  // ports to talk.  See

  // If your ISP provided one or more IP addresses for stable
  // nameservers, you probably want to use them as forwarders.
  // Uncomment the following block, and insert the addresses replacing
  // the all-0's placeholder.

  forwarders {; // Cloudflare; // Google

  allow-query { local-lan; };

  // If BIND logs error messages about the root key being expired,
  // you will need to update your keys.  See
  dnssec-validation auto;

  auth-nxdomain no;    // conform to RFC1035
  listen-on-v6 { any; };

  // Additional config for our usage
  recursion yes;
  querylog yes; // Disable if you want, nice for debugging.
  version "not available"; // Disable for security

Adding our own Zones

For adding our own zones, we’ll add a separate file called zone.<domain> in this folder.

We’ll then add the domain to the /etc/bind/named.conf.local file so it’ll be served:

// Do any local configuration here

// Consider adding the 1918 zones here, if they are not used in your
// organization
//include "/etc/bind/zones.rfc1918";

zone "" {
    type master;
    file "/etc/bind/";

Here’s the content of my /etc/bind/ file:

; BIND data file for us-ne-1 lan0
$TTL    604800
@       IN      SOA (
            ; Owner
                              4         ; Serial - increment after save
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL

@           IN      NS
@           IN      A ; Address of this server
foo         IN      A ; Add more records here!

Debugging / Checking for errors

Using named-checkzone

You can individually debug zonefiles by checking their config. Any issues with the zone file should be printed to the console.

named-checkzone /etc/bind/

Should output something like this:

zone loaded serial 4

Using named-checkconf

The same goes for your config files, you can use named-checkconf and it’ll print any syntax issues you may have. However, this doesn’t print an “OK” message, like you get from named-checkzone. If you’re not seeing any output, it’s likely your config is fine, especially if checking the exit code via echo $? returns 0.

named-checkconf /etc/bind/named.conf

Debug Mode

You can also start named in debug mode, although this doesn’t always seem to yield the most helpful results. I’d recommend checking the config files above before debugging elsewhere.

sudo -u bind named -d 1

Applying Changes

After making changes to the config files, you’ll need to restart the named service to apply the changes. This may vary distribution to distribution:

sudo systemctl restart named

Testing it out

finally, to test it out, you can use dig to query your server. dig is included in the dnsutils package we installed earlier.

I’m querying from on the host itself, hence the @, if you’re querying from another host, you can replace it with the IP of the host running named.

$ dig @


You should also be able to query for external domains:

$ dig @


Change Log

  • 3/1/2020 - Initial Revision
  • 4/23/2024 - Add extra debugging info, and info about latest tested version

Found a typo or technical problem? file an issue!