Rate this page

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:

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:

  1. ns1 must be configured to act as a slave nameserver for the zone.
  2. ns1 must be told when to perform a zone transfer. The preferred method for ns0 to send it a notification whenever a transfer is needed.
  3. ns0 must be configured to allow zone transfers to ns1.

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:

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:

  1. Is named is running on ns0 as an authoritative nameserver for example.com?
  2. Is named is running on ns1?
  3. Has ns1 successfully performed an initial zone transfer, and if not why?
  4. Does ns0 notify ns1 when the zone serial number changes?
  5. Does ns1 perform further zone transfers when notified by ns0?

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:

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:

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:

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.

Tags: bind | dns