(new Soapbox())->shout(array_map('strtoupper', $opinions)); //Shaun's blog

Me, elsewhere

Miscellaneous public code

A PHP API client for Reddit

I don't tweet much

XMPP chat
(Pidgin, Miranda, Swift, etc.)

Perfect is the enemy of good enough.

Building a BIND 9.11 DNS server on CentOS 6

Posted February 03, 2017 by shaun

This article outlines the deployment of a recursive, caching, authoritative DNS server running BIND 9.11.29 on CentOS 6.10. Why this combination? The BIND name server is the most feature-rich open source resolver, with decades of development behind it. And despite closing in on its nominal end-of-life, CentOS 6 remains a popular server OS due to its proven stability and the absence of systemd.

Preparing your environment

In order to set up your DNS server, you're going to need:

  • A server running CentOS 6.10 (bare metal, VM, or VPS will all work)
  • root ssh access to your server
  • At least 64MB of available RAM for the named process
  • wget or some other utility to download a file

There are also some software dependencies:

  • The gcc compiler (yum -y install gcc)
  • The file utility (yum -y install file)
  • OpenSSL header files (yum -y install openssl-devel)

You don't necessarily need to devote a whole server specifically to DNS. It's common to have a resolver running on a mail server, web server, RADIUS server, etc. If you run into memory or CPU pressure from your DNS query volume, you can always move the service later.

This guide assumes that SELinux enforcement has been disabled on the target system.

Downloading BIND 9.11

Software bundled for CentOS 6 via the yum package manager often lags a generation or two behind the current release. This is true for BIND; the latest version available through yum is 9.8.2. We're going to use a more modern version, 9.11, which offers numerous improvements over the 9.8 branch (feature matrix). 9.11 is the current stable extended-support version, or ESV, recommended for production use.

Since BIND 9.11 isn't available in yum, it's necessary to download and compile it yourself.

First, find or create a location on your server's filesystem where you can compile the source code and optionally keep it around in case you need it later. I typically make a directory named /home/files to hold the software distributions I build manually. Whatever location you pick, go ahead and cd to that directory.

Next, download the latest ESV distribution of BIND. You can check ISC's downloads page to find it (click on "BIND" and look for "Current-Stable, ESV"). At the time this post was last updated, 9.11.29 is the correct version. BIND source packages follow a consistent naming pattern, so you can substitute any version number into the URL below.

[root@host /home/files]# wget https://ftp.isc.org/isc/bind9/9.11.29/bind-9.11.29.tar.gz
  (11.2 MB/s) - `bind-9.11.29.tar.gz' saved [8297010/8297010]

If you have gpg installed, it's wise to verify the signature of the downloaded file.

Configuring the installer

Extract the source tarball and enter the source directory.

[root@host /home/files]# tar xzf bind-9.11.29.tar.gz
[root@host /home/files]# cd bind-9.11.29
[root@host /home/files/bind-9.11.29]#

Next, run the configure script to set up the build environment and enable the capabilities you need.

The generic BIND distribution doesn't follow CentOS 6 path conventions, so you don't want to run a bare ./configure command. The following example sets the system paths to sane values for CentOS 6, and ensures that the most commonly used DNS features are turned on. You can find a full list of options by running ./configure --help.

[root@host /home/files/bind-9.11.29]# ./configure                     \
  --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin                  \
  --sbindir=/usr/sbin --sysconfdir=/etc --localstatedir=/var          \
  --datadir=/usr/share --includedir=/usr/include --libdir=/usr/lib64  \
  --libexecdir=/usr/libexec --sharedstatedir=/var/lib                 \
  --mandir=/usr/share/man --infodir=/usr/share/info --with-libtool    \
  --with-pic --disable-static --disable-isc-spnego --enable-threads   \
  --enable-ipv6 --enable-filter-aaaa --enable-querytrace              \
  --enable-fixed-rrset --enable-rpz-nsip --enable-rpz-nsdname         \
  --with-dlopen=yes --with-dlz-filesystem=yes --without-python

If you encounter errors, it's likely that you're missing one of the dependencies listed in the "Preparing your environment" section, above. When the script finishes, you should see a configuration summary and you're ready to compile.

Compiling and installing BIND

Run make install to compile and install the software.

[root@host /home/files/bind-9.11.29]# make install

Once the installation finishes, several steps must be taken to set up the environment.

First, add a user and a group for BIND. Because the name server daemon is called named, we'll go with that; later on, the init script we create will tell BIND to run as this unprivileged user. On some CentOS 6 installations, you may get a warning that a user called named already exists; that's fine and you can disregard the warning.

[root@host ~]# adduser -r -s /sbin/nologin named
[root@host ~]# groupmems -a named -g named

Now create the filesystem structures where BIND will store its data. Zone files, temporary keys, and ephemeral data will live in /var/named, log files will be written to /var/log/named, and the pidfile will go to /var/run/named.

[root@host ~]# mkdir -p /var/named/{dynamic,data,slaves}
[root@host ~]# wget -O /var/named/named.ca ftp://ftp.internic.net/domain/named.cache
[root@host ~]# chown -R root:named /var/named
[root@host ~]# chmod 770 /var/named
[root@host ~]# chmod -R 770 /var/named/{data,dynamic,slaves}
[root@host ~]# mkdir /var/log/named
[root@host ~]# chown named:named /var/log/named
[root@host ~]# chmod 740 /var/log/named
[root@host ~]# mkdir /var/run/named
[root@host ~]# chown named:named /var/run/named
[root@host ~]# chmod 755 /var/run/named

The wget command in there fetches a copy of the root hints file. This file tells BIND where the root name servers are, providing a bootstrap into the DNS system when the service starts. If you don't have wget, substitute some other command to retrieve this file.

Next, create a file at /etc/sysconfig/named to supply runtime options to the named service. If your server is IPv6-capable, you can just create an empty file. If you're in an IPv4-only environment, use the command below to create a file that (mostly) disables IPv6 features in BIND:

[root@host ~]# cat <<EOF > /etc/sysconfig/named
# Don't try doing IPv6 lookups

Now, add an init script to manage the named service:

[root@host ~]# touch /etc/rc.d/init.d/named
[root@host ~]# chmod 755 /etc/rc.d/init.d/named

Copy the contents of this file into /etc/rc.d/init.d/named

This is the init script that ships with the (older) CentOS 6 BIND RPM. You shouldn't need to make any changes to it.

Configuring bind with the named.conf file

The BIND DNS server is configured through a file called named.conf. Installing BIND manually, as we did, doesn't install this file; it's up to you to create a copy:

[root@host ~]# touch /etc/named.conf
[root@host ~]# chgrp named /etc/named.conf
[root@host ~]# chmod 640 /etc/named.conf

Technically, BIND will run even if this file is empty, but the bare minimum defaults probably won't meet your needs. You need to open named.conf in an editor and set some configuration options.

Copy the contents of this file into /etc/named.conf

This example named.conf, which is thoroughly annotated and ready to use, covers the basic settings for your DNS server:

  • Creates an access control list (ACL) to restrict sensitive operations
  • Allows only trusted hosts to query the server, unless overridden per-zone
  • Sets up the filesystem hierarchy that BIND will use
  • Configures comprehensive, dynamic logging of interesting events
  • Ensures that DNSSEC is enabled with automatic validation

After your server is set up and working, you'll probably want to make some changes to these options. There are dozens of directives you can place in this file to control different aspects of your name server's behavior. Chapter 6 of the BIND 9 Manual is the complete and canonical guide to configuration. There's also some extensive documentation by Zytrax, although it hasn't yet been fully updated for BIND 9.11.

Running BIND

At this point you should be ready to run BIND by starting the named service:

[root@host ~]# service named start
  Starting named:          [  OK  ]

If something goes catastrophically wrong, a reasonably informative error message should appear on the console and you need to address whatever it's complaining about. If the error isn't clear, the system log in /var/log/messages may contain some hints. BIND writes to the system log, instead of to its own log files, before it finishes the startup process.

Once you get the "OK" message, inspect the last 200 or so lines of the system log in /var/log/messages. You should see an indication that BIND has started up, detected its environment, configured some default zones (RFC1918), and has begun listening for DNS queries. You can also look at the various files in /var/log/named to see what BIND is up to.

Finally, with named running, try some test queries to make sure the service functions properly and you're able to get responses:

[root@host ~]# nslookup centos.org

  Non-authoritative answer:
  Name:   centos.org

[root@host ~]# dig +short TXT o-o.myaddr.l.google.com @
  "[server's IP address here]"

Extra considerations...

You probably want BIND to start up automatically whenever the system boots. To accomplish this, run chkconfig named on.

Don't forget to tell your server to use itself for DNS! Edit /etc/resolv.conf and set the nameserver to, removing any other nameserver entries. If this file gets rewritten when your server reboots (and reverts to using some other server), set the nameserver back to the localhost and then render the file immutable with chattr +i /etc/resolv.conf.

If you own a domain and want your BIND server to respond authoritatively for it, you need to create a zone file and tell named.conf where to find it. Zone file configuration is beyond the scope of this article, but here's an example zone file from the Fedora documentation. You'll also need to update your domain registration to point at your new DNS server, and add "glue" records for it; both of these tasks must be done through your registrar.

Occasionally, one of the root server IP addresses will change and a new version of the root hints file is published. If you like, you can set up a cron job to download a fresh copy (wget -O /var/named/named.ca ftp://ftp.internic.net/domain/named.cache) on a monthly basis. This isn't a necessary task; as long as any one of the root hints in your file is valid, BIND will connect to it and learn the current IPs of the other root servers.

Updated Mar 18, 2021 to reference BIND version 9.11.29 as the latest ESV.

Recent articles

📰 curl 7.74.0 regression breaks Smokeping probes

📰 chrony improves client stats output for easier abuse detection

📰 Resolving PHP error "Fatal error: strict_types declaration must not use block mode"

📰 Resolving "Not using downloaded repomd.xml because it is older than what we have" yum error

📰 Resolving subversion error E125001: Couldn't determine absolute path of '.'

📰 Caveat with Vantec SATA/IDE to USB 2.0 Adapter and Macrium software

📰 Jay Niffley, Man of Mystery

📰 Multi-protocol scanning activity from Amazon GovCloud

📰 Compiling Doxygen on FreeBSD without LaTeX and Ghostscript

📰 Introducing Snuze, a PHP client for the Reddit API

📰 jisusaiche: Java's installer telemetry

📰 BIND client log error "query_find: query_getdb failed"

📰 Resolving "The lang/perl5.24 port has been deleted: Has expired" portmaster error

📰 Armagaddon2 interim fix for Firefox 56 and other old versions

📰 Strange DNS queries: qname "miep", qtype ANY

▲ Back to top | Permalink to this page