When to run your own BIND
Most hosts are well served by systemd-resolved or an external DNS resolver (1.1.1.1). You need your own BIND when:
- Network with more than 20 hosts - internal names (
db1.corp.local) without editing/etc/hostson every machine. - Split-horizon DNS - return private IPs inside the network, public IPs outside.
- Caching resolver for an office or data center - reduces latency and upstream load.
- Authoritative server for your own public domain - self-hosted DNS.
Alternatives: dnsmasq (simpler, for small networks), unbound (resolver only, no authoritative), PowerDNS (database-backed).
Installation and package differences
| Distribution | Package | Daemon | Config |
|---|---|---|---|
| RHEL/Fedora | bind | named | /etc/named.conf |
| Debian/Ubuntu | bind9 | named | /etc/bind/named.conf |
| Utilities | bind-utils / dnsutils | dig, host, nslookup | - |
# RHEL
sudo dnf install bind bind-utils
sudo systemctl enable --now named
# Debian
sudo apt install bind9 dnsutils
sudo systemctl enable --now bind9
The rest of this article uses RHEL paths; substitute /etc/bind/ for Debian.
BIND architecture: three roles
+-----------------+ query +-----------------+
| Client | --------------------> | Recursive |
| /etc/resolv.conf | | resolver/cache |
| nameserver | | |
| 192.168.0.10 | | * recursion |
+-----------------+ | * cache |
+--------+--------+
|
v if not in cache
+-----------------+
| Authoritative |
| for example.org |
+-----------------+
A single named instance can fill any or all of these roles:
- Caching/recursive resolver - answers clients and caches replies from upstream DNS servers.
- Authoritative primary (master) - holds the original copy of the
example.orgzone. - Authoritative secondary (slave) - a replica of the primary, synchronized via AXFR/IXFR.
/etc/named.conf structure
options { listen-on port 53 { 127.0.0.1; 192.168.0.10; }; listen-on-v6 port 53 { ::1; };directory "/var/named";
dump-file "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";
allow-query { localhost; 192.168.0.0/24; };recursion yes;
forwarders { 1.1.1.1; 9.9.9.9; };dnssec-validation auto;
};
logging { channel default_debug {file "data/named.run";
severity dynamic;
};
};
zone "." IN {type hint;
file "named.ca";
};
include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";
Key sections:
options- global settings (interfaces, allowed clients, forwarders, recursion).zone "..."- each zone the server handles.include "..."- split a large config into files (often one per zone).acl name { ... }- a named list of IPs/networks for use inallow-query,allow-transfer.logging- log destinations and severity.
Zone types
| Type | Purpose |
|---|---|
master | Authoritative holder of the original zone (= primary in new terms) |
slave | Authoritative replica from master (= secondary) |
hint | Root servers (. zone) for recursive resolution |
forward | Delegate queries for a zone to another server |
stub | Minimal copy with NS records only (rarely used) |
Forward zone: example.org to IP
zone "example.org" IN {type master;
file "example.org.db";
allow-update { none; }; allow-transfer { 192.168.0.11; }; # secondary};
Zone file /var/named/example.org.db:
$TTL 3600
@ IN SOA ns1.example.org. admin.example.org. (
2026042901 ; serial - YYYYMMDDxx, increment on every CHANGE
3600 ; refresh
1800 ; retry
1209600 ; expire
86400 ) ; negative-cache TTL
IN NS ns1.example.org.
IN NS ns2.example.org.
IN MX 10 mail.example.org.
ns1 IN A 192.168.0.10
ns2 IN A 192.168.0.11
www IN A 192.168.0.20
mail IN A 192.168.0.30
api IN CNAME www
A trailing . after a name means FQDN. Without it, the name is completed with $ORIGIN =
example.org. This is the most common mistake in zone files.
Reverse zone: IP to name
For 192.168.0.0/24 the reverse zone is 0.168.192.in-addr.arpa (octets
in reverse order).
zone "0.168.192.in-addr.arpa" IN {type master;
file "192.168.0.rev";
};
File 192.168.0.rev:
$TTL 3600
@ IN SOA ns1.example.org. admin.example.org. (
2026042901 3600 1800 1209600 86400 )
IN NS ns1.example.org.
10 IN PTR ns1.example.org.
20 IN PTR www.example.org.
30 IN PTR mail.example.org.
PTR records are used in logs (readable names instead of IPs), for anti-spam (a mail server with a matching reverse record is trusted), and for traceroute.
DNS record types
| Type | Purpose |
|---|---|
SOA | Start of Authority: zone metadata (serial, TTLs) |
NS | Authoritative name servers for the zone |
A | name to IPv4 |
AAAA | name to IPv6 |
CNAME | alias to another name |
PTR | IP to name (reverse) |
MX | mail server for the domain plus priority |
TXT | arbitrary text (SPF, DKIM, ACME challenge) |
SRV | service on a host: _sip._tcp.example.org |
CAA | which CAs may issue certificates for the domain |
Caching-only server: minimal config
When you do not need an authoritative server:
options { listen-on { 127.0.0.1; 192.168.0.0/24; }; allow-query { localhost; 192.168.0.0/24; };recursion yes;
forwarders { 1.1.1.1; 9.9.9.9; };forward only; # use forwarders only, do not recurse to root
};
zone "." IN { type hint; file "named.ca"; };This is the ideal office DNS: it caches upstream responses locally.
rndc: controlling named at runtime
sudo rndc status # check if running, show zone serials
sudo rndc reload # re-read all configs and zones
sudo rndc reload example.org # re-read one zone
sudo rndc flush # clear the entire cache
sudo rndc flushname host.example.org # drop cache for a specific name
sudo rndc dumpdb -all # dump cache to file
sudo rndc stats # write statistics
On first install, generate the control key:
sudo rndc-confgen -a -r /dev/urandom
The key is saved to /etc/rndc.key; both named and rndc use it for
authentication.
Validation after editing
Run these checks before rndc reload. A broken config will kill named:
# check named.conf syntax
sudo named-checkconf
# check zone file syntax
sudo named-checkzone example.org /var/named/example.org.db
# -> zone example.org/IN: loaded serial 2026042901
# -> OK
Testing:
dig @192.168.0.10 example.org # query this specific server
dig @192.168.0.10 -x 192.168.0.20 # reverse lookup
dig @192.168.0.10 example.org AXFR # zone transfer (if allowed)
dig @192.168.0.10 +short www.example.org
Security checklist
-
allow-recursionrestricted to your own network. An open recursive resolver is a DDoS amplifier:allow-recursion { 192.168.0.0/24; localhost; }; -
allow-transferonly for known secondaries. Without this, AXFR exposes the entire zone to anyone:allow-transfer { 192.168.0.11; }; # secondary IP -
TSIG key for transfers. Even a secondary IP can be spoofed:
key "transfer-key" { algorithm hmac-sha256; secret "BASE64..."; };zone "example.org" IN {type master;
allow-transfer { key transfer-key; };};
-
DNSSEC validation on caching servers:
dnssec-validation auto. -
Rate limiting against amplification attacks:
rate-limit { responses-per-second 10; }; -
fail2ban watching the named log to block clients hammering queries.
Logs and debugging
Default log: /var/log/messages (RHEL) or journalctl -u named.
To increase verbosity for a specific zone:
sudo rndc trace 3 # level 0..10
sudo rndc notrace
Common problems:
loading zone X: file not found- the path infile ""is missing thedirectoryprefix from options.bad SOA record- a trailing dot is missing after an FQDN, or the SOA has the wrong number of fields.serial number unchanged- you edited the zone but did not increment the serial. Secondary servers will not synchronize.journal out of sync- after manually editing a zone file, delete the.jnljournal.