“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).
• Replaceexample.testand IPs with your real domain and network. (.testis safe for labs.)
• Usesudofor commands or run as root.
1 — Prepare the VM & network
- Update packages:
sudo apt update && sudo apt upgrade -y
- (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/24reverse is56.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-statusand/var/log/syslogfor AppArmor denials.
13 — Operational tips & security
- Increment the SOA serial on every zone change. Use
YYYYMMDDnnformat. - Restrict zone transfers:
allow-transfer { <slave-ip>; };ornone;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/bindregularly.
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
