DNS setup with bind on CentOS 7

Maybe you need a private DNS server on an internal network or maybe you just want to learn more about DNS. Setting up a pair of DNS servers is not too complicated and can be useful in certain situations.

This guide will outline how to setup 2 DNS servers, one being the primary and the other being the secondary DNS server on CentOS 7. This guide will make use of the following servers:

dns01.example.com (192.168.1.101) - Primary DNS server
dns02.example.com (192.168.1.102) - Secondary DNS server

Before beginning, make sure you have the latest updates on both servers by running:

[root@dns01 ~]# yum update
[root@dns01 ~]# reboot

Primary DNS server setup

First, install bind by running:

[root@dns01 ~]# yum install bind bind-utils

There are a couple key settings that need to be customized to fit your needs:

- trusted-recursion : Which IP's or subnets you want to allow inbound to perform lookups.
- forwarders : Specify a pair of DNS servers to act of forwarders.  
- zonefile : Setup your zonefiles

The instructions below will create a new named.conf with the following setup:

- trusted-recursion from 192.168.1.0/24
- forwarders : Will use google's DNS servers, 8.8.8.8 and 8.8.4.4
- zonefile : We will be setting up example.com and allow zone transfers to dns02.example.com (192.168.1.102).  We'll also be setting reverse DNS.

Adjust the settings to meet your environments needs accordingly. The primary fields to change will be in bold below:

[root@dns01 ~]# mv /etc/named.conf /etc/named.conf.orig 
[root@dns01 ~]# vim /etc/named.conf
//
// named.conf
//
// Provided by Red Hat bind package to configure the ISC BIND named(8) DNS
// server as a caching only nameserver (as a localhost DNS resolver only).
//
// See /usr/share/doc/bind*/sample/ for example named configuration files.
//
// See the BIND Administrator's Reference Manual (ARM) for details about the
// configuration located in /usr/share/doc/bind-{version}/Bv9ARM.html

acl "trusted-recursion" {
        localhost;
        localnets;
        192.168.1.0/24;
};


options {
        listen-on port 53 { any; };
        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; };
        allow-recursion { trusted-recursion; };
        allow-query-cache { trusted-recursion; };
        /*
         - If you are building an AUTHORITATIVE DNS server, do NOT enable recursion.
         - If you are building a RECURSIVE (caching) DNS server, you need to enable
           recursion.
         - If your recursive DNS server has a public IP address, you MUST enable access
           control to limit queries to your legitimate users. Failing to do so will
           cause your server to become part of large scale DNS amplification
           attacks. Implementing BCP38 within your network would greatly
           reduce such attack surface
        */
        /* recursion yes; */

        dnssec-enable yes;
        dnssec-validation no;

        /* Path to ISC DLV key */
        bindkeys-file "/etc/named.iscdlv.key";

        managed-keys-directory "/var/named/dynamic";

        pid-file "/run/named/named.pid";
        session-keyfile "/run/named/session.key";

        # Setup Google's dns as forwarders
        forwarders {
                8.8.8.8;
                8.8.4.4;
        };
};

logging {
        channel default_debug {
                file "data/named.run";
                severity dynamic;
        };
};

zone "." IN {
        type hint;
        file "named.ca";
};

include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";

zone "example.com" {
    type master;
    file "dynamic/example.com"; # zone file path
    allow-transfer { 192.168.1.102; };
    notify yes;
};

zone "1.168.192.in-addr.arpa" in {
        type master;
        file "dynamic/1.168.192.in-addr.arpa.zone";
        allow-transfer { 192.168.1.102; };
        notify yes;
};

Create the actual zonefile for example.com:

[root@dns01 ~]# vim /var/named/dynamic/db.example.com
; Remember to update the serial by 1 each time you edit this file!
$TTL 300                ; 5 minutes 
@       IN      SOA     dns01.example.com. admin.example.com. (
                  1     ; Serial
               3600     ; Refresh
                300     ; Retry
            1814400     ; Expire
                300 )   ; Negative Cache TTL

; name servers - NS records
    IN      NS      dns01.example.com.
    IN      NS      dns02.example.com.

; name servers - A records
dns01.example.com.     IN     A     192.168.1.101
dns02.example.com.     IN     A     192.168.1.102

; All other A records
example.com.           IN     A     192.168.1.200
www.example.com.       IN     A     192.168.1.200
web01.example.com.     IN     A     192.168.1.201
web02.example.com.     IN     A     192.168.1.202
web03.example.com.     IN     A     192.168.1.203

Then setup reverse DNS for your IP space:

[root@dns01 ~]# vim /var/named/dynamic/1.168.192.in-addr.arpa.zone
vim /var/named/dynamic/1.168.192.in-addr.arpa.zone
$ORIGIN 1.168.192.in-addr.arpa.
$TTL 86400              ; 1 day
@       IN      SOA     dns01.example.com. admin.example.com. (
                  1     ; Serial
               7200     ; refresh (2 hous)
               7200     ; retry (2 hours)
            2419200     ; expire (5 weeks 6 days 16 hours)
              86400 )   ; minimum (1 day)

1.168.192.in-addr.arpa. IN NS dns01.example.com.
1.168.192.in-addr.arpa. IN NS dns02.example.com.

101     IN     PTR     dns01.example.com.
102     IN     PTR     dns02.example.com.

200     IN     PTR     www.example.com.
201     IN     PTR     web01.example.com.
202     IN     PTR     web02.example.com.
203     IN     PTR     web03.example.com.

Now confirm your syntax is valid:

[root@dns01 ~]# named-checkconf

If no errors are returned, set bind to start on boot and fire it up:

[root@dns01 ~]# systemctl enable named
[root@dns01 ~]# systemctl restart named

Finally, update the servers /etc/resolv.conf:

[root@dns01 ~]# mv /etc/resolv.conf /etc/resolv.conf.orig
[root@dns01 ~]# cat << EOF > /etc/resolv.conf
domain example.com
search example.com
nameserver 192.168.1.101
nameserver 192.168.1.102
EOF

Secondary DNS server setup

Setting up dns02.example.com will be easier since it will automatically retrieve the zonefiles from dns01. Adjust the settings to meet your environments needs accordingly. The primary fields to change will be in bold below:

[root@dns02 ~]# mv /etc/named.conf /etc/named.conf.orig 
[root@dns02 ~]# vim /etc/named.conf
//
// named.conf
//
// Provided by Red Hat bind package to configure the ISC BIND named(8) DNS
// server as a caching only nameserver (as a localhost DNS resolver only).
//
// See /usr/share/doc/bind*/sample/ for example named configuration files.
//
// See the BIND Administrator's Reference Manual (ARM) for details about the
// configuration located in /usr/share/doc/bind-{version}/Bv9ARM.html

acl "trusted-recursion" {
        localhost;
        localnets;
        192.168.1.0/24;
};


options {
        listen-on port 53 { any; };
        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; };
        allow-recursion { trusted-recursion; };
        allow-query-cache { trusted-recursion; };
        /*
         - If you are building an AUTHORITATIVE DNS server, do NOT enable recursion.
         - If you are building a RECURSIVE (caching) DNS server, you need to enable
           recursion.
         - If your recursive DNS server has a public IP address, you MUST enable access
           control to limit queries to your legitimate users. Failing to do so will
           cause your server to become part of large scale DNS amplification
           attacks. Implementing BCP38 within your network would greatly
           reduce such attack surface
        */
        /* recursion yes; */

        dnssec-enable yes;
        dnssec-validation no;

        /* Path to ISC DLV key */
        bindkeys-file "/etc/named.iscdlv.key";

        managed-keys-directory "/var/named/dynamic";

        pid-file "/run/named/named.pid";
        session-keyfile "/run/named/session.key";

        # Setup Google's dns as forwarders
        forwarders {
                8.8.8.8;
                8.8.4.4;
        };
};

logging {
        channel default_debug {
                file "data/named.run";
                severity dynamic;
        };
};

zone "." IN {
        type hint;
        file "named.ca";
};

include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";

zone "example.com" {
        type slave;
        file "slaves/db.example.com";
        masters { 192.168.1.101; };
};

zone "1.168.192.in-addr.arpa" in {
        type slave;
        file "slaves/1.168.192.in-addr.arpa.zone";
        masters { 192.168.1.101; };

Now confirm your syntax is valid:

[root@dns02 ~]# named-checkconf

If no errors are returned, set bind to start on boot and fire it up:

[root@dns02 ~]# systemctl enable named
[root@dns02 ~]# systemctl restart named

Verify the zonefiles replicated over to dns02.example.com by checking in:

[root@dns02 ~]# ls -al /var/named/slaves/

Finally, update the servers /etc/resolv.conf:

[root@dns01 ~]# cp /etc/resolv.conf /etc/resolv.conf.orig
[root@dns01 ~]# cat << EOF > /etc/resolv.conf
domain example.com
search example.com
nameserver 192.168.1.102
nameserver 192.168.1.101
EOF

Testing the DNS servers

You can verify the DNS servers are working by:

[root@web01 ~]# dig @192.168.1.101 www.example.com +short
192.168.1.200
[root@web01 ~]# dig @192.168.1.101 -x 192.168.1.200 +short
www.example.com.

[root@web01 ~]# dig @192.168.1.102 www.example.com +short
192.168.1.200
[root@web01 ~]# dig @192.168.1.102 -x 192.168.1.200 +short
www.example.com.