DNS or Domain Name System is one of the most important building blocks of the modern IT and internet. DNS allows you to use meaningful names instead of IP addresses. Especially since IPv6 is getting more popular, DNS remains a very important part of your network. This article will describe how to set up a basic master DNS-server and a slave which will replicate the data from the master.
Why a master and a slave
No single system or installation has a perfect 100% uptime and since DNS can be a quite critical component of your network, it is recommended to have a secondary DNS to provide a backup in case the primary one fails. You could simply set up two equal DNS-servers which have the same configuration and data. While this would perfectly work, it would require you to do all changes two times. Once on the primary and once on the secondary.
By setting up one server as the master and the other as the slave, the slave will replicate it’s zone-data from the master to itself. This way, when making changes in some zone on the master, the slave gets notified and takes over the changes almost instantly without the need to do any configuration on the slave’s side.
The master
The example will be done with CentOS 7 but the syntax of the commands should be equal for almost all Linux and Unix variants since Bind is quite universal.
We will start by configuring a single master DNS. The IP of the machine which will be the master is 192.168.202.101.
The first step is to install bind and bind-utils:
[jensd@master ~]$ sudo yum install bind bind-utils ... Complete!
After the installation, perform a basic bind configuration by adjusting the sample configuration file in /etc/named.conf. We will also add two test zones.
/etc/named.conf on the master:
options { listen-on port 53 { 127.0.0.1; 192.168.202.101;}; #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"; memstatistics-file "/var/named/data/named_mem_stats.txt"; allow-query { any;}; recursion no; dnssec-enable no; dnssec-validation no; dnssec-lookaside auto; bindkeys-file "/etc/named.iscdlv.key"; managed-keys-directory "/var/named/dynamic"; pid-file "/run/named/named.pid"; session-keyfile "/run/named/session.key"; }; logging { channel default_debug { file "data/named.run"; severity dynamic; }; }; zone "blaat.test" { type master; file "/var/named/data/db.blaat.test"; check-names fail; allow-update { none; }; allow-query { any; }; }; zone "miauw.test" { type master; file "/var/named/data/db.miauw.test"; check-names fail; allow-update { none; }; allow-query { any; }; }; zone "." IN { type hint; file "named.ca"; }; include "/etc/named.rfc1912.zones"; include "/etc/named.root.key";
The above file differs from the supplied example on the following lines:
2: added this machines IP address
3: commented the line since we don’t do anything with IPv6 here
8: allow querying from everywhere
9: disable recursion by default (you don’t want this on a public DNS)
10+11: disable DNSsec
24-30: a test zone called “blaat.test”
31-37: a test zone called “miauw.test”
In the configuration file, we specified that the data for the zones can be found in the files /var/named/data/db.miauw.test and /var/named/data/db.blaat.test. We need to create those files and enter some zone-data:
/var/named/data/db.blaat.test:
@ IN SOA ns.blaat.test admin.blaat.test. ( 2014082201 ; serial 1D ; refresh 1H ; retry 1W ; expire 3H ) ; minimum @ NS ns.blaat.test. ns IN A 192.168.202.101 blaat.test. IN A 192.168.202.1 host1.blaat.test. IN A 192.168.202.10
/var/named/data/db.miauw.test
@ IN SOA ns.miauw.test admin.miauw.test. ( 2014082201 ; serial 1D ; refresh 1H ; retry 1W ; expire 3H ) ; minimum @ NS ns.miauw.test. ns IN A 192.168.202.101 miauw.test. IN A 192.168.202.1 host1.miauw.test. IN A 192.168.202.10
After performing the above steps, we can verify if the syntax in our configuration and zone files is correct before starting the service.
[jensd@master ~]$ sudo named-checkconf /etc/named.conf [jensd@master ~]$ sudo named-checkzone blaat.test /var/named/data/db.blaat.test /var/named/data/db.blaat.test:1: no TTL specified; using SOA MINTTL instead zone blaat.test/IN: loaded serial 2014082201 OK [jensd@master ~]$ sudo named-checkzone miauw.test /var/named/data/db.miauw.test /var/named/data/db.miauw.test:1: no TTL specified; using SOA MINTTL instead zone miauw.test/IN: loaded serial 2014082201 OK
In the above example, the syntax seems to be ok so we can start the master:
[jensd@master ~]$ sudo systemctl start named
When all goes well and we don’t receive any warning messages, we can test our freshly created master DNS-server:
[jensd@master ~]$ nslookup blaat.test localhost Server: localhost Address: 127.0.0.1#53 Name: blaat.test Address: 192.168.202.1 [jensd@master ~]$ nslookup miauw.test localhost Server: localhost Address: 127.0.0.1#53 Name: miauw.test Address: 192.168.202.1
Adding zone data
When information is changed for a certain zone, we can simply edit the relevant zone file and update the serial in that file. After checking the syntax, a reload makes sure that the server will reply with the newly provided information.
Edit /var/named/data/db.miauw.test to test updating. Don’t forget to update the serial on the second line:
@ IN SOA ns.miauw.test admin.miauw.test. ( 2014082202 ; serial 1D ; refresh 1H ; retry 1W ; expire 3H ) ; minimum @ NS ns.miauw.test. ns IN A 192.168.202.101 miauw.test. IN A 192.168.202.1 host1.miauw.test. IN A 192.168.202.10 host2.miauw.test. IN A 192.168.202.20
Now, check the syntax, reload the zone-information and test the newly added information:
[jensd@master ~]$ sudo vi /var/named/data/db.miauw.test [jensd@master ~]$ sudo named-checkzone miauw.test /var/named/data/db.miauw.test /var/named/data/db.miauw.test:1: no TTL specified; using SOA MINTTL instead zone miauw.test/IN: loaded serial 2014082202 OK [jensd@master ~]$ sudo systemctl reload named [jensd@master ~]$ nslookup host2.miauw.test 192.168.202.101 Server: 192.168.202.101 Address: 192.168.202.101#53 Name: host2.miauw.test Address: 192.168.202.20
Add a slave DNS to the master
Now that our master is fine, it’s time to add a slave DNS-server to the master.
The slave will be running on another machine. In our example, the slave’s IP address will be 192.168.202.102.
Like with the master, we need to install bind on the slave too:
[jensd@slave ~]$ sudo yum install bind bind-utils ... Complete!
After installation, we need to configure the slave’s /etc/named.conf to behave as a slave for the previously configured master.
/etc/named.conf on the slave:
options { listen-on port 53 { 127.0.0.1; 192.168.202.102;}; #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"; memstatistics-file "/var/named/data/named_mem_stats.txt"; allow-query { any;}; recursion no; dnssec-enable no; dnssec-validation no; dnssec-lookaside auto; bindkeys-file "/etc/named.iscdlv.key"; managed-keys-directory "/var/named/dynamic"; pid-file "/run/named/named.pid"; session-keyfile "/run/named/session.key"; }; logging { channel default_debug { file "data/named.run"; severity dynamic; }; }; zone "blaat.test" { type slave; file "/var/named/data/db.blaat.test"; masters { 192.168.202.101; }; check-names fail; allow-update { none; }; allow-query { any; }; }; zone "miauw.test" { type slave; file "/var/named/data/db.miauw.test"; masters { 192.168.202.101; }; check-names fail; allow-update { none; }; allow-query { any; }; }; zone "." IN { type hint; file "named.ca"; }; include "/etc/named.rfc1912.zones"; include "/etc/named.root.key";
As you can see, the configuration is quite similar in comparison with the master. The slave’s configuration also contains the same zones as on the master and they are configured as type slave. Zone files don’t need to be created since they should be replicated from the master.
In order to let the master notify the slave when a zone is updated and to allow the zone transfers, we need to add the following lines to the master’s /etc/named.conf in the options{}-section:
notify yes; also-notify { 192.168.202.102; }; allow-transfer { 127.0.0.1; 192.168.202.102; };
The next step is to reload the configuration at the master, since we changed it and to start the slave:
[jensd@master ~]$ sudo named-checkconf /etc/named.conf [jensd@master ~]$ sudo systemctl reload named
[jensd@slave ~]$ sudo systemctl start named
If all goes well, the slave should have replicated the zone information from the master and created it’s zone files on the location that was specified in /etc/named.conf on the slave.
[jensd@slave ~]$ sudo ls -l /var/named/data total 12 -rw-r--r--. 1 named named 294 Aug 22 15:51 db.blaat.test -rw-r--r--. 1 named named 294 Aug 22 15:51 db.miauw.test -rw-r--r--. 1 named named 1074 Aug 22 15:51 named.run
By looking at /var/named/data/named.run on the slave, you can see that the data was transferred from the master.
[jensd@slave ~]$ sudo tail /var/named/data/named.run zone blaat.test/IN: Transfer started. transfer of 'blaat.test/IN' from 192.168.202.101#53: connected using 192.168.202.102#34291 zone blaat.test/IN: transferred serial 2014082201 transfer of 'blaat.test/IN' from 192.168.202.101#53: Transfer completed: 1 messages, 6 records, 191 bytes, 0.001 secs (191000 bytes/sec) zone blaat.test/IN: sending notifies (serial 2014082201) zone miauw.test/IN: Transfer started. transfer of 'miauw.test/IN' from 192.168.202.101#53: connected using 192.168.202.102#39349 zone miauw.test/IN: transferred serial 2014082201 transfer of 'miauw.test/IN' from 192.168.202.101#53: Transfer completed: 1 messages, 6 records, 191 bytes, 0.001 secs (191000 bytes/sec) zone miauw.test/IN: sending notifies (serial 2014082201)
To be sure that our slave DNS-server contains the correct data, we can do a query using that server:
[jensd@master ~]$ nslookup host1.blaat.test 192.168.202.101 Server: 192.168.202.101 Address: 192.168.202.101#53 Name: host1.blaat.test Address: 192.168.202.10 [jensd@master ~]$ nslookup host2.miauw.test 192.168.202.101 Server: 192.168.202.101 Address: 192.168.202.101#53 Name: host2.miauw.test Address: 192.168.202.20
Test replication from the master to the slave
To be completely sure that data flows from the master to the slave and that the slave is notifies when a zone is updated on the master, we can simply update a zone and see if the data is available on the slave:
Update the zone in /var/named/data/db.blaat.test (don’t forget about the serial):
@ IN SOA ns.blaat.test admin.blaat.test. ( 2014082202 ; serial 1D ; refresh 1H ; retry 1W ; expire 3H ) ; minimum @ NS ns.blaat.test. ns IN A 192.168.202.101 blaat.test. IN A 192.168.202.1 host1.blaat.test. IN A 192.168.202.10 host2.blaat.test. IN A 192.168.202.20
Check the syntax and reload the zone configuration:
[jensd@master ~]$ sudo vi /var/named/data/db.blaat.test [jensd@master ~]$ sudo named-checkzone blaat.test /var/named/data/db.blaat.test /var/named/data/db.blaat.test:1: no TTL specified; using SOA MINTTL instead zone blaat.test/IN: loaded serial 2014082202 OK [jensd@master ~]$ sudo systemctl reload named
After reloading the zone on the master, check if the data is automatically transferred to the slave:
[jensd@slave ~]$ sudo tail /var/named/data/named.run ... client 192.168.202.101#18736: received notify for zone 'blaat.test' zone blaat.test/IN: Transfer started. transfer of 'blaat.test/IN' from 192.168.202.101#53: connected using 192.168.202.102#50604 zone blaat.test/IN: transferred serial 2014082202 transfer of 'blaat.test/IN' from 192.168.202.101#53: Transfer completed: 1 messages, 7 records, 213 bytes, 0.001 secs (213000 bytes/sec) zone blaat.test/IN: sending notifies (serial 2014082202) [jensd@slave ~]$ nslookup host2.blaat.test 192.168.202.102 Server: 192.168.202.102 Address: 192.168.202.102#53 Name: host2.blaat.test Address: 192.168.202.20
This should be all you need to create a simple master and slave DNS-server with Bind.
Pingback: Getting Started with the BIND DNS Server
Nice, thanks for the tutorial
Agree, very good tutorial!