When it makes sense to run your own BIND 9 instead of a DNS provider
Managed DNS from a registrar or hosting provider covers most needs, but not all of them. A self-run BIND 9 is worth it if you own an ASN and are building an Anycast network, if you need non-standard zone logic through scripts and views, or if a security policy forbids storing the zone with a third-party provider. The price is that you become responsible for updates, resilience, and protecting the server against DDoS.
Installing BIND 9 and the key configuration files
On Debian or Ubuntu the server comes up like this:
sudo apt update
sudo apt install bind9 bind9utils bind9-doc -yThe configuration is split across several files, each with a clear role:
| File | Purpose |
|---|---|
| /etc/bind/named.conf.options | Global settings: recursion, forwarders, listening addresses |
| /etc/bind/named.conf.local | The list of zones the server is authoritative for |
| /etc/bind/zones/db.example.com | The content of a specific zone: A, NS, MX, and other records |
| /var/log/syslog | The named startup and error log |
Declaring a zone in named.conf.local
Every zone is declared as its own block:
zone "example.com" {
type master;
file "/etc/bind/zones/db.example.com";
allow-transfer { 203.0.113.53; };
also-notify { 203.0.113.53; };
};The allow-transfer directive permits zone transfer only to the listed secondary server IPs, and also-notify makes the master notify them immediately about a serial number change instead of waiting out the refresh interval.
The zone file: SOA, NS, A, and other records
The zone file itself describes the domain's content:
$TTL 3600
@ IN SOA ns1.example.com. admin.example.com. (
2026092901 ; serial
3600 ; refresh
900 ; retry
1209600 ; expire
3600 ) ; minimum
IN NS ns1.example.com.
IN NS ns2.example.com.
ns1 IN A 203.0.113.10
ns2 IN A 203.0.113.53
@ IN A 203.0.113.10
www IN CNAME example.com.The serial number must increase on every edit, otherwise secondary servers will not pick up the new zone version. General record types are covered in a separate knowledge base article.
Checking syntax and reloading the zone
Before restarting named, check the syntax with tools from the bind9utils package:
named-checkconf
named-checkzone example.com /etc/bind/zones/db.example.com
sudo rndc reload example.comThe named-checkzone command catches typos and format violations before they reach production, and rndc reload picks up changes without a full service restart or dropping active sessions.
A secondary server and zone transfer (AXFR)
Resilience requires at least one secondary server on a separate IP — the same requirement underlies glue records when the NS servers live inside the delegated domain itself. The slave configuration looks like this:
zone "example.com" {
type slave;
file "/var/cache/bind/db.example.com";
masters { 203.0.113.10; };
};After the first successful AXFR, the secondary server keeps a local copy of the zone and keeps answering queries even if the master is temporarily unreachable. You can confirm both versions match by comparing the serial with dig, as described in the article on checking a DNS zone. If you plan to delegate part of the namespace to separate NS servers, also read about subdomain delegation.
Summary: a checklist for launching an authoritative server
- named-checkconf and named-checkzone pass with no errors before every reload.
- At least two NS servers on different IPs and, ideally, in different networks.
- allow-transfer is limited to the specific secondary server IPs, not open to everyone.
- The serial increases on every zone edit, and changes are immediately visible through dig from an external resolver.