Configure BIND as a slave DNS server
Tested on |
Debian (Lenny) |
Ubuntu (Lucid, Maverick) |
Objective
To configure BIND to act as a slave DNS server for a given zone
Background
A nameserver running BIND can be configured to serve each zone as either a master or a slave:
- A slave obtains its copy of the zone data by means of a zone transfer from another nameserver.
- A master obtains zone data from some other source, allowing it to operate independently of other nameservers.
Every zone should have at least two nameservers. Typical practice is to have one master, and one or two slaves which take their zone data from that master. These instructions describe how to configure the slaves.
Scenario
Suppose that the zone example.com
has two nameservers, ns0.example.com
(198.51.100.1) and ns1.example.com
(203.0.113.1). Of these, ns0
is already configured as a master. You wish to configure ns1
as a slave, taking its zone data from ns0
.
Both nameservers are running BIND version 9.
File locations
On Debian-based systems, zone declarations should be placed in the file /etc/bind/named.conf.local
and options in the file /etc/bind/named.conf.options
. You should not modify /etc/bind/named.conf
. Slave zone files should be placed in /var/lib/bind
(not /etc/bind
) so that named
has permission to write to them. Log messages are written to /var/log/daemon.log
.
Method
Overview
There are three points to address if ns1
is to act as a slave to ns0
:
-
ns1
must be configured to act as a slave nameserver for the zone. -
ns1
must be told when to perform a zone transfer. The preferred method forns0
to send it a notification whenever a transfer is needed. -
ns0
must be configured to allow zone transfers tons1
.
For most purposes the default configuration of BIND would satisfy points 2 and 3, however it is good practice to configure it explicitly if you intend to rely on its behaviour.
Add a slave zone declaration to ns1
The named
configuration file must include a zone declaration for each zone to be served. Here is a suitable declaration for the zone example.com
on ns1
:
zone "example.com" { type slave; masters { 198.51.100.1; }; file "/var/lib/bind/db.example.com"; };
Setting the type
to slave
specifies that the zone data is obtained from another nameserver.
The masters
statement contains a list of nameservers from which zone data can be obtained. These need not be masters in the sense defined above: it is possible (and sometimes necessary) for a slave to obtain zone data from another slave. Masters must be specified as IP addresses, not as domain names, however it is possible to define a ‘masters list’ containing the required addresses which can then be referred to symbolically (see below).
Zone files are optional for slave nameservers, but strongly recommended otherwise the slave will lose all knowledge of the zone content whenever it is restarted. It will not then be able to start serving the zone again until it has performed a zone transfer, and if the master is unavailable for any reason then the period of downtime could be substantial.
Ensure that notifications from ns0 are enabled
There are two ways to control when zone transfers take place:
- by polling at regular intervals, or
- by having the master notify the slave when the zone has changed.
The latter method is preferred as it is both quicker and more efficient. BIND sends notifications by default, however it is good practice to enable them explicitly if they are an important part of the configuration. This can be done for individual zones:
zone "example.com" { type master; file "/var/lib/bind/db.example.com"; notify yes; // ... };
or as the default for all zones:
options { notify yes; // ... };
The setting for a zone takes precedence, therefore if you use the latter method then you should check that it has not been overridden.
The master needs to know which nameservers to notify. By default it notifies the ones that have NS
records, which for most purposes is sufficient. Nameservers that do not have NS
records can be notified by adding an also-notify
statement. As previously this can be done either for an individual zone:
zone "example.com" { type master; notify yes; also-notify { 203.0.113.1; }; file "/var/lib/bind/db.example.com"; };
or as the default for all zones:
options { notify yes; also-notify { 203.0.113.1; }; // ... };
Ensure that ns0 allows zone transfers
By default BIND allows zone transfers from anywhere. Opinion is divided as to whether this is good practice, and it is not unusual for a more restrictive policy to be imposed. The servers that are allowed to perform transfers are specified in an allow-transfer
statement. As with notifications this can be done either for an individual zone:
zone "example.com" { type master; notify yes; allow-transfer { 203.0.113.1; }; file "/var/lib/bind/db.example.com"; };
or as the default for all zones:
options { notify yes; allow-transfer { 203.0.113.1; }; // ... };
If you are content for zone transfers to be unrestricted then you can make this explicit using an address of any
:
options { notify yes; allow-transfer { any; }; // ... };
Reload the configuration of named on ns0
If the configuration of ns0
has been changed in any way then it should be reloaded. See Cause a system service to reload its configuration.
Reload the configuration of named on ns1
The configuration of ns1
will have changed, so it will certainly need to be reloaded. This should be the last thing that you do (after reloading ns0
if necessary). Again, see Cause a system service to reload its configuration.
Testing
Check that ns1 is serving the zone
You can test whether ns1
is operational by using the dig
command to request the statement of authority record for the zone in question:
dig @203.0.113.1 -t SOA example.com +norecurs
The +norecurs
flag at the end of the command instructs dig
to perform a non-recursive query. The answer should be similar to the following:
;; ANSWER SECTION: example.com. 86400 IN SOA example.com. hostmaster.example.com. 41 28800 7200 604800 86400
Receiving the correct answer indicates that ns1
is functioning as a nameserver, but not necessarily that it is a slave for example.com
: the answer could have been cached from a previous recursive query. To tell the difference you should inspect the flags that are displayed near the start of the response:
;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42311 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 2
The aa
flag is the significant one. If ns1
is operating as a slave then the aa
flag will be present, meaning that the answer is authoritative.
Check that notifications are working
The initial zone transfer is not dependent on notifications, but subsequent ones are (unless you intend to rely on polling). To test whether they are working you will need to modify the zone on ns0
and check whether the change is replicated on ns1
. The least invasive change you can make is to increment the serial number.
Edit the zone file on ns0
and locate the SOA record. This should look similar to:
@ IN SOA example.com. hostmaster.example.com. ( 41 8H 2H 1W 1D)
The serial number in this record is 41, therefore you should increment it to 42:
@ IN SOA example.com. hostmaster.example.com. ( 42 8H 2H 1W 1D)
Now reload the configuration of named
on ns0
(see Cause a system service to reload its configuration). ns0
should notify ns1
that it has a copy of the zone with a serial number of 42. The copy of the zone held by ns1
has an older serial number, 41, so when it receives the notification it should request a zone transfer. You can determine whether this has happened by re-requesting the SOA record:
dig @203.0.113.1 -t SOA example.com +norecurs
If the serial number has changed to 42 then a zone transfer has occurred, which probably means that notifications are working:
;; ANSWER SECTION: example.com. 86400 IN SOA example.com. hostmaster.example.com. 42 28800 7200 604800 86400
(For additional confidence that a notification caused the transfer you can either repeat the test or inspect the logs.)
Troubleshooting
Strategy
If the tests described above indicate that ns1
is not functioning as intended then you should attempt to answer the following questions:
- Is
named
is running onns0
as an authoritative nameserver forexample.com
? - Is
named
is running onns1
? - Has
ns1
successfully performed an initial zone transfer, and if not why? - Does
ns0
notifyns1
when the zone serial number changes? - Does
ns1
perform further zone transfers when notified byns0
?
Questions 1 to 3 are relevant when ns1
is not working as a nameserver at all. Questions 4 and 5 are relevant when it is working, but not responding to updates.
Check whether named is running on ns0
Before looking at ns1
it would be prudent to check that ns0
is working. A good way to do this is to perform a remote query from ns0
to ns1
concerning the zone you are attempting to serve:
dig @198.51.100.1 -t SOA example.com
This should give an answer similar to the following:
;; ANSWER SECTION: example.com. 86400 IN SOA example.com. hostmaster.example.com. 41 28800 7200 604800 86400
The aa
flag should be set, indicating that this is an authoritative response:
;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 13518 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 2
If either of these are missing then that would indicate ns0
is running as a nameserver, but is not authoritative for example.com
. The absence of any response at all could indicate that there is no nameserver running on ns0
, or that there is a problem with network connectivity. Whatever the reason, it will need to be addressed before the slave nameserver on ns1
can be properly tested.
Check whether named is running on ns1
You can check whether named
is running using the ps
command:
ps -C named
This should give a response of the form:
PID TTY TIME CMD 11409 ? 00:00:00 named
If no process is listed then you should try restarting named
, then check again using ps
. If it does not start then this may indicate that:
- there is a syntax error in one of the configuration files, or
- another process is listening on port 53.
The first of these is the more likely explanation. The log should contain enough information to identify the cause.
Check whether ns1 has successfully performed initial zone transfer
You can check whether an initial zone transfer has occurred by looking for the zone file. This is the argument to the file
statement in the zone declaration:
zone "example.com" { type slave; masters { 198.51.100.1; }; file "/var/lib/bind/db.example.com"; };
The file should have been created by named
, and have content equivalent to (but probably not identical to) the master zone file on ns0
.
If it has not been written then this could be because:
-
ns1
has not requested a zone transfer, or -
ns1
sent the request to the wrong nameserver, or -
ns1
cannot communicate withns1
, or -
ns0
refused to transfer the zone, or -
ns1
received the zone data, but was unable to write the file.
You can check the first four points by viewing DNS traffic to and from ns1
using tcpdump
:
tcpdump -n "host ns1.example.com and (udp port 53 or tcp port 53)"
You should see an initial query for the SOA record (normally UDP), followed by the zone transfer (always TCP).
If ns0
refused to transfer the zone then this should be recorded in the log on ns0
, for example:
client 203.0.113.1#42541: zone transfer 'example.com/AXFR/IN' denied
If the transfer occurred but the file could not be written then this should be recorded in the log on ns1
, for example:
dumping master file: /etc/bind/tmp-nIOVHD85JX: open: permission denied
(See below for further consideration of these errors.)
Check whether ns0 notifies ns1 when the zone serial number changes
You can check whether ns0
is notifying ns1
by using tcpdump
to view the traffic:
tcpdump -n "host ns1.example.com and (udp port 53 or tcp port 53)"
A notification should look similar to:
198.51.100.1.3278 > 203.0.113.1.53: 62737 notify [b2&3=0x2400] [1a] SOA? example.com. (95) 203.0.113.1.53 > 198.51.100.1.3278: 62737 notify* 0/0/0 (29)
Notifications should also be logged by the sender:
zone example.com/IN: sending notifies (serial 42)
and by the receiver:
client 198.51.100.1#3278: received notify for zone 'example.com'
If notifications are not being sent or logged then you should check that they are enabled for the zone in question, and that ns1
is either:
- listed as a nameserver using an
NS
record in the master zone file, or - listed in a
also-notify
statement in the master zone declaration.
Check whether ns1 performs further zone transfers when notified
Subsequent zone transfers can be viewed in the same way as the initial transfer, but may be considerably smaller if you have enabled the use of incremental transfers.
The most likely reason for the slave not requesting a transfer when it has received a notification is if it already has a copy of the zone with the same or a more recent serial number. In that case you should advance the serial number of the master zone file until it is greater than that of the slave zone file.
Errors
Zone transfer denied
An error of the form:
client 203.0.113.1#42541: zone transfer 'example.com/AXFR/IN' denied
on ns0
indicates that zone transfers have been restricted to a specific list of nameservers and that ns1
is not one of them. You should look for a relevant allow-transfer
statement in the configuration of ns0
and add ns1
to the list.
Dumping master file: permission denied
An error of the form:
dumping master file: /etc/bind/tmp-nIOVHD85JX: open: permission denied
on ns1
indicates that named
has successfully performed a zone transfer, but was unable to write the result to a zone file because it did not have permission to write to the relevant directory.
In this particular case it has been incorrectly configured to write the zone file to /etc/bind
. You should not attempt to fix this by granting write access to that directory: there are good security reasons why named
should only have read access to its configuration. Instead you should write the zone file to some other location. On Debian-based systems, the appropriate location is /var/lib/bind
.
Variations
Use a masters list
If it is necessary to refer to the same master nameserver(s) repeatedly then it is good practice to define a ‘masters list’ containing the relevant IP address(es) so that they can be referred to symbolically. For example:
masters ns0 { 198.51.100.1; }; zone "example.com" { type slave; masters { ns0; }; notify no; file "/var/lib/bind/zone.example.com"; }; zone "example.net" { type slave; masters { ns0; }; notify no; file "/var/lib/bind/zone.example.net"; };
Doing this reduces the risk of specifying the wrong IP address, and simplifies the task of changing the address should this ever be necessary.