Configuring a Slave DNS Server with BIND9
In this guide, you will learn how to configure a slave DNS server using BIND9 on Debian. This server will sync with the master server (dns1.javiercruces.org
) and distribute the name resolution load in your local network. You will also be guided to verify that the zone transfer works correctly.
In this case, the slave server is located in the 192.168.10.0/24 network, with the IP 192.168.10.200.
1. Initial Setup of the Slave Server
Hostname
First, assign the correct hostname. Edit the /etc/hostname
file:
dns2
Next, configure the /etc/hosts
file to associate the fully qualified domain name with the local IP:
127.0.1.1 dns2.javiercruces.org dns2
Verify that the FQDN resolves correctly using hostname -f
. You should get the following output:
debian@dns2:~$ hostname -f
dns2.javiercruces.org
2. Installing BIND9
Install the BIND9 package as we did on the master server:
sudo apt update && sudo apt install bind9 bind9utils bind9-doc rsync -y
3. Basic Configuration
Edit named.conf.options
On the slave server, edit the /etc/bind/named.conf.options
file to allow queries from internal networks:
options {
directory "/var/cache/bind";
allow-query { 127.0.0.1; 192.168.10.0/24; };
recursion yes;
dnssec-validation no;
forwarders {
1.1.1.1;
8.8.8.8;
};
};
4. Configuring Slave Zones
Edit the /etc/bind/named.conf.local
file to define the slave zones. These should match the zones configured on the master server:
zone "javiercruces.org" {
type slave;
masters { 192.168.10.1; };
file "/var/cache/bind/slaves/db.javiercruces.org";
};
zone "10.168.192.in-addr.arpa" {
type slave;
masters { 192.168.10.1; };
file "/var/cache/bind/slaves/db.192.168.10";
};
Create the directory to store the slave files if it does not exist:
sudo mkdir -p /var/cache/bind/slaves
sudo chown bind:bind /var/cache/bind/slaves
5. Restarting the Service
Once everything is configured, restart the BIND9 service:
sudo systemctl restart bind9
Check for errors in the event log:
sudo journalctl -xeu bind9
You can also check if the zones were transferred correctly by running:
ls -l /var/cache/bind/slaves
6. Updating the Master Server
For the slave server to receive the zones correctly, it needs to be authorized by the master server (dns1
).
Edit the /etc/bind/named.conf.local
file on the master server and add the allow-transfer
option with the slave’s IP:
zone "javiercruces.org" {
type master;
file "/var/cache/bind/db.javiercruces.org";
allow-transfer { 192.168.10.200; };
};
zone "10.168.192.in-addr.arpa" {
type master;
file "/var/cache/bind/db.192.168.10";
allow-transfer { 192.168.10.200; };
};
Additionally, we will update the DNS records to add the new server. You need to add an A record and an NS record. Here’s the complete file:
debian@dns1:~$ sudo cat /var/cache/bind/db.javiercruces.org
$TTL 86400
@ IN SOA dns1.javiercruces.org. root.javiercruces.org. (
1 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
86400 ) ; Negative Cache TTL
;
@ IN NS dns1.javiercruces.org.
@ IN NS dns2.javiercruces.org.
@ IN MX 10 correo.javiercruces.org.
$ORIGIN javiercruces.org.
dns1 IN A 192.168.10.1
dns2 IN A 192.168.10.200
correo IN A 192.168.10.2
thor IN A 192.168.10.3
hela IN A 192.168.10.4
www IN CNAME thor
informatica IN CNAME thor
ftp IN CNAME hela
We must also update the reverse zone:
$TTL 86400
@ IN SOA dns1.javiercruces.org. root.javiercruces.org. (
1 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
86400 ) ; Negative Cache TTL
;
@ IN NS dns1.javiercruces.org.
$ORIGIN 10.168.192.in-addr.arpa.
1 IN PTR dns1.javiercruces.org.
2 IN PTR correo.javiercruces.org.
3 IN PTR thor.javiercruces.org.
4 IN PTR hela.javiercruces.org.
200 IN PTR dns2.javiercruces.org.
After saving the changes, reload the BIND configuration:
sudo rndc reload
Or restart the service:
sudo systemctl restart bind9
With this, the master server is authorized to send zones to the slave when necessary.
7. Verifications
Every time you restart the service on dns1
, it will send changes to dns2
. To verify that the zone transfer is working correctly, run the following command on dns2
to view logs in real-time:
debian@dns2:~$ sudo journalctl -u named -f
Then, add a record on the master server:
sentinel IN A 192.168.10.25
You can force the zone transfer with:
debian@dns2:~$ sudo rndc sync
And the logs of a successful transfer will look like this:
debian@dns2:~$ sudo journalctl -u named -f
May 10 23:11:08 dns2 named[936]: received control channel command 'sync'
May 10 23:11:08 dns2 named[936]: dumping all zones: success
Finally, perform a query to both servers to verify that both return the same result:
debian@cliente1:~$ dig @192.168.10.1 sentinel.javiercruces.org
; <<>> DiG 9.18.33-1~deb12u2-Debian <<>> @192.168.10.1 sentinel.javiercruces.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31484
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 067375f875fc084c01000000681fdf328945678dcc84fea2 (good)
;; QUESTION SECTION:
;sentinel.javiercruces.org. IN A
;; ANSWER SECTION:
sentinel.javiercruces.org. 86400 IN A 192.168.10.25
;; Query time: 0 msec
;; SERVER: 192.168.10.1#53(192.168.10.1) (UDP)
;; WHEN: Sat May 10 23:20:18 UTC 2025
;; MSG SIZE rcvd: 98
debian@cliente1:~$ dig @192.168.10.200 sentinel.javiercruces.org
; <<>> DiG 9.18.33-1~deb12u2-Debian <<>> @192.168.10.200 sentinel.javiercruces.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 29032
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 4fd30029eb8c1f3d01000000681fdf34b473e093120ca15c (good)
;; QUESTION SECTION:
;sentinel.javiercruces.org. IN A
;; AUTHORITY SECTION:
javiercruces.org. 86400 IN SOA dns1.javiercruces.org. root.javiercruces.org. 1 604800 8
6400 2419200 86400
;; Query time: 0 msec
;; SERVER: 192.168.10.200#53(192.168.10.200) (UDP)
;; WHEN: Sat May 10 23:20:20 UTC 2025
;; MSG SIZE rcvd: 128