User Tools

Site Tools



We run a caching name server on all our servers. This speeds up name lookups, and reduces network load to external name servers a bit.

On some servers, we also serve DNS for several domains to the outside world. We use BuddyNS as our secondary servers; they use AXFR to transfer changes to our domains.

We decided to use BIND 9, as it is popular and well supported. BIND 9 was completely rewritten with security in mind, and so it seems to have a lot fewer security issues than BIND 4 and BIND 8 did. We decided to put BIND into a chroot jail, as it's pretty simple to do and well-documented. This will protect us from most BIND and DNS exploits that do turn up.


First, install the required packages:

sudo apt-get install bind9 bind9utils bind9-doc dnsutils

Debian automatically starts the daemon, but we're going to change a lot of its config, so we should stop the daemon until we're done:

sudo /etc/init.d/bind9 stop

Next build out /var/lib/bind/chroot to contain enough so that bind9 can run chrooted within it:

sudo mkdir -p /var/lib/bind/chroot/{etc,dev,var/cache/bind,var/run/named}
sudo mknod /var/lib/bind/chroot/dev/null c 1 3
sudo mknod /var/lib/bind/chroot/dev/random c 1 8
sudo chmod 660 /var/lib/bind/chroot/dev/{null,random}
sudo chmod 775 /var/lib/bind/chroot/var/{cache/bind,run/named}
sudo chown -R bind:bind /var/lib/bind/chroot/{etc,var/*,dev}
sudo rm -rf /var/run/named /var/cache/bind
sudo ln -s /var/lib/bind/chroot/var/run/named /var/run/named
sudo ln -s /var/lib/bind/chroot/var/cache/bind /var/cache/bind


Copy the configuration into the chroot directory, and link back to the original locations, so we can update the configuration from the original config-file location:

sudo mv /etc/bind /etc/bind.dist
sudo cp -a /etc/bind.dist /var/lib/bind/chroot/etc/bind
sudo ln -s /var/lib/bind/chroot/etc/bind /etc/bind

Next edit /etc/default/bind9 to tell it to start up chrooted to /var/lib/bind9/chroot:

sudo sed -i -e 's|OPTIONS="-u bind"|OPTIONS="-u bind -t /var/lib/bind/chroot"|' /etc/default/bind9

Edit /etc/bind/named.conf.options and tell it which interfaces to listen on, and who to forward requests to if we don't have the answer cached. We also include names for a few backup forwarders, in case we decide to use them at a later date.

acl loopback        {;};                   # The "localhost" ACL is pre-defined, but includes all interfaces.
acl external_subnet {;};
acl buddyns         {;;;};            # Allow AXFR to these addresses for BuddyNS to provide secondary/authoritative DNS for us.
acl opendns         {;;};                          # OpenDNS public DNS servers.
acl verizon_dns     {;;;;;;};    # Verizon public DNS servers. 

options {
    directory "/var/cache/bind";
    listen-on {loopback; external_subnet;};         # Listen on loopback interface (for DNS caching), plus any interface on our external subnet (for queries and transfers).
    forwarders {;;};   # Forward queries here, unless we're authoritative. (Cannot use named ACLs here.)
    allow-transfer {buddyns; localhost;};           # Allow AXFRs to BuddyNS (so they can mirror us), and all local interfaces (for testing).
    auth-nxdomain no;                               # Conform to RFC1035.
    version none;                                   # Don't publicize our version number.

For caching-only servers, remove the external_subnet from listen-on, and remove the allow-transfer line.


To get logging out of the chroot jail, we need to set up a socket within the jail, and have the syslog daemon listen to it.

Since Debian 5+ uses rsyslog, we simply had to find the config option that would listen on an additional UNIX socket:

sudo sh -c 'echo "\$AddUnixListenSocket /var/lib/bind/chroot/dev/log" > /etc/rsyslog.d/bind9.conf'

Then restart the logging daemon:

sudo /etc/init.d/rsyslog restart


Start the named server:

sudo /etc/init.d/bind9 start

If startup fails, tail the /var/log/syslog file to look for errors. The most likely error is forgetting a semi-colon somewhere in the config file.

Client Configuration

Edit /etc/resolv.conf to tell clients to use localhost to resolve DNS names. Again, we include a few other name servers just as documentation.

DOMAIN=$(hostname -d)
sudo sh -c 'cat > /etc/resolv.conf' <<EOF
domain $DOMAIN
#nameserver # OpenDNS public DNS server
#nameserver 208.67.222 .222 # OpenDNS public DNS server

We also need to delete any dns-* lines from /etc/network/interfaces, as they cause /etc/resolv.conf to be updated when the interface comes up.

sudo sed -i /etc/network/interfaces -e '/^.*dns-.*/d'


Run nslookup and/or dig to resolve some DNS names. Make sure you get answers back from

Run some client programs to make sure they are resolving host names properly.

Check /var/log/daemon.log and /var/log/syslog for startup/shutdown info from the bind9 daemon.

Run sudo rndc status to check the status of the server.

Run sudo rndc stats and then read /var/cache/bind/named.stats to get server stats, including number of successful and failed DNS lookups.


The OpenDNS servers are publicly available for anyone to use. It probably doesn't make sense to use them on a server though, because they send unknown addresses to their own servers. Their servers contain search pages for web access; I'm not sure what happens with other services.

The 4.2.2.x addresses are supposedly Verizon's publicly-available DNS server that anyone can use.


We should probably hit the root servers instead of forwarding to OpenDNS. Or forward to the DNS servers provided by our ISP.


Details using BIND under chroot is available on the Debian Wiki page on BIND, as well as the Bind-Chroot-Howto for Debian on HowtoForge.

build/dns.txt · Last modified: 2012/12/10 22:41 (external edit)