What is BIND9?
BIND9 (Berkeley Internet Name Domain version 9) is the most widely deployed open-source DNS server. It is maintained by ISC (Internet Systems Consortium) and powers a significant portion of internet DNS infrastructure.
- Acts as an authoritative DNS server for your domain zones
- Acts as a recursive resolver for internal networks
- Fully standards-compliant (RFC 1034, 1035)
Prerequisites
- Ubuntu 20.04 / 22.04 / 24.04 (any LTS)
- Root or sudo privileges
- A static IP address configured on the server
- Port 53 TCP/UDP open in your firewall
Step 1 – Update the System
Always update packages before installing:
sudo apt update && sudo apt upgrade -y
Step 2 – Install BIND9
sudo apt install bind9 bind9utils bind9-doc -y
This installs:
- bind9 – the DNS server daemon (
named
) - bind9utils – tools like
named-checkconf
,named-checkzone
- bind9-doc – documentation
Step 3 – Verify Installation
named -v
Expected output:
BIND 9.18.x (Ubuntu)
Step 4 – Configure BIND9 (named.conf.options)
Edit the main options file:
sudo nano /etc/bind/named.conf.options
Replace the contents with a secure baseline configuration:
options {
directory "/var/cache/bind";
// Allow recursion only for trusted networks
recursion yes;
allow-recursion { 127.0.0.1; 10.0.0.0/8; 192.168.0.0/16; };
// Listen on all interfaces
listen-on { any; };
listen-on-v6 { any; };
// Forward unresolved queries to public DNS
forwarders {
8.8.8.8;
8.8.4.4;
};
forward only;
// Security hardening
dnssec-validation auto;
auth-nxdomain no;
version none;
};
Important: Restrict
allow-recursionto your internal subnets only. Never allow open recursion to the internet.
Step 5 – Create a Forward Zone
Edit
named.conf.localto declare your zone:
sudo nano /etc/bind/named.conf.local
Add:
zone "example.local" {
type master;
file "/etc/bind/zones/db.example.local";
};
Create the zones directory and zone file:
sudo mkdir -p /etc/bind/zones
sudo cp /etc/bind/db.local /etc/bind/zones/db.example.local
sudo nano /etc/bind/zones/db.example.local
Edit to look like:
$TTL 604800
@ IN SOA ns1.example.local. admin.example.local. (
2026021501 ; Serial (YYYYMMDDnn)
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
; Name servers
@ IN NS ns1.example.local.
; A records
ns1 IN A 192.168.1.10
@ IN A 192.168.1.10
www IN A 192.168.1.20
Step 6 – Create a Reverse Zone (Optional but Recommended)
Add to
named.conf.local:
zone "1.168.192.in-addr.arpa" {
type master;
file "/etc/bind/zones/db.192.168.1";
};
sudo cp /etc/bind/db.127 /etc/bind/zones/db.192.168.1
sudo nano /etc/bind/zones/db.192.168.1
$TTL 604800
@ IN SOA ns1.example.local. admin.example.local. (
2026021501
604800
86400
2419200
604800 )
@ IN NS ns1.example.local.
10 IN PTR ns1.example.local.
20 IN PTR www.example.local.
Step 7 – Validate Configuration
Check for syntax errors before restarting:
sudo named-checkconf
Check each zone file:
sudo named-checkzone example.local /etc/bind/zones/db.example.local
sudo named-checkzone 1.168.192.in-addr.arpa /etc/bind/zones/db.192.168.1
Expected output:
zone example.local/IN: loaded serial 2026021501
OK
Step 8 – Start & Enable BIND9
sudo systemctl enable --now named
Verify it is running:
sudo systemctl status named
Expected output:
● named.service - BIND Domain Name Server
Active: active (running)
Step 9 – Configure Firewall
sudo ufw allow 53/tcp
sudo ufw allow 53/udp
sudo ufw reload
Step 10 – Test DNS Resolution
From a client on the same network:
nslookup www.example.local 192.168.1.10
Or using
dig:
dig @192.168.1.10 www.example.local
Expected output:
;; ANSWER SECTION:
www.example.local. 604800 IN A 192.168.1.20
✅ Best Practices
- Always use
named-checkconf
before restarting BIND9 - Restrict recursion to internal networks only
- Keep serial numbers updated (use YYYYMMDDNN format) on every zone change
- Enable DNSSEC for production zones
- Monitor BIND9 logs:
sudo journalctl -u named -f
- Set
version none;
to hide BIND version from public
Remember: Always validate zone files after edits. A single syntax error can take down DNS for your entire domain.
