Exercise: Setting Up a DNS Server with BIND9 on Ubuntu 24.04

Introduction

In the previous exercise, you set up a DHCP server inside a virtual machine and tested it with a client machine in VirtualBox. Now you’ll extend your server to also provide DNS (Domain Name System) services for your internal network.

DNS translates domain names (like www.example.com) into IP addresses and back again. In your local network, you can run your own DNS server to resolve names of machines without relying on the internet.

You’ll use BIND9, the most widely used DNS server software on Linux.

By the end of this exercise you will:

  • Install and configure BIND9
  • Create a forward lookup zone (name → IP)
  • Create a reverse lookup zone (IP → name)
  • Test your DNS configuration from the client machine

1. Preparing the Server Machine

Make sure you are working on the same server VM that already runs your DHCP server. Update and install BIND9:

sudo apt update 
sudo apt install bind9 bind9-utils -y
  • bind9: the DNS server software
  • bind9-utils: contains useful tools like dig for testing

Check if the service is running:

systemctl status bind9

You should see it as active (running). If not, start it:

sudo systemctl start bind9 
sudo systemctl enable bind9

2. Understanding DNS Zones

DNS is structured into zones.

  • A forward zone maps names → IP addresses.
    Example: www.mynetwork.local → 192.168.56.10
  • A reverse zone maps IP addresses → names.
    Example: 192.168.56.10 → www.mynetwork.local

We’ll configure both.


3. Configuring a Forward Zone

  1. Open the BIND configuration for local zones:
sudo nano /etc/bind/named.conf.local
  1. Add the following block (replace the network/domain names as needed):
zone "mynetwork.local" {
    type master;
    file "/etc/bind/db.mynetwork.local";
};

This tells BIND that it will act as the master DNS server for the domain mynetwork.local, using the zone file db.mynetwork.local.

  1. Create the forward zone file by copying the default template:
sudo cp /etc/bind/db.local /etc/bind/db.mynetwork.local
  1. Edit the new zone file:
sudo nano /etc/bind/db.mynetwork.local

Example content (adapt as needed):

$TTL    604800
@       IN      SOA     ns1.mynetwork.local. admin.mynetwork.local. (
                              2         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL

; Name server
@       IN      NS      ns1.mynetwork.local.

; A records
ns1     IN      A       192.168.56.10
www     IN      A       192.168.56.20
www2    IN      A       192.168.56.21

; MX records
@       IN      MX 10   mail.mynetwork.local.
@       IN      MX 20   mail2.mynetwork.local.

mail    IN      A       192.168.56.30
mail2   IN      A       192.168.56.31

Explanation:

  • ns1 is the DNS server itself (at .10)
  • Two web servers: www and www2
  • Two mail servers with MX priorities

4. Configuring a Reverse Zone

  1. Edit the config file again:
sudo nano /etc/bind/named.conf.local

Add:

zone "56.168.192.in-addr.arpa" {
    type master;
    file "/etc/bind/db.192.168.56";
};

This reverse zone corresponds to the subnet 192.168.56.0/24. (It’s written backwards for DNS purposes.)

  1. Create the reverse zone file:
sudo cp /etc/bind/db.127 /etc/bind/db.192.168.56
  1. Edit the new file:
sudo nano /etc/bind/db.192.168.56

Example content:

$TTL    604800
@       IN      SOA     ns1.mynetwork.local. admin.mynetwork.local. (
                              2         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL

; Name server
@       IN      NS      ns1.mynetwork.local.

; PTR records
10      IN      PTR     ns1.mynetwork.local.
20      IN      PTR     www.mynetwork.local.
21      IN      PTR     www2.mynetwork.local.
30      IN      PTR     mail.mynetwork.local.

Explanation:

  • IP 192.168.56.10 maps to ns1.mynetwork.local
  • IP 192.168.56.20 maps to www.mynetwork.local
  • IP 192.168.56.21 maps to www2.mynetwork.local
  • IP 192.168.56.30 maps to mail.mynetwork.local

5. Checking Configuration

Run:

sudo named-checkconf 
sudo named-checkzone mynetwork.local /etc/bind/db.mynetwork.local 
sudo named-checkzone 56.168.192.in-addr.arpa /etc/bind/db.192.168.56

If no errors appear, restart BIND:

sudo systemctl restart bind9

6. Configuring the Client to Use the DNS Server

On your client VM, set the DNS server to point to your server VM (e.g. 192.168.56.10).
If you have already installed and configured DHCP on your server, configure your DHCP accordingly, so that your host knows which DNS server to use. Otherwise set it manually in /etc/netplan/ or Network Manager.


7. Testing DNS Resolution

From the client VM, run:

dig @192.168.56.10 www.mynetwork.local 
dig @192.168.56.10 www2.mynetwork.local 
dig @192.168.56.10 mail.mynetwork.local 
dig -x 192.168.56.20

Expected results:

  • www.mynetwork.local resolves to 192.168.56.20
  • www2.mynetwork.local resolves to 192.168.56.21
  • Reverse lookup of 192.168.56.20 gives www.mynetwork.local

You can also try with:

nslookup www.mynetwork.local 192.168.56.10

8. Extending DNS with DDNS (Dynamic DNS Updates)

So far, you configured DNS zones manually. That works for static servers (like www, mail), but for client machines that come and go, maintaining DNS by hand is impractical.

With Dynamic DNS (DDNS), the DHCP server can automatically update the DNS server whenever it leases a new IP to a client.

  • When a host gets an IP, its hostname → IP (A record) and IP → hostname (PTR record) are added to DNS.
  • When the lease expires or is released, the records are removed.

This creates a seamless integration between DHCP and DNS.


8.1. Create a TSIG Key for Secure Updates

DNS updates must be secured to prevent unauthorized changes. The DHCP server and DNS server share a secret key (TSIG).

On the server VM:

sudo rndc-confgen -a -r /dev/urandom

This creates a key in /etc/bind/rndc.key. But for DHCP we’ll generate our own:

sudo dnssec-keygen -a HMAC-SHA256 -b 256 -n HOST dhcpupdate

This generates two files like Kdhcpupdate.+163+12345.key and .private.
View the key:

cat Kdhcpupdate.+163+*.key

You’ll see something like:

dhcpupdate. IN KEY 512 3 163 XXXXXXXXXXXXXXXXXXXXX==

The last part (XXXXXXXXXXXXXXXXX==) is the secret. Save it.


8.2. Configure BIND to Accept DDNS Updates

Edit your named.conf.local:

sudo nano /etc/bind/named.conf.local

Modify your zones to allow updates with the key:

key "dhcpupdate" {
    algorithm hmac-sha256;
    secret "XXXXXXXXXXXXXXXXXXXX==";
};

zone "mynetwork.local" {
    type master;
    file "/etc/bind/db.mynetwork.local";
    allow-update { key dhcpupdate; };
};

zone "56.168.192.in-addr.arpa" {
    type master;
    file "/etc/bind/db.192.168.56";
    allow-update { key dhcpupdate; };
};

8.3. Configure DHCP Server to Send Updates

Edit your DHCP config:

sudo nano /etc/dhcp/dhcpd.conf

Add the same key definition:

key dhcpupdate {
    algorithm hmac-sha256;
    secret "XXXXXXXXXXXXXXXXXXXX==";
};

zone mynetwork.local. {
    primary 127.0.0.1;
    key dhcpupdate;
}

zone 56.168.192.in-addr.arpa. {
    primary 127.0.0.1;
    key dhcpupdate;
}

Explanation:

  • zone mynetwork.local. → updates forward zone
  • zone 56.168.192.in-addr.arpa. → updates reverse zone
  • Both use the key you generated

Restart both services:

sudo systemctl restart bind9 
sudo systemctl restart isc-dhcp-server

8.4. Testing DDNS

  1. On your client VM, configure it to get a hostname via DHCP (default on Ubuntu).
    For example, set hostname to client1:

    sudo hostnamectl set-hostname client1

    Then reconnect network (or reboot).

  2. On the server VM, check if DNS got updated:

    dig @127.0.0.1 client1.mynetwork.local 
    dig -x <client1-IP>

    You should see both:

    • client1.mynetwork.local → correct IP
    • reverse lookup of IP → client1.mynetwork.local
  3. Add a second client (e.g. client2), and repeat. DNS should update automatically.