While it is not essential to have a private DNS server for your home lab I’ve found that many scenarios are rather difficult without one. Using fully qualified domain names rather than IP addresses makes configuring applications and infrastructure services easier. Even from an administrative perspective remembering names is clearly more efficient than four octets.
In this post, we will setup a private DNS environment consisting of primary and secondary servers running BIND (BIND9). Both will run Ubuntu Server 14.04 as virtual machines on a VMware ESXi 5.5 host. We’ll also configure a third Ubuntu server that will act as a client to test querying the new DNS servers.
Prerequisites
- VM to serve as the Primary DNS server, ns1 (1 vCPU, 1GB vRAM)
- VM to serve as the Secondary DNS server, ns2 (1 vCPU, 1GB vRAM)
- VM to test querying the DNS servers, host1 (1 vCPU, 1GB vRAM)
Parameters used in this example:
homelab.local
will be used as the lab domain name- 10.1.100.0/24 is the private subnet
Host | FQDN | IP Address |
---|---|---|
ns1 | ns1.homelab.local | 10.1.100.41 |
ns2 | ns2.homelab.local | 10.1.100.42 |
host1 | host1.homelab.local | 10.1.100.90 |
Configure Primary Server Networking
In order for the servers to reach the Ubuntu package repositories you need to edit the network interfaces configuration file and hosts file.
Edit the network interfaces configuration file on the ns1 server:
$ sudo vi /etc/network/interfaces
When done editing it should look like:
iface lo inet loopback
auto lo
# primary network interface
auto eth0
iface eth0 inet static
address 10.1.100.41
netmask 255.255.255.0
network 10.1.100.0
broadcast 10.1.100.255
gateway 10.1.100.1
dns-nameservers 8.8.8.8 8.8.4.4
Then restart networking:
$ /etc/init.d/networking restart
Edit the hosts file on the ns1 server:
$ sudo vi /etc/hosts
When done editing it should look like:
127.0.0.1 localhost
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
10.1.100.41 ns1.homelab.local ns1
Configure Secondary Server Networking
Repeat the same process for the secondary server, ns2.
Edit the network interfaces configuration file on the ns2 server:
$ sudo vi /etc/network/interfaces
When done editing it should look like:
iface lo inet loopback
auto lo
# primary network interface
auto eth0
iface eth0 inet static
address 10.1.100.42
netmask 255.255.255.0
network 10.1.100.0
broadcast 10.1.100.255
gateway 10.1.100.1
dns-nameservers 8.8.8.8 8.8.4.4
Then restart networking:
$ /etc/init.d/networking restart
Edit the hosts file on the ns2 server:
$ sudo vi /etc/hosts
When done editing it should look like:
127.0.0.1 localhost
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
10.1.100.42 ns2.homelab.local ns2
Install BIND on the Primary DNS Server
Connect to the ns1 host (10.1.100.41) via SSH.
Download package lists and information of latest versions:
$ sudo apt-get -y update
Install BIND packages:
$ sudo apt-get -y install bind9 bind9utils bind9-doc
Configure BIND to run in IPv4 mode by editing the bind9 service parameters file:
$ sudo vi /etc/default/bind9
Add “-4” to the OPTIONS variable. It should look like the following:
# run resolvconf?
RESOLVCONF=no
# startup options for the server
OPTIONS="-4 -u bind"
Save the file and exit.
Configure the Primary DNS Server
The primary configuration file for the BIND DNS server named process is /etc/bind/named.conf
. It includes three additional configuration files: named.conf.options
, named.conf.local
, and named.conf.default-zones
.
Configure Options File
On ns1, edit the named.conf.options file:
$ sudo vi /etc/bind/named.conf.options
By default the file should look like the following:
options {
directory "/var/cache/bind";
// If there is a firewall between you and nameservers you want
// to talk to, you may need to fix the firewall to allow multiple
// ports to talk. See http://www.kb.cert.org/vuls/id/800113
// If your ISP provided one or more IP addresses for stable
// nameservers, you probably want to use them as forwarders.
// Uncomment the following block, and insert the addresses replacing
// the all-0's placeholder.
// forwarders {
// 0.0.0.0;
// };
//========================================================================
// If BIND logs error messages about the root key being expired,
// you will need to update your keys. See https://www.isc.org/bind-keys
//========================================================================
dnssec-validation auto;
auth-nxdomain no; # conform to RFC1035
listen-on-v6 { any; };
};
First we will define an access control list called trusted
that will determine which clients the DNS servers will allow recursive queries from. You can enter individual client IP addresses to tightly control access but since this is a home lab we will use subnets to permit recursive queries from the 10.1.100.0/24 network. Add the ACL before the options
block as follows:
// Lab subnets we wish to allow recursive queries from.
acl "trusted" {
10.1.100.0/24; # lab network
};
Edit the directory
directive to read as follows:
options {
directory "/var/cache/bind";
recursion yes; # enables resursive queries
allow-recursion { trusted; }; # allows recursive queries from "trusted" clients
listen-on { 10.1.100.41; }; # ns1 private IP address - listen on private network only
allow-transfer { none; }; # disable zone transfers by default
forwarders {
8.8.8.8;
8.8.4.4;
};
dnssec-validation auto;
auth-nxdomain no; # conform to RFC1035
listen-on-v6 { any; };
};
Save the file and exit the editor.
Configure Local DNS Zones
We will define our local forward and reserve DNS zones in the named.conf.local
file.
On ns1, open the file for editing:
$ sudo vi /etc/bind/named.conf.local
Add a forward zone for homelab.local
:
zone "homelab.local" {
type master;
file "/etc/bind/zones/db.homelab.local"; # zone file path
allow-transfer { 10.1.100.42; }; # ns2 private IP address – secondary
};
Add a reverse zone for the 10.1.100.0/24 subnet. The reverse mapping for 10.1.100 is entered as 100.1.10
:
zone "100.1.10.in-addr.arpa" {
type master;
file "/etc/bind/zones/db.10.1.100"; # 10.1.100.0/24 subnet
allow-transfer { 10.1.100.42; }; # ns2 private IP address – secondary
};
If your lab includes multiple subnets you want to provide DNS resolution for you should add a zone and zone file for each subnet. At this point the /etc/bind/named.conf.local
file should look like the following:
zone "homelab.local" {
type master;
file "/etc/bind/zones/db.homelab.local"; # zone file path
allow-transfer { 10.1.100.42; }; # ns2 private IP address – secondary
};
zone "100.1.10.in-addr.arpa" {
type master;
file "/etc/bind/zones/db.10.1.100"; # 10.1.100.0/24 subnet
allow-transfer { 10.1.100.42; }; # ns2 private IP address – secondary
};
Save the file and exit the editor.
Create the Forward Zone File
Once the zones are specified in the BIND configuration file we need to create forward and reverse zone files. We will start with the forward zone file which defines DNS records for forward lookups. For example, if a client queries the DNS server for host1.homelab.local
the server will look in the homelab.local
forward zone file for a record mapping host1
to it’s IP address.
The forward zone file is where we define DNS records for forward DNS lookups. That is, when the DNS receives a name query, “host1.homelab.local” for example, it will look in the forward zone file to resolve host1’s corresponding private IP address.
In the named.conf.local
file the default zone file location was specified to be /etc/bind/zones
. The directory must be created before we can store zone files:
$ sudo mkdir /etc/bind/zones
Create the forward zone file for homelab.local
based on the /etc/bind/db.local
sample:
$ cd /etc/bind/zones
$ sudo cp ../db.local ./db.homelab.local
Edit the forward zone file:
$ sudo vi /etc/bind/zones/db.homelab.local
By default, it should match the following:
;
; BIND data file for local loopback interface
;
$TTL 604800
@ IN SOA localhost. root.localhost. (
2 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
@ IN NS localhost.
@ IN A 127.0.0.1
@ IN AAAA ::1
Edit the SOA record replacing localhost
with ns1’s FQDN, replacing root.localhost
with admin.homelab.local
, and incrementing the serial
value:
@ IN SOA ns1.homelab.local. admin.homelab.local. (
3 ; Serial
Delete the localhost.
, 127.0.0.1
, and ::1
records.
Add nameserver (NS) records for the ns1 and ns2 servers:
; name servers - NS records
IN NS ns1.homelab.local.
IN NS ns2.homelab.local.
Add A records for the hosts in your lab that you want to have *.homelab.local FQDNs. For this example we’ll create A records for ns1, ns2, and host1:
; name servers - A records
ns1.homelab.local. IN A 10.1.100.41
ns2.homelab.local. IN A 10.1.100.42
;
; 10.1.100.0/24 - A records
host1.homelab.local. IN A 10.1.100.90
At this point the file should look like the following:
$TTL 604800
@ IN SOA ns1.homelab.local. admin.homelab.local. (
3 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
; name servers - NS records
IN NS ns1.homelab.local.
IN NS ns2.homelab.local.
;
; name servers - A records
ns1.homelab.local. IN A 10.1.100.41
ns2.homelab.local. IN A 10.1.100.42
;
; 10.1.100.0/24 - A records
host1.homelab.local. IN A 10.1.100.90
Save and exit the db.homelab.local
file.
Create the Reverse Zone File
Next we will create a reverse zone file containing DNS PTR records for reverse DNS lookups. For example, if a client queries the DNS server for 10.1.100.90
the server will look in the 10.1.100
zone file for a record mapping 10.1.100.90
to the FQDN host1.homelab.local
.
In the named.conf.local
file on ns1 the file for the reverse zone 100.1.10.in-addr.arpa
was set to be /etc/bind/zones/db.10.1.100
. Create the reverse zone file based on the /etc/bind/db.127
sample:
$ cd /etc/bind/zones
$ sudo cp ../db.127 ./db.10.1.100
Edit the reverse zone file:
$ sudo vi /etc/bind/zones/db.10.1.100
By default, it should match the following:
;
; BIND reverse data file for local loopback interface
;
$TTL 604800
@ IN SOA localhost. root.localhost. (
1 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
@ IN NS localhost.
1.0.0 IN PTR localhost.
As we did with the forward zone file edit the SOA record and increment the serial
value as follows:
@ IN SOA ns1.homelab.local. admin.homelab.local. (
2 ; Serial
Delete the localhost.
NS and localhost.
PTR records.
Add nameserver (NS) records for the ns1 and ns2 servers:
; name servers - NS records
IN NS ns1.homelab.local.
IN NS ns2.homelab.local.
Add PTR records for each of the hosts in your lab. The first column will be the last octet of the host’s IP addresses in reverse order. If you were using a /16 network then you would enter the last two octets of the host’s IP addresses in reverse order. For this example we’ll create records for the ns1, ns2, and host1 hosts on the 10.1.100.0/24 subnet:
; PTR Records
41 IN PTR ns1.homelab.local. ; 10.1.100.41
42 IN PTR ns2.homelab.local. ; 10.1.100.42
90 IN PTR host1.homelab.local. ; 10.1.100.90
At this point the file should look like the following:
$TTL 604800
@ IN SOA ns1.homelab.local. admin.homelab.local. (
2 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
; name servers - NS records
IN NS ns1.homelab.local.
IN NS ns2.homelab.local.
;
; PTR Records
41 IN PTR ns1.homelab.local. ; 10.1.100.41
42 IN PTR ns2.homelab.local. ; 10.1.100.42
90 IN PTR host1.homelab.local. ; 10.1.100.90
Save and exit the db.10.1.100
file.
Repeat these steps for any additional subnets used in your lab.
Check BIND Configuration File Syntax
Check the syntax of the configuration files that start with named.conf
:
$ sudo named-checkconf
If the configuration files have no syntax errors you won’t see any error messages.
Check the syntax of the forward zone file:
$ sudo named-checkzone homelab.local db.homelab.local
If there are no syntax errors you should see something similar to the following:
zone homelab.local/IN: loaded serial 3
OK
Check the syntax of the reverse zone file:
$ sudo named-checkzone 100.1.10.in-addr.arpa /etc/bind/zones/db.10.1.100
If there are no syntax errors you should see something similar to the following:
zone 100.1.10.in-addr.arpa/IN: loaded serial 2
OK
Restart BIND
Restart the BIND service:
$ sudo service bind9 restart
Install BIND on the Secondary Server
Connect to the ns2 host (10.1.100.42) via SSH.
Download package lists and information of latest versions:
$ sudo apt-get -y update
Install BIND packages:
$ sudo apt-get -y install bind9 bind9utils bind9-doc
Configure BIND to run in IPv4 mode by editing the bind9 service parameters file:
$ sudo vi /etc/default/bind9
Add "-4" to the OPTIONS variable. It should look like the following:
# run resolvconf?
RESOLVCONF=no
# startup options for the server
OPTIONS="-4 -u bind"
Save the file and exit.
Configure the Secondary DNS Server
Configure Options File
On ns2, edit the named.conf.options
file:
$ sudo vi /etc/bind/named.conf.options
By default the file should look like the following:
options {
directory "/var/cache/bind";
// If there is a firewall between you and nameservers you want
// to talk to, you may need to fix the firewall to allow multiple
// ports to talk. See http://www.kb.cert.org/vuls/id/800113
// If your ISP provided one or more IP addresses for stable
// nameservers, you probably want to use them as forwarders.
// Uncomment the following block, and insert the addresses replacing
// the all-0's placeholder.
// forwarders {
// 0.0.0.0;
// };
//========================================================================
// If BIND logs error messages about the root key being expired,
// you will need to update your keys. See https://www.isc.org/bind-keys
//========================================================================
dnssec-validation auto;
auth-nxdomain no; # conform to RFC1035
listen-on-v6 { any; };
};
Add an ACL to permit recursive queries from the 10.1.100.0/24 network before the options
block as follows:
// Lab subnets we wish to allow recursive queries from.
acl "trusted" {
10.1.100.0/24; # lab network
};
Edit the directory directive to read as follows:
options {
directory "/var/cache/bind";
recursion yes; # enables resursive queries
allow-recursion { trusted; }; # allows recursive queries from "trusted" clients
listen-on { 10.1.100.42; }; # ns2 private IP address - listen on private network only
allow-transfer { none; }; # disable zone transfers by default
forwarders {
8.8.8.8;
8.8.4.4;
};
dnssec-validation auto;
auth-nxdomain no; # conform to RFC1035
listen-on-v6 { any; };
};
Save the file and exit the editor.
Configure Local DNS Zones
We will define our local slave zones on the secondary DNS server that correspond to the master zones defined on the primary. As you will see below the file
parameter for zones of type slave
does not contain a path and there is a masters
directive that is set to the IP address of the primary DNS server.
On ns2, open the file for editing:
$ sudo vi /etc/bind/named.conf.local
Add a forward zone for homelab.local
:
zone "homelab.local" {
type slave;
file "db.homelab.local";
masters { 10.1.100.41; }; # ns1 private IP
};
Add a reverse zone for the 10.1.100.0/24 subnet. The reverse mapping for 10.1.100 is entered as 100.1.10
:
zone "100.1.10.in-addr.arpa" {
type slave;
file "db.10.1.100";
masters { 10.1.100.41; }; # ns1 private IP
};
The /etc/bind/named.conf.local
file should look like the following:
zone "homelab.local" {
type slave;
file "db.homelab.local";
masters { 10.1.100.41; }; # ns1 private IP
};
zone "100.1.10.in-addr.arpa" {
type slave;
file "db.10.1.100";
masters { 10.1.100.41; }; # ns1 private IP
};
Save the file and exit the editor.
Check BIND Configuration File Syntax
Check the syntax of the configuration files that start with named.conf
:
$ sudo named-checkconf
If the configuration files have no syntax errors you won’t see any error messages.
Restart BIND
Restart the BIND service:
$ sudo service bind9 restart
Test DNS Using Ubuntu Client
The primary and secondary DNS servers have now been deployed, so it is time to test name and IP address resolution. We will use a third Ubuntu 14.04 Server configured to query our two new servers.
Configure Test Client Networking
Connect to the host1 host (10.1.100.90) via SSH.
Edit the network interfaces configuration file:
$ sudo vi /etc/network/interfaces
Look for the parameters. Remove the existing dns-nameservers
and dns-search
entries and replace them with your private domain and ns1 and ns2 private IP addresses.
When done editing it should look like:
iface lo inet loopback
auto lo
# primary network interface
auto eth0
iface eth0 inet static
address 10.1.100.90
netmask 255.255.255.0
network 10.1.100.0
broadcast 10.1.100.255
gateway 10.1.100.1
dns-search homelab.local
dns-nameservers 10.1.100.41 10.1.100.42
Save and close the file.
Bounce the interface to apply the changes:
$ sudo ifdown eth0 && sudo ifup eth0
Test Forward Lookup
Run the following command to perform a forward lookup and retrieve the IP address of host1.homelab.local:
$ nslookup host1
When you perform a DNS query for host1 it is expanded to host1.homelab.local
because of the dns-search homelab.local
that is set in the network interfaces configuration file. The command output should be:
frank@host1:~$ nslookup host1
Server: 10.1.100.41
Address: 10.1.100.41#53
Name: host1.homelab.local
Address: 10.1.100.90
Test Reverse Lookup
Run the following command to perform a reverse lookup of host1’s IP address:
$ nslookup 10.1.100.90
The command output should be:
Server: 10.1.100.41
Address: 10.1.100.41#53
91.100.1.10.in-addr.arpa name = host1.homelab.local.
Query NS1 Using DIG
Run the following command to query the primary DNS server using DIG:
$ dig homelab.local any @ns1.homelab.local
The command output should be:
; <<>> DiG 9.9.5-3ubuntu0.1-Ubuntu <<>> homelab.local any @ns1.homelab.local
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20320
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 3
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;homelab.local. IN ANY
;; ANSWER SECTION:
homelab.local. 604800 IN SOA ns1.homelab.local. admin.homelab.local. 3 604800 86400 2419200 604800
homelab.local. 604800 IN NS ns1.homelab.local.
homelab.local. 604800 IN NS ns2.homelab.local.
;; ADDITIONAL SECTION:
ns1.homelab.local. 604800 IN A 10.1.100.41
ns2.homelab.local. 604800 IN A 10.1.100.42
;; Query time: 1 msec
;; SERVER: 10.1.100.41#53(10.1.100.41)
;; WHEN: Fri Feb 13 22:31:58 EST 2015
;; MSG SIZE rcvd: 152
Query NS2 Using DIG
Run the following command to query the secondary DNS server using DIG:
$ dig homelab.local any @ns2.homelab.local
The command output should be:
; <<>> DiG 9.9.5-3ubuntu0.1-Ubuntu <<>> homelab.local any @ns2.homelab.local
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58763
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 3
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;homelab.local. IN ANY
;; ANSWER SECTION:
homelab.local. 604800 IN NS ns1.homelab.local.
homelab.local. 604800 IN NS ns2.homelab.local.
homelab.local. 604800 IN SOA ns1.homelab.local. admin.homelab.local. 3 604800 86400 2419200 604800
;; ADDITIONAL SECTION:
ns1.homelab.local. 604800 IN A 10.1.100.41
ns2.homelab.local. 604800 IN A 10.1.100.42
;; Query time: 1 msec
;; SERVER: 10.1.100.42#53(10.1.100.42)
;; WHEN: Fri Feb 13 22:32:04 EST 2015
;; MSG SIZE rcvd: 152
If the command output from the forward and reverse lookups match the examples above it means that your DNS servers are configured properly.
Summary
This post walks through setting up a private DNS environment with redundant DNS servers running BIND. We also tested querying the DNS servers using a third Ubuntu system to confirm that both work as expected. In a future post maintaining DNS records will be covered.