The most surprising thing about BIND is that it’s not just a DNS server; it’s a complex, distributed system designed for resilience and security, often misunderstood as a simple lookup service.
Let’s see BIND in action. Imagine a small network with a few internal hosts. We want server1.local to resolve to 192.168.1.10 and server2.local to 192.168.1.11.
First, we need to install BIND. On a Debian/Ubuntu system:
sudo apt update
sudo apt install bind9 bind9utils bind9-doc
On a Red Hat/CentOS/Fedora system:
sudo yum update
sudo yum install bind bind-utils
Now, the core configuration. The main file is typically /etc/bind/named.conf (Debian/Ubuntu) or /etc/named.conf (Red Hat/CentOS). We’ll include a zone file for our local domain.
In named.conf, we add:
zone "local" {
type master;
file "/etc/bind/zones/db.local";
};
This tells BIND that it’s the primary ("master") server for the local zone and that the zone’s data is in /etc/bind/zones/db.local.
Next, we create the zone file /etc/bind/zones/db.local:
$TTL 604800
@ IN SOA ns1.local. admin.local. (
2 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
@ IN NS ns1.local.
ns1 IN A 192.168.1.5 ; The IP of our BIND server itself
server1 IN A 192.168.1.10
server2 IN A 192.168.1.11
Here’s what’s happening:
$TTL: Default Time To Live for records.@ IN SOA ns1.local. admin.local. (...): Start Of Authority. It defines the primary name server (ns1.local) and an email address for the administrator (admin.localbecomesadmin@local.). The numbers are crucial for zone transfers and caching. TheSerialnumber MUST be incremented every time you change the zone file; DNS servers use this to detect updates.@ IN NS ns1.local.: This zone is authoritative forlocaland the name server isns1.local.ns1 IN A 192.168.1.5: The IP address forns1.local.server1 IN A 192.168.1.10: A record mappingserver1.localto its IP.server2 IN A 192.168.1.11: A record mappingserver2.localto its IP.
We need to ensure BIND can read this file. Set permissions:
sudo chown bind:bind /etc/bind/zones/db.local
sudo chmod 644 /etc/bind/zones/db.local
Now, start and enable the BIND service:
sudo systemctl start bind9 # or named on Red Hat/CentOS
sudo systemctl enable bind9 # or named
Check the status and logs for errors:
sudo systemctl status bind9
sudo journalctl -u bind9 -f
To test, use dig or nslookup from another machine on the network, or from the server itself if it’s configured to use itself as a resolver. First, configure your client to use 192.168.1.5 as its DNS server (e.g., in /etc/resolv.conf or network manager settings).
dig server1.local @192.168.1.5
dig server2.local @192.168.1.5
You should see output like:
;; ANSWER SECTION:
server1.local. 604800 IN A 192.168.1.10
BIND’s internal model revolves around zones, which are authoritative databases of DNS records. When a BIND server receives a query, it first checks its cache. If the answer isn’t there, it consults its local zone files if it’s authoritative for the domain. If not, it acts as a resolver, querying other DNS servers (root servers, TLD servers, other authoritative servers) recursively until it gets an answer, which it then caches. The named.conf file orchestrates this by defining which zones BIND is authoritative for, where to find their data, and how to forward queries it can’t answer itself.
A common pitfall is forgetting to increment the serial number in the zone file after making changes. If you don’t, other DNS servers (or even BIND itself if it’s acting as a secondary) won’t know there’s a new version and will continue to serve stale data. BIND uses this serial number as a timestamp to detect updates.
The next step is often setting up reverse DNS lookup (PTR records) to map IP addresses back to hostnames, which is critical for many network services and security protocols.