An authoritative DNS server holds the official records for your domain. Running your own with BIND gives full control over zones and private nameservers such as ns1.example.com. This guide sets up a primary BIND server, a secondary, and the registrar side.
Before you start
- Two Linux servers with static IPs, ideally in different locations (for example
203.0.113.10and198.51.100.20). - Root access and UDP/TCP port 53 open on both.
- Access to your domain's registrar to create glue records (child nameservers).
Note: On cPanel/WHM, DNS zones are managed for you through the Zone Editor and the server's nameserver. Only run BIND by hand on servers without a panel.
Install BIND
- Ubuntu/Debian:
sudo apt install -y bind9 bind9-utils(config in/etc/bind/, servicenamed). - AlmaLinux/Rocky:
sudo dnf install -y bind bind-utils && sudo systemctl enable named(config in/etc/named.conf).
Disable open recursion
In the options block (/etc/bind/named.conf.options or /etc/named.conf) set:
options {
directory "/var/cache/bind";
recursion no;
allow-transfer { none; };
listen-on { any; };
listen-on-v6 { any; };
dnssec-validation auto;
};On AlmaLinux keep its default directory "/var/named"; and change listen-on from 127.0.0.1 to any.
Create the zone on the primary
- Declare the zone (Ubuntu:
/etc/bind/named.conf.local):zone "example.com" { type primary; file "/etc/bind/zones/db.example.com"; allow-transfer { 198.51.100.20; }; also-notify { 198.51.100.20; }; };Older BIND versions use
type master. - Create
/etc/bind/zones/db.example.com:$TTL 3600 @ IN SOA ns1.example.com. hostmaster.example.com. ( 2026010101 ; serial 3600 ; refresh 900 ; retry 1209600 ; expire 300 ) ; negative TTL IN NS ns1.example.com. IN NS ns2.example.com. ns1 IN A 203.0.113.10 ns2 IN A 198.51.100.20 @ IN A 203.0.113.50 www IN CNAME example.com. @ IN MX 10 mail.example.com. mail IN A 203.0.113.60 - Check and reload:
sudo named-checkconf && sudo named-checkzone example.com /etc/bind/zones/db.example.com && sudo systemctl reload named
Configure the secondary
zone "example.com" {
type secondary;
primaries { 203.0.113.10; };
file "/var/cache/bind/db.example.com";
};Reload named on the secondary; it transfers the zone from the primary. Older versions use type slave and masters.
Register glue records and nameservers
- At your registrar, create child nameservers
ns1.example.com → 203.0.113.10andns2.example.com → 198.51.100.20. - Set the domain's nameservers to
ns1.example.comandns2.example.com. - Allow time for the TLD to publish the change.
Test the setup
dig @203.0.113.10 example.com A +norecurse– answer with theaaflag.dig @198.51.100.20 example.com SOA +short– same serial as the primary.dig @203.0.113.10 google.com– should beREFUSED(no open recursion).
Warning: Increase the SOA serial every time you edit a zone, or secondaries will keep serving old records.
Troubleshooting
- Zone fails to load: read
journalctl -u named; usually a missing trailing dot or syntax error. - Secondary does not update: serial not increased,
allow-transfermissing, or TCP 53 blocked. - Permission denied on zone file (AlmaLinux): files must be readable by the
namedgroup and have the right SELinux context – runrestorecon -Rv /var/named.
FAQ: BIND authoritative DNS
Why do the records need a trailing dot?
A trailing dot makes a name fully qualified; without it BIND appends the zone name, giving ns1.example.com.example.com.
Can one server be both nameservers?
It works technically but defeats redundancy. Use two servers on different networks.
Should I enable DNSSEC?
Yes if you can maintain it: sign the zone and publish the DS record at the registrar. Broken DNSSEC makes the domain unreachable.
