Step by step DNS Server installation in ubuntu in a fresh VM

“Nice — below is a complete, step-by-step, blog-ready guide to install and configure a simple authoritative + optional recursive BIND9 DNS server on a fresh Ubuntu VM. It’s copyright-free and ready to paste into your notes or blog.

Notes before you begin
• This guide assumes Ubuntu 22.04 / 24.04 (netplan-based).
• Replace example.test and IPs with your real domain and network. (.test is safe for labs.)
• Use sudo for commands or run as root.


1 — Prepare the VM & network

  1. Update packages:
sudo apt update && sudo apt upgrade -y
  1. (Optional but recommended) Give the VM a stable IP. Find your interface name:
ip addr show

Create a netplan file /etc/netplan/01-netcfg.yaml (example for static IP 192.168.56.10/24):

network:
  version: 2
  renderer: networkd
  ethernets:
    ens33:
      dhcp4: no
      addresses: [192.168.56.10/24]
      gateway4: 192.168.56.1
      nameservers:
        addresses: [8.8.8.8,1.1.1.1]

Apply it:

sudo netplan apply

2 — Install BIND9

sudo apt install bind9 bind9utils bind9-doc dnsutils -y

3 — Basic BIND options

Edit /etc/bind/named.conf.options. Minimal example (authoritative + allow recursion to localnets):

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

Inside:

options {
    directory "/var/cache/bind";
    recursion yes;                 # set to no if this server MUST be authoritative-only
    allow-recursion { localnets; 127.0.0.1; };
    allow-query { any; };
    forwarders { 8.8.8.8; 1.1.1.1; };  # for recursive queries; remove for pure-authoritative
    dnssec-validation auto;
    auth-nxdomain no;    # conform to RFC1035
};

Save and exit.


4 — Define your zones

Edit /etc/bind/named.conf.local and add forward and reverse zones:

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

Example:

zone "example.test" {
    type master;
    file "/etc/bind/db.example.test";
    allow-transfer { none; };   # restrict AXFRs; configure TSIG if you need slaves
};

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

Reverse zone name depends on your network (for 192.168.56.0/24 reverse is 56.168.192.in-addr.arpa).


5 — Create forward zone file

Create /etc/bind/db.example.test:

sudo cp /etc/bind/db.local /etc/bind/db.example.test
sudo nano /etc/bind/db.example.test

Example content (edit serial and IPs):

$TTL 604800
@   IN  SOA ns1.example.test. admin.example.test. (
        2025092801 ; serial (YYYYMMDDnn)
        604800     ; refresh
        86400      ; retry
        2419200    ; expire
        604800 )   ; negative cache TTL
;
@       IN  NS      ns1.example.test.
ns1     IN  A       192.168.56.10
www     IN  A       192.168.56.11
mail    IN  A       192.168.56.12
@       IN  MX 10   mail.example.test.

Important: Always update the serial when changing the file (format YYYYMMDDnn is convenient).


6 — Create reverse zone file

Create /etc/bind/db.192.168.56:

sudo cp /etc/bind/db.127 /etc/bind/db.192.168.56
sudo nano /etc/bind/db.192.168.56

Example:

$TTL 604800
@   IN  SOA ns1.example.test. admin.example.test. (
        2025092801 ; serial
        604800
        86400
        2419200
        604800 )
;
@       IN  NS  ns1.example.test.
10      IN  PTR ns1.example.test.      ; 192.168.56.10 -> ns1
11      IN  PTR www.example.test.      ; 192.168.56.11 -> www
12      IN  PTR mail.example.test.     ; 192.168.56.12 -> mail

7 — Syntax check & load zones

Check config & zones:

sudo named-checkconf                 # checks named.conf syntax
sudo named-checkzone example.test /etc/bind/db.example.test
sudo named-checkzone 56.168.192.in-addr.arpa /etc/bind/db.192.168.56

Fix any errors the commands print.

Restart BIND:

sudo systemctl restart bind9
sudo systemctl enable bind9
sudo systemctl status bind9

8 — Firewall (allow DNS)

Allow DNS ports (adjust to your security policy):

sudo ufw allow 53/tcp
sudo ufw allow 53/udp
# Or restrict to a management net:
# sudo ufw allow from 192.168.56.0/24 to any port 53 proto udp

9 — Test your DNS server

From the server itself:

dig @127.0.0.1 example.test A +short    # should return 192.168.56.11 if configured
dig @127.0.0.1 ns1.example.test A +short # should return 192.168.56.10
dig -x 192.168.56.11 @127.0.0.1 +short   # reverse lookup -> www.example.test.

From a remote machine (replace with server IP):

dig @192.168.56.10 www.example.test A +short
nslookup www.example.test 192.168.56.10

If you enabled recursion and forwarders, test recursive queries:

dig @192.168.56.10 www.google.com A +short

10 — Make it authoritative-only (optional)

If you plan to host a public authoritative server and must not recursively resolve for the public, edit named.conf.options:

recursion no;
allow-query { any; };
forwarders { };   # remove forwarders

Restart BIND. Authoritative-only servers should never allow open recursion.


11 — Slave server configuration (optional)

If you want a slave:
In the slave /etc/bind/named.conf.local:

zone "example.test" {
    type slave;
    file "/var/cache/bind/db.example.test";
    masters { 198.51.100.5; };   # master IP
};

On master, allow transfer to slave IP or use TSIG keys for secure zone transfers.


12 — Troubleshooting & logs

  • Check systemd journal:
sudo journalctl -u bind9 -f
  • Check syslog for named messages:
sudo tail -f /var/log/syslog | grep named
  • If BIND can’t read files, AppArmor may block it; check sudo aa-status and /var/log/syslog for AppArmor denials.

13 — Operational tips & security

  • Increment the SOA serial on every zone change. Use YYYYMMDDnn format.
  • Restrict zone transfers: allow-transfer { <slave-ip>; }; or none; and use TSIG where needed.
  • Limit recursion to trusted networks to avoid being used in DNS amplification attacks.
  • Enable DNSSEC if you publish publicly and need tamper protection (optional, advanced).
  • Back up /etc/bind regularly.

Quick one-line summary (for your blog)

Install BIND9, define forward/reverse zones in named.conf.local, create zone files /etc/bind/db.* with SOA/NS/A/PTR records, validate with named-checkzone, open UDP/TCP 53, restart bind9, and test with dig @your-server domain.


REF: AI Tools/Open AI/ChatGPT