DNS with bind9 and DHCP on Ubuntu 14.04

Updated for Ubuntu 14.04-3 LTS. 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.

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 desktop install with MATE. 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: dns-server.dragon.org.uk
    • Server Type: Authoritative.
    • Forward Lookup Zone: dragon.lab.
    • Reverse Lookup Zone: 200.1.10.in-addr.arpa.
  • Network:
    • Subnet:
    • DNS/DHCP Server Address:
    • DNS/DHCP Server Name: lab-dns-dhcp
    • Gateway Address:
    • Broadcast Address:
    • Netmask:
  • DHCP Server:
    • Dynamic Pool: to
    • With Updates to DNS (bind9)

The interfaces file should have something like this:

auto eth0
iface eth0 inet static

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 isc-dhcp-server bind9

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, 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"; 

To the first config file we will edit.

sudo nano named.conf.options
acl internals {

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;
       // Google's DNS
   allow-query {
   // restrict recursion
   allow-recursion {
   allow-transfer {
   // 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 { any; };
   auth-nxdomain no;    # conform to RFC1035

Add the section for “acl internals {}”, and update the commented out section for forwarders. This limits access to your server and LAN only. 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. You can now use the name internals in the three sections for allow-query, allow-recursion and allow-transfer. These are now limited to our own internal network, LAN.

The forwarders section, where your DNS server asks to lookup IP address for hosts it does not know. This is where you place the DNS from your ISP. I’m using which in the one on my lab-router. You can also use Google’s, or OpenDNS,

The installation process creates the crypto file needed when our new DHCP server talks back to this DNS server. The command below creates 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.

sudo /usr/sbin/rndc-confgen -a

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 "Ay6c74c/HELP/MEr26ZPlw==";

The file contents should be kept secret. We will change the permissions so the casual reader cannot see it.

sudo chown root:bind /etc/bind/rndc.key
sudo chmod 640 /etc/bind/rndc.key

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.

That is all we need here.

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"; 

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 be Read/Write by both.

sudo nano /var/lib/bind/dragon.lab.zone
$TTL 907200	; 1 week 3 days 12 hours
dragon.lab		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.dragon.lab.
$ORIGIN dragon.lab.
lab-router1		A
ns1                     A
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
200.1.10.in-addr.arpa 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.
$ORIGIN 200.1.10.in-addr.arpa.
1			PTR	lab-router1.dragon.lab.
3                       PTR     dns-server.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 will be using this DNS/DHCP server along with Samba4 to create an Active directory server you should also add another CNAME record to /var/lib/bind/dragon.lab.zone at the end./var/lib/bind/dragon.lab.rev.zone.

lab-addc1               CNAME   ns1  

Also add the reverse lookup record to /var/lib/bind/dragon.lab.rev.zone, but this time before the “PTR dragon.lab. line. . Adding these records just means you can access the machine with two different names, in this case dns-dhcp and lab-addc1. I use the hostname lab-addc1 as the SAMBA AD DC server name.

3                       PTR     dns-server.dragon.lab.
3                       PTR     lab-addc1.dragon.lab.
			PTR	dragon.lab.

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 we can use the following:


desktop1              A  


20                       PTR     desktop1.dragon.lab.

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, 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

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: 0, AUTHORITY: 0, ADDITIONAL: 0

;lab-dns-dhcp.			IN	A

;; Query time: 1 msec
;; WHEN: Sun Sep 27 11:36:33 BST 2015
;; MSG SIZE  rcvd: 30

;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 5992
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1

; EDNS: version: 0, flags:; udp: 4096
;dragon.lab.			IN	A

.			1799	IN	SOA	a.root-servers.net. nstld.verisign-grs.com. 2015092700 1800 900 604800 86400

;; Query time: 40 msec
;; WHEN: Sun Sep 27 11:36:33 BST 2015
;; MSG SIZE  rcvd: 114

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 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 lab-router1
; <<>> DiG 9.9.5-3ubuntu0.5-Ubuntu <<>> -x
;; 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


;; ANSWER SECTION: 0	IN	PTR	lab-router1.dragon.lab.

;; Query time: 2 msec
;; WHEN: Sun Sep 27 11:39:41 BST 2015
;; MSG SIZE  rcvd: 77

Do not continue until your DNS is working.

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 interim;
update-static-leases on;

# This option points to the same rndc.key we create for bind9.
include "/etc/bind/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; # 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; # 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 netmask {
  option subnet-mask;
  option routers;
  option domain-name-servers;
  option domain-name "dragon.lab";
  ddns-domainname "dragon.lab.";
  ddns-rev-domainname "200.1.10.in-addr.arpa.";

# 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;
#      ddns-hostname "static1";
#  }

If try and start up the dhcp daemon it will throw an error and fail to start. Access to the rndc.key file is being blocked by apparmor. Edit the apparmor config file for dhcpd. If you seach towars the end there is a line for /etc/dhcp/ddns-keys/** r, comment this out and add the one below to replace it.

sudo nano /etc/apparmor.d/usr.sbin.dhcpd
#  /etc/dhcp/ddns-keys/** r,  
  /etc/bind/rndc.key  r,

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 to 08:00:27:d3:5e:8a (lab-desktop) via eth0
Jul 20 14:54:19 lab-dns-dhcp named[2190]: client rndc-key: signer "rndc-key" approved
Jul 20 14:54:19 lab-dns-dhcp named[2190]: client 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 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 ( from 08:00:27:d3:5e:8a (lab-desktop) via eth0
Jul 20 14:54:19 lab-dns-dhcp dhcpd: DHCPACK on 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
Jul 20 14:54:19 lab-dns-dhcp named[2190]: client rndc-key: signer "rndc-key" approved
Jul 20 14:54:19 lab-dns-dhcp named[2190]: client rndc-key: updating zone '200.1.10.in-addr.arpa/IN': deleting rrset at '' PTR
Jul 20 14:54:19 lab-dns-dhcp named[2190]: client rndc-key: updating zone '200.1.10.in-addr.arpa/IN': adding an RR at '' PTR
Jul 20 14:54:19 lab-dns-dhcp dhcpd: Added reverse map from 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 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.

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.cong 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’:
named[4321]: error (insecurity proof failed) resolving β€˜com/NS/IN’:

You need to comment out the following line in /etc/bind/named.conf.options, it appears to be set by default.

dnssec-validation auto;

13 thoughts on “DNS with bind9 and DHCP on Ubuntu 14.04

  1. Lars Urban

    Hello again,

    also this is a nice work, setup your config (in my case without DHCP) and it is running without problems.
    Thank you for your Work !

    A little typo :
    sudo ntp restart –> sudo service ntp restart


    1. Richard Post author

      I am glad you found the tutorial useful and can amend it to suit your needs.
      Also thank you for letting me know about the typo. My only comment about that is DOH!! Do you know how many times I read and re-read that?

      1. Jan Hauge

        Thank you for your neat writeup of the steps. I have done the setup many times but run often out of time before getting dhcp to work but have now thanks to you both dns and dhcp running quite nicely.

        My next step is to get the AD DC on top. I have one running but I want to get it right with the necessary.

        Keep up the good work!

  2. Jeff Brown

    Many thanks for the tutorial. After stumbling down a few other paths, I found this, and now have BIND, NTP, DNS, and DHCP services running on Ubuntu 14.04.
    The next step for me is the Samba AD-DC config, but sleep followed by coffee is needed first!

  3. Ryan

    Great How-to! Just the right amount of hand holding for someone like me with an understanding of the concepts but not the implementation. I’ve learned a bunch from this.

    One thing that did throw me for a bit was the zone definitions. The code does not format correctly in Chrome which caused some confusion as I was entering it myself instead of copying/pasting.

    Thanks for posting this! Now on to the AD DC..

  4. Michael


    Thanks for this very useful guide! It has saved a lot of time!

    But I think I have found one little bug…
    ddns-rev-domainname “200.1.10.in-addr.arpa.”; –> in my case this will cause an error when I try a reverse lookup on a client who has got the IP from the dhcp
    (Because the dhcp has written this wrong statement into the zone-file: )

    I have fixed this Problem with this correction:
    ddns-rev-domainname “in-addr.arpa.”;

    And also I have changed
    “zone 200.1.10.in-addr.arpa. …”
    into “zone in-addr.arpa. …”

    I hope this contribution is helpful

    1. Richard Post author

      Thanks for pointing out the mistake in the zones. I only needed to to change the DHCP setting for ddns-rev-domainname β€œin-addr.arpa.”; I have also rechecked it on 14.04-3.

  5. Sal

    Hi and thanks for such a great HOWTO.

    The only problem i had, was that i had to do a

    “sudo chown root:bind /var/lib/bind/*zone”


    “sudo chmod 644 /var/lib/bind/*zone”

    then everything worked grat!

    Thanks again.

  6. Bitnuts

    Thanks for this guide. It worked like a charm. Also thanks to Michael who pointed out the β€œzone 200.1.10.in-addr.arpa. …” issue.

    Much appreciated. I learned a lot

  7. Faron

    Excellent resource. This has been my 10+ attempt to get this to work as per I want. The concept from this resource worked so well with patient, of course. My scenario has to do with owning CIDR /29, and that is a new ballgame but, it brought me back to the battle with bind. Thanks to your article. I finally tackled that down. Readers, my /29 worked so well without a problem.


  8. ahka

    Apparently the reverse zone requirements have changed or whatever because the command named-checkzone issues the message:
    3: ignoring out-of-zone data (200.1.10.in-addr.arpa)
    12: ignoring out-of-zone data (
    13: ignoring out-of-zone data (
    has 0 SOA records
    has no NS records

    I’ve copied and pasted the example so I’m pretty sure it is not a typo on my part.

    The other example zone is correct.

    Unfortunately I’ve problems configuring my own reverse lookup zone and I got the same messages when using your example as a template.

    Furthermore this is a great blog. I’ve used three blog posts in one day with no problems at all except the one mentioned above. All blogs are very clear and easy to understand. Thanks for your good work.

  9. Mark

    Finally,.. an article that describes how to set dhcp and bind9 up,.. that actually works!!,.. Ok the others may work if you know a little more, but this article gives and overview of what he options mean,.. with little tests on the way to show things are heading in the right direction,…. and voila a working dhcp bind9 system,.. finally…

    The only thing that I needed to amend for later ubuntu releases was the “interfaces” stuff as this has changed slightly, certainly on a Raspberry Pi…
    And ….many thanks to Michael for the correction….


Leave a Reply

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