DNS with bind9 and DHCP on Ubuntu 16.04

This post will show you how to install DNS with bind9 and DHCP on Ubuntu 16.04. We will end up with a full blown bind9 DNS with an integrated DHCP server. If you are a home user and your network has grown such that you are tired of using all static IP addresses and having to configure the /etc/hosts files by hand, then use the great tool dnsmasq. See my How to set up dnsmasq. Dnsmasq is so much simpler to setup and maintain than bind9, you should think about using it.

DNS with bind9 and DHCP on Ubuntu 16.04 also works on a Raspberry PI 3 running the Ubuntu Image.

If you are determined to use bind9 and isc-dhcp server then carry on. This is what I do.

I start off with a minimal Ubuntu server install. This is all tried and tested out in a test Networking Lab with VirtualBox.

Backup your system before you go any further! Do not do this on a production server.

This is what we will be installing with this howto.

  • DNS Server:
    • Name: lab-dns-dhcp.dragon.lab
    • Server Type: Authoritative.
    • Forward Lookup Zone: dragon.lab.
    • Reverse Lookup Zone: 200.1.10.in-addr.arpa.
  • Network:
    • Subnet: 10.1.200.0/24
    • DNS/DHCP Server Address: 10.1.200.3
    • DNS/DHCP Server Name: lab-dns-dhcp
    • Gateway Address: 10.1.200.1
    • Broadcast Address: 10.1.200.255
    • Netmask: 255.255.255.0
  • DHCP Server:
    • Dynamic Pool: 10.1.200.100 to 10.1.200.119
    • With Updates to DNS (bind9)

The interfaces file should have something like this:

auto eth0
iface eth0 inet static
   address 10.1.200.3
   gateway 10.1.200.1
   netmask 255.255.255.0
   dns-nameservers  8.8.8.8

Update your system with the latest patches and security fixes.

sudo apt-get update
sudo apt-get dist-upgrade

Let’s pretend it’s Windows and reboot as we installed some updates. That gives you a minute or so to grab a very swift coffee πŸ™‚

sudo reboot

Installing the software is painless both modules should be available from the usual Ubuntu repos.

sudo apt-get install bind9 isc-dhcp-server

DNS Configuration

The configuration files for bind9 are cryptic and not particularly intuitive. It is very easy to break a working setup, let alone fail to get it working. You can do this by missing off a single semi-colon or full stop. Talking about full stops, if your system fails to work it is most likely a missing full stop that is stopping it from working. Look at the log output in /var/log/syslog.

The official documentation for bind9 which is rather extensive and very well written, so go there first, there is no need to go anywhere else for help :- Get it from https://www.isc.org it is also installed with the bind9-doc package.

So you insist on following my howto, let us begin. The first configuration file to look at, is one you should not change. Add your changes to the files which are included or to those included further down the branches. Let’s have a look at it anyway.

cd /etc/bind
less /etc/bind/named.conf
// This is the primary configuration file for the BIND DNS server named.
//
// Please read /usr/share/doc/bind9/README.Debian.gz for information on the 
// structure of BIND configuration files in Debian, *BEFORE* you customize 
// this configuration file.
//
// If you are just adding zones, please do that in /etc/bind/named.conf.local

include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
include "/etc/bind/named.conf.default-zones"; 

Key File

The installation process creates a crypto file needed when our new DHCP server talks back to this DNS server. The command below creates or recreates a file /etc/bind/rndc.key replacing the one generated by the install process, so it’s not strictly necessary to run this at all but it will not do any harm to run it again at this time. The -b 512 means the secret part will be created with 512 bits rather than the default 128 bits. In this case bigger is better.

sudo /usr/sbin/rndc-confgen -a -b 512

It should look something like this, do not include the secret string in any log posts. πŸ™‚ The one here has been mangled from the original. The text in quotes “rncd.key” can be changed to anything you like, within reason.
Just remember that if you do change the text, also update the text where it is accessed in both /etc/bind/named.conf* and /etc/dhcp/dhcpd.conf

key "rndc-key" {
  algorithm hmac-md5;
  secret "kOvv6eBVbAkwHjbBzeC3hezzTQWT4cZ/HellOTHeReThisiSManGledW0f4aGT775Nhb6E4MdzsRX5dZFDhpMQ==";
};

The file contents should be kept secret. The default permissions are correct, owner:group = bind:bind with permissions of 0640. These settings will not work with DHCP as the owner/group is wrong. If you change the permissions, each time bind is updated you will need to change them back again. It gets annoying, see comments the below. The answer proposed by the upstream developers is that when you are using DHCP with DDNS you copy the rndc.key file from /etc/bind into /etc/dhcp/ddns-keys. The permissions also need to be changed on the new file.

sudo cp /etc/bind/rndc.key /etc/dhcp/ddns-keys
sudo chown root:root /etc/dhcp/ddns-keys/rndc.key
sudo chmod 640 /etc/dhcp/ddns-keys/rndc.key

If you rebuild the file with rndc-confgen, remember to copy it over to ddns-keys again.

named.conf.options

To the first config file we will edit.

sudo nano named.conf.options
include "/etc/bind/rndc.key";

acl internals {
    // lo adapter 
    127.0.0.1;
    // CIDR for your local networks
    10.1.200.0/24;
};

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 https://www.kb.cert.org/vuls/id/800113

   // 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 {
       // DNS on the Internet you could also add 
       // the DNS servers from your ISP
       10.1.200.1;
       // Google's DNS
//       8.8.8.8;
       // Open DNS 
//       208.67.220.220;
   };
   allow-query {
      internals;
   };
   allow-query-cache {
      internals;
   };
   // enables recursive queries but on from our local nets and local hosts
   // Do not allow externals to do recursive queries.
   recursion yes;
   allow-recursion {
      internals;
   };
   allow-transfer {
      internals;
   };
   //========================================================================
   // If BIND logs error messages about the root key being expired,
   // you will need to update your keys.  See https://www.isc.org/bind-keys
   //========================================================================
   // turn off zone encryption. The auto flag still generates 
   // warnings in the log file
   dnssec-enable no;
   // dnssec-validation auto;

   listen-on-v6 { none; };
   auth-nxdomain no;    # conform to RFC1035
};  

Add the section for “acl internals {}”. This limits access to your server and LAN only when applied to options. It will stop the scum bags in China using your DNS. Not sure why the guys in China are so interested in hacking my servers or using my DNS. You can now use the name internals in the sections for allow-query, allow-query-cache, allow-recursion and allow-transfer. These are now limited to our own internal network, LAN.

The forwarders section, this is where you place the DNS from your ISP. I’m using 10.1.200.1 which in the one on my lab-router. You can also use Google‘s DNS 8.8.8.8, 8.8.4.4 or OpenDNS 208.67.220.220, 208.67.222.222. This DNS will use these IP addresses to forward queries it cannot answer directly.

We turn on recursive queries but restrict them to be from our local clients only. Do not allow externals to perform recursive queries on your DNS.
Towards the end you will see the option listen-on-v6 I have set this to none as I do not use IPv6 on my network and there is no need to listen or answer queries for IPV6.

To set only one or more IPv4 addresses just add the IP addresses to aa listen-on block as show below:

listen-on { 10.1.200.3; };

To listen on all interfaces use this:

listen-on { any; };

Adding DNS Zones

Let’s get on with defining our first zones. Before that include the rndc.key file created above into the named.conf.local file. We will use it again later. The first zone is the forward looking zone for dragon.lab the second one is the reverse lookup zone definition.

The files which the zones point to can be called anything, make them meaningful. They must be placed in /var/lib/bind and should have permissions 644 and be owned:group by bind:bind. More of that a little later.

named.conf.local

sudo nano /etc/bind/named.conf.local
//
// Do any local configuration here
//
include "/etc/bind/rndc.key";

zone "dragon.lab" {
     type master;
     file "/var/lib/bind/dragon.lab.zone";
     allow-update { key rndc-key; };
};

# This is the zone definition for reverse DNS. replace 200.1.10 with your network
# address in reverse notation - e.g my network address is 10.1.200
zone "200.1.10.in-addr.arpa" {
     type master;
     file "/var/lib/bind/dragon.lab.rev.zone";
     allow-update { key rndc-key; };
};

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

The string rndc-key; must be the same string you used in the rndc.key file as mentioned above. Also take a look at the commented out include file zones.rfc1918. You may decide to use it after amending it to your own environment.

Dummy Zones

I have seen some people add dummy zones like this:

zone "facebook.com" {
  type master;
  file "/var/lib/bind/block-domains";
};

These zones are designed to stop unwanted advertising, doubleclick.net, or other commonly used junk on web pages like icons to Facebook and Twitter. I believe this type of zone is unwarranted, the user can always install and configure an ad-blocker. It is not up to the network guy to block this type of content.

Configuring the Zones

Zones files go in the directory /var/lib/bind and should be owned:group by root:bind and shoud have permissions of 0775.

sudo nano /var/lib/bind/dragon.lab.zone
$ORIGIN dragon.lab.
$TTL 907200	; 1 week 3 days 12 hours
@                IN SOA	ns1.dragon.lab. admin.dragon.lab. (
				2014071403 ; serial
				28800      ; refresh (8 hours)
				3600       ; retry (1 hour)
				604800     ; expire (1 week)
				38400      ; minimum (10 hours 40 minutes)
				)
			NS	ns1

lab-router1		A	10.1.200.1
ns1                     A       10.1.200.3
lab-dns-dhcp            CNAME   ns1   ; the name of the server we are building

Make sure you get the syntax correct. Note the trailing full stop ‘.’ on the hostname ns1.dragon.lab., (two places) and the email address admin.dragon.lab.. Get these wrong and your DNS will not work.

To fully explain what each bit of this file is doing, read the official documentation it is rather good. A quick run through may help out a little here though.

  • $ORIGIN Sets the domain name that will be appended to any unqualified records.
  • $TTL The time-to-live of the RR field is a 32-bit integer represented in units of seconds. The TTL describes how long a RR can be cached before it should be discarded.
    Rather than using seconds you can add a suffix for

    • m minutes
    • h hours
    • d days
    • w weeks
  • SOA Start of Authority record, contains general administrative and control information about the domain. It has the following format
    • Name dragon.lab
    • Class IN
    • Type SOA
    • Name-Server ns1.dragon.lab. (Note: the trailing full stop)
    • Email-Address admin.dragon.lab. (Note: the @ is replaced with a full stop and there is a trailing one)
    • Serial-No Usually the date as YYYYMMDDSS where SS is a number counting up, used by slave DNS servers.
    • Refresh How often slave DNS server should check back
    • Retry If the above fails retry after this long
    • Expiry Remove data this old when retries fail.
    • Minimum-TTL Time to remember that NXDOMAIN, not found, was returned by the master DNS
  • All the NS, MX, A and CNAME Records for the zone.

The reverse lookup zone file looks like this.

sudo nano /var/lib/bind/dragon.lab.rev.zone

Here is the complete reverse lookup. The in-addr.arpa domain is a legacy domain from the early days of the Internet. We also use PRT records not MX, A or CNAME records here. Watch out for trailing full stops!

$TTL 907200	; 1 week 3 days 12 hours
@                 IN SOA	ns1.dragon.lab. admin.dragon.lab. (
				2014071402 ; serial
				28800      ; refresh (8 hours)
				604800     ; retry (1 week)
				604800     ; expire (1 week)
				86400      ; minimum (1 day)
				)
			NS	ns1.dragon.lab.

1			PTR	lab-router1.dragon.lab.
3                       PTR     lab-dns-dhcp.dragon.lab.
			PTR	dragon.lab.

Change the permissions on the two new zone files we created, so they are in the bind group and read and writable by the owner and the group.

sudo chown bind:bind /var/lib/bind/*zone
sudo chmod 664 /var/lib/bind/*zone

If you want to add some more host names with static IP addresses make the entries in /var/lib/bind/dragon.lab.zone, for lookups and /var/lib/bind/dragon.lab.rev.zone for the reverse lookups. Say we have a machine called desktop1 which has an IP address of 10.1.200.20 we can use the following:

/var/lib/bind/dragon.lab.zone
desktop1              A   10.1.200.20  

And add desktop1 to the reverse lookup zone file.

/var/lib/bind/dragon.lab.rev.zone
20                       PTR     desktop1.dragon.lab.

Check Bind Config Syntax

You can check the syntax of your bind9 config files with the following command. If there are no errors you will see no output and will be returned to a new prompt. If there are errors they will be highlighted. They will give the file and line number where the mistake was detected. If by some chance you have no errors try creating one yourself, just to see the output.

sudo named-checkconf

We can also check the zone files for errors. See the command lines for the forward and reverse zones.

sudo named-checkzone dragon.lab /var/lib/bind/dragon.lab.zone
sudo named-checkzone 200.1.10.in-addr.arpa /var/lib/bind/dragon.lab.rev.zone

We should be able to start or restart our DNS server now. Remember to check the error/warning output in your /var/log/syslog. It will point out where you missed off those pesky full stops. πŸ™‚ Use the tail command below in a new terminal window and the restart in your existing terminal. You can see the log lines as they are written.

sudo tail -fn10 /var/log/syslog
sudo service bind9 restart

If you see any messages like the one below they usually mean you forget to change the permissions above.

managed-keys-zone: journal file is out of date: removing journal file

Now we have a very basic zone file setup. The NIC on the DNS server should be setup to look only at localhost, 127.0.0.1. change the the line for dns-nameservers, the interfaces file should now have something like this in it. Remember we used the Google DNS or OpenDNS in the named.conf.local file as our forwarder so your lab-dns-dhcp server will look there if it cannot find an answer from bind.

auto eth0
iface eth0 inet static
   address 10.1.200.3
   gateway 10.1.200.1
   netmask 255.255.255.0
   dns-nameservers  127.0.0.1

Reload the new settings in the interfaces file by bouncing eth0 or rebooting the server.

sudo ifdown eth0 && sudo ifup eth0

Now for a quick test to see something is working, lookup the lab-dns-dhcp server.

dig lab-dns-dhcp@dragon.lab
; <<>> DiG 9.9.5-3ubuntu0.5-Ubuntu <<>> lab-dns-dhcp dragon.lab
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49518
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0

;; QUESTION SECTION:
;lab-dns-dhcp.			IN	A    10.1.200.3

;; Query time: 1 msec
;; SERVER: 10.1.200.1#53(10.1.200.1)
;; WHEN: Sun Sep 27 11:36:33 BST 2015
;; MSG SIZE  rcvd: 30

And we can do a reverse lookup on the IP address to check the reverse lookup zone.

dig -x 10.1.200.3
; <<>> DiG 9.10.3-P4-Ubuntu <<>> -x 10.1.200.3
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 55110
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 3

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;3.200.1.10.in-addr.arpa.	IN	PTR

;; ANSWER SECTION:
3.200.1.10.in-addr.arpa. 907200 IN	PTR	ns1.dragon.lab.

;; AUTHORITY SECTION:
200.1.10.in-addr.arpa.	907200	IN	NS	ns1.dragon.lab.

;; ADDITIONAL SECTION:
ns1.dragon.lab.	86400	IN	A	10.1.200.3


;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(10.1.200.1)
;; WHEN: Sat Sep 16 15:07:24 BST 2017
;; MSG SIZE  rcvd: 148

You can use the following tools to debug your DNS server. The messages in syslog are usually pretty informative.

  • tail -f /var/log/syslog
  • dig [hostname]
  • host [hostname]
  • ping [hostname]

The man pages for all of them are a good source of information and their command line switches.

Let us do a quick check that the reverse lookup is also working. This time lookup the IP address 10.1.200.1 that is my lab-router, you may need to use a different IP depending on what you placed in your dragon.lab.rev.zone file.

dig -x 10.1.200.1
; <<>> DiG 9.9.5-3ubuntu0.5-Ubuntu <<>> -x 10.1.200.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1124
;; flags: qr aa rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;1.200.1.10.in-addr.arpa.	IN	PTR

;; ANSWER SECTION:
1.200.1.10.in-addr.arpa. 0	IN	PTR	lab-router1.dragon.lab.

;; Query time: 2 msec
;; SERVER: 10.1.200.1#53(10.1.200.1)
;; WHEN: Sun Sep 27 11:39:41 BST 2015
;; MSG SIZE  rcvd: 77
Do not continue until your DNS is working.

If all is working then you now has a basic DNS for your local LAN working. now would be a good time to take a backup.

DHCP Configuration

The config for DHCP is all in one file and a little less verbose. Let's dive right in and edit the file.
You should be able to work out what the options do, if not look in man dhcp.conf

sudo nano /etc/dhcp/dhcpd.conf
ddns-updates on;
ddns-update-style standard;
authoritative;

# This option points to the copy rndc.key we created for bind9.
include "/etc/dhcp/ddns-keys/rndc.key";

allow unknown-clients;
use-host-decl-names on;
default-lease-time 86400; #24  hours
max-lease-time 86400;
log-facility local7;

# dragon.lab DNS zones
zone dragon.lab. {
  primary 10.1.200.3; # This server is the primary DNS server for the zone
  key rndc-key;       # Use the key we defined earlier for dynamic updates
}
zone 200.1.10.in-addr.arpa. {
  primary 10.1.200.3; # This server is the primary reverse DNS for the zone
  key rndc-key;       # Use the key we defined earlier for dynamic updates
}

# dragon.lab LAN range
subnet 10.1.200.0 netmask 255.255.255.0 {
  range 10.1.200.100 10.1.200.119;
  option subnet-mask 255.255.255.0;
  option routers 10.1.200.1;
  option domain-name-servers 10.1.200.3;
  option domain-name "dragon.lab";
  ddns-domainname "dragon.lab.";
  ddns-rev-domainname "in-addr.arpa.";

  ## To PXE Boot from another server ##
#  filename "pxelinux.0";
#  next-server 10.1.200.5; 
}

# Static hosts give an IP addr by MAC address
#group {
#  # Fist static host
#  host static1.dragon.lab {
#      hardware ethernet 01:23:45:67:89:ab;
#      fixed-address 10.1.200.120;
#      ddns-hostname "static1";
#  }
#}

Listen on specific NIC

To allow DHCP to listen only on some interfaces amend the file /etc/default/isc-dhcp-server, then look towards the end of the file for the comment shown below:

sudo nano /etc/default/isc-dhcp-server
# On what interfaces should the DHCP server (dhcpd) serve DHCP requests?
#	Separate multiple interfaces with spaces, e.g. "eth0 eth1".
INTERFACES="enp0s3"

Testing That Lot

Reboot the server to get our services, DNS, DHCP & apparmor, restarted and along with all their dependencies. Take a look at the syslog file for any errors or warnings.

Now boot up another machine which will use the DHCP service we have created. As it boots the output in syslog should look similar to the following:

Jul 20 14:54:18 lab-dns-dhcp dhcpd: DHCPDISCOVER from 08:00:27:d3:5e:8a via eth0
Jul 20 14:54:19 lab-dns-dhcp dhcpd: DHCPOFFER on 10.1.200.105 to 08:00:27:d3:5e:8a (lab-desktop) via eth0
Jul 20 14:54:19 lab-dns-dhcp named[2190]: client 10.1.200.2#15077/key rndc-key: signer "rndc-key" approved
Jul 20 14:54:19 lab-dns-dhcp named[2190]: client 10.1.200.2#15077/key rndc-key: updating zone 'dragon.lab/IN': adding an RR at 'lab-desktop.dragon.lab' A
Jul 20 14:54:19 lab-dns-dhcp named[2190]: client 10.1.200.2#15077/key rndc-key: updating zone 'dragon.lab/IN': adding an RR at 'lab-desktop.dragon.lab' TXT
Jul 20 14:54:19 lab-dns-dhcp dhcpd: DHCPREQUEST for 10.1.200.105 (10.1.200.2) from 08:00:27:d3:5e:8a (lab-desktop) via eth0
Jul 20 14:54:19 lab-dns-dhcp dhcpd: DHCPACK on 10.1.200.105 to 08:00:27:d3:5e:8a (lab-desktop) via eth0
Jul 20 14:54:19 lab-dns-dhcp dhcpd: Added new forward map from lab-desktop.dragon.lab. to 10.1.200.105
Jul 20 14:54:19 lab-dns-dhcp named[2190]: client 10.1.200.2#15077/key rndc-key: signer "rndc-key" approved
Jul 20 14:54:19 lab-dns-dhcp named[2190]: client 10.1.200.2#15077/key rndc-key: updating zone '200.1.10.in-addr.arpa/IN': deleting rrset at '105.200.1.10.200.10.10.in-addr.arpa' PTR
Jul 20 14:54:19 lab-dns-dhcp named[2190]: client 10.1.200.2#15077/key rndc-key: updating zone '200.1.10.in-addr.arpa/IN': adding an RR at '105.200.1.10.200.1.10.in-addr.arpa' PTR
Jul 20 14:54:19 lab-dns-dhcp dhcpd: Added reverse map from 105.200.1.10.200.1.10.in-addr.arpa. to lab-desktop.dragon.lab.

You should see, in order, DHCPDISCOVER, DHCPOFFER followed by a line saying it is "updating zone 'dragon..." and then some lines with DHCPREQUEST, DHCPACK and "Added new forward map" If you do, you are all done!

Try using dig to find the IP of your dhcp enabled machine and then do a reverse lookup on that IP. You should see the answer lines similar to these.

lab-desktop.dragon.lab.	3600	IN	A	10.1.200.100

100.200.1.10.in-addr.arpa. 3600	IN	PTR	lab-desktop.dragon.lab.

If not you missed something out, I found it was usually missing semicolons or permissions not being set correctly or a pesky missing full stop. The syslog is a great help finding the problem.

Testing with nsupdate

You can also add and remove codes from the DNS with nsupdate, here is a quick example. Read through the man page for the command to find out more. After executing the command line you will be given a '>' prompt. While running through the commands also run a tail on your syslog in another terminal to see some extra logging.

nsupdate -k /etc/bind/rndc.key
> server localhost
> zone dragon.lab
> update delete test.dragon.lab. A
> update add test.dragon.lab. 86400 IN A 10.1.200.190
> show
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:      0
;; flags:; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; ZONE SECTION:
;dragon.lab.			IN	SOA

;; UPDATE SECTION:
test.dragon.lab.	0	ANY	ANY	
test.dragon.lab.	86400	IN	A	10.1.200.190

In another window use dig to examine the records for test.dragon.lab. You should see that you get answers for the A record.

> send
> update delete test.dragon.lab. A
> show
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:      0
;; flags:; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; ZONE SECTION:
;dragon.lab.			IN	SOA

;; UPDATE SECTION:
st.dragon.lab.	0	ANY	ANY	
st.dragon.lab.	0	ANY	A	

> send
> quit

That was rather long. I Bet you are glad you grabbed that swift coffee right at the beginning. πŸ™‚

NTP Server

If you are setting up a DNS and DHCP server you will also need a NTP server to synchronise the clocks on the PC's connected to your LAN. An NTP server uses very little in resources, it will not need a dedicated machine to run on. We can add one to the DNS/DHCP server. It only takes a few edits from a default install and you will be done.

To install and configure an NTP server follow my HOWTO

Updates To The DNS root Zone

The root name server list is updated occasionally. To keep yours up to date, download the latest with:

sudo mv /etc/bind/db.root /etc/bind/db.root_old
sudo wget -q -O /etc/bind/db.root https://www.internic.net/zones/named.root
sudo service bind9 reload

You might want to set up a crontab job to do this for you, frequently and on a regular basis.

Trouble shooting

If anything is not working check the /var/log/syslog output first. You can also look in the DHCP leases file /var/lib/dhcp/dhcpd.leases.

Unable to add forward map from host.dragon.lab

You may see this when testing a DHCP client. The client will get an IP address but the DNS will not get updated. Check that the zones in dhcp.conf and named.conf.local are the same. In dhcp.conf the name ends in a full stop.

Also check the primary lines in dhcp.conf actually point to your DNS server.

If you see something like "insecurity proof failed"

If you see something like the following in syslog

error (chase DS servers) resolving β€˜dragon.lab/DS/IN’: 10.1.200.101#23
named[4321]: error (insecurity proof failed) resolving β€˜com/NS/IN’: 10.1.200.101#23
named[518]: error (no valid RRSIG) resolving './NS/IN': 128.63.2.53#53named[518]: error (network unreachable) resolving './NS/IN': 2001:503:c27::2:30#53

You need to comment out the following line in /etc/bind/named.conf.options, or change it from auto to no.

dnssec-validation auto;

If you see errors like these:

Apr 17 14:53:17 hostname named[518]: error (network unreachable) resolving './NS/IN': 2001:503:c27::2:30#53

This means that IPv6 is not working and probably not enabled on your server. You can stop bind9 from accessing or resopning to IPV6 by adding updating the line shown below in /etc/default/bind6 adding the -4.

OPTIONS="-4 -u bind"

17 thoughts on “DNS with bind9 and DHCP on Ubuntu 16.04

  1. Dirk Hedlund

    Nice, concise, well-written article.

    I do have a question, though. The ownership on rndc.key keeps getting reset to root:root when updates are installed. Any idea why? Or more to the point, how do I stop that from happening?

    Reply
    1. Richard Post author

      Good question and since the weather is grey, cold and damp outside, I decided to fix this. It has also been annoying me too! I found there is a better way. The way I was using was going against the system expected by the developers. Never a good thing to do. If you copy the rndc.key file into /etc/dhcp/ddns-key, there is no need to change the permissions of the bind copy or update the apparmor config for DHCP.
      I have updated the post to reflect the necessary changes.

      I have also added some commands to test the config files for bind9 out before trying to start the service. They make find those missing full stops and semi-colons so much simpler.

      Reply
  2. carlos

    DNS Server:
    Name: dns-server.dragon.lab I imagine this is the hostname?

    Network:
    DNS/DHCP Server Name: lab-dns-dhcp What is this name for?

    Cause you have two different names its confusing me?

    Reply
    1. Richard Post author

      Ah, you are right lab-dns-dhcp.dragon.lab is the name of the DNS/DHCP server this post creates. Just change all the occurrences of dns-server to lab-dns-dhcp and it should work without the confusion. I have updated the post accordingly. Ta!

      Reply
  3. Bruno Forcier

    Hi, this is actually great!

    Wondering how I could go about making a secondary in case the primare failed?

    Have you tought of writing an article about doing this?

    Thanks

    Reply
  4. Jose

    Hi: Congratulations. This is a very useful explanation about DNS and DHCP configuration.
    I’d like to know also what should I do if I’d like that DNS and DHCP would listen in a different interface and IP address.

    Thanks in advance,

    Reply
    1. Richard Post author

      Good point! Setting the NIC that DNS and DHCP listen on is simple:
      For DNS add a listen-on { 10.1.200.3; }; block to named.conf.options
      For DHCP update the INTERFACES=”” line in /etc/default/isc-dhcp-server

      I have updated the post to show that.

      Reply
  5. Benjamin McAllen Covet

    crystal clear explanation, would like to test the combination of dnsmasq, isc-dhcp-server and bind9 configuration, is that a good idea?

    -new learner-

    Reply
    1. Richard Post author

      Unless you have 100’s of PC’s that will use your DNS and DHCP, I would go for dnsmasq as it is far simpler to setup and administer. I have never thought of using all three together, that would seem to be over kill. Or just making your own life difficult.

      Reply
  6. Ted

    Very well done (thank you!) I had to re-jigger my home/office DNS & routers, and you managed to cover all the right bases with accurate information.

    Apropos Microsoft, I spent the first 25 years of my career as a developer/consultant battling planned obsolescence, disruption of evolving standards, and deliberate sabotage of development tools — designed to destroy competition, and imprison their ‘customers’ — before Linux & open-source broke their hegemony over desktop computing.

    And, BTW, the fight ain’t over. The monopolists at Intel, Google, Apple, Facebook (supposedly on ‘our’ side), as well as the entire cabal of telecoms, purveyors of big-media, and the US Government — are quietly cooperating in an attempt to suffocate open-source, critical net-neutral paradigms, and last but not least, our right to live a private life. The outcome will depend on how many of those who recognize what’s taking place are willing to be bought. (Which is one reason I consistently prefer dogs to humans !;)

    Reply
    1. Richard Post author

      Thank you, your comments made me smile, the message is getting out there albeit slowly. I have preferred dogs to people for many many years, espicially children. Dogs at least will not stab you in the back or lie to your face unless there are sausages to steal πŸ™‚

      Reply
  7. Francois

    My DHCP reverse addresses were not being updated properly.
    It would seem that the /etc/dhcp/dhcpd.conf entry
    ddns-rev-domainname “200.1.10.in-addr.arpa.”;
    should look like:
    ddns-rev-domainname “in-addr.arpa.”;
    My /var/log/syslog entries looked like:
    dhcpd: Added reverse map from 80.8.168.192.8.168.192.in-addr.arpa. to LAPTOP-SIP0SIQR.home.lab.
    After the change reverse DNS worked properly and the syslog entries were:
    dhcpd: Added reverse map from 71.8.168.192.in-addr.arpa. to DESKTOP-S7S5KFE.home.lab.

    Reply
    1. Richard Post author

      Francois, thank you for your comment pointing out my mistake. You are right. What was I thinking? As you say the option ddns-rev-domainname in /etc/dhcp/dhcp.conf should be set to simply “in-addr.arpa.”. I have updated the post accordingly.

      Reply
  8. Bogdan

    You have a command “dig -x lab-router1”, to check the reverse DNS.
    For me it’s not working. With “-x” parameter you should pass an IP instead of a hostname.
    I’m using CentOS 7.

    Reply
    1. richard Post author

      haha! πŸ™‚ You are quite right, the whole point of a reverse lookup it that you have the IP address and not the hostname. Damn, I’m still grinning over that typo. Well spotted.

      Reply
  9. Brainstorms

    This is just what I’ve been looking for, as I want to implement Linux NUCs with these capabilities, plus a few additional ones. Basically what I’m making are Bastion Hosts to isolate LANs (my home LAN and groups of subnets at work) that will also provide comprehensive DNS/DHCP service for the protected subnets.

    The reason I’m writing is that I want to add blacklisting to my local DNS (but not DNSBL, which seems to be designed for blocking spam in emails). To date, I’ve been using specially-crafted ‘hosts’ tables, which are my LAN’s hosts table cat’d to a hosts table of “bad” domains that all resolve to 0.0.0.0. I get this list from a website that updates it every couple of months. This “bad” domains hosts table blocks attempts to resolve spammers, malware, spyware, adware, trackers, etc., eliminating most ads, popups, webbugs, etc. on web pages (as they don’t even load, speeding up surfing as well). This works wonderfully as an enhanced ‘hosts’ table.

    What I need to know is, what’s the best way to transform/incorporate this hosts table into the DNS server I’m about to build (using your guide), so that my hosts can go back to their default minimalist ‘hosts’ tables? I want their DNS lookups to resolve local hosts, forward to external DNS for external hosts, but also return 0.0.0.0 (or 404, etc) on my blacklisted domains so that unwanted external lookups are blocked. Do I have to write a script to generate A records and cat that to my local hosts A records? It would be nice if I could “seed” my server’s cached records list with these (and a long TTL for each).

    My other addition is to add FWKNOP (cipherdyne.org/fwknop, basically encrypted port knocking) to give me a stealthy, secure way of getting into my LAN from elsewhere on the internet (typically while I’m at work). This also allows me at work to surf into hosts hidden behind my Bastion Hosts for things like remote desktop, etc. without exposing open ports (which invites unwanted queries from the corporate IT security team).

    Any suggestions are welcome! Thanks!

    Reply
  10. chris

    This is fantastic! Thank you very much for taking the time to write this post (and checking peoples comments to update accordingly).

    THANK YOU

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *