The DNS (Domain Name System) is a system where all domain names of servers are organized in a specific hierarchy. Why do we need it? Imagine needing to connect to a device with the IP address 91.206.179.207. You could enter this address in the command line to get the information you need, but remembering many such numeric combinations is very difficult. Therefore, special servers were created to convert domain names into IP addresses. So, for example, when you enter hostman.com in your browser’s search bar, the request data is sent to a DNS server, which looks for matches in its database. The DNS server then sends the necessary IP address to your device, and only then does the browser directly access the resource.
Configuring your own DNS allows for more flexible and precise system configuration and avoids reliance on third parties. In this article, we will look at how to set up DNS using the BIND nameserver on Ubuntu.
Zone: A part of the DNS hierarchy hosted on a DNS server. It establishes the boundaries within which a specific server or group of servers is responsible.
Root Servers: DNS servers containing information about top-level domains (.ru, .com, etc.).
Domain: A named part of the DNS hierarchy, a specific node that includes other nodes. DNS addresses are read from right to left and start with a dot, with domains also separated by dots. For example, the domain poddomen.domen.ru should be read as .ru.domen.poddomen. Usually, the domain name reflects the DNS hierarchy structure, but the final dot is omitted.
FQDN (Fully Qualified Domain Name): A full domain name including the names of all parent domains.
Resource Record: A unit of information storage, essentially a record that links a name to some service information. It consists of:
Name (NAME
): The name or IP address that owns the zone.
Time to Live (TTL
): The duration a record is stored in the DNS cache before being deleted.
Class (CLASS
): Network type, usually IN
(Internet).
Type (TYPE
): The record's purpose.
Various Information (DATA
): Additional details.
A
: Maps a hostname to an IPv4 address. Each network interface can have only one A record.website.com. 520 IN A 91.206.179.207
AAAA
: The same as an A record, but for IPv6.CNAME
: Canonical name record, an alias for a real name for redirection.
MX
: Specifies mail hosts for the domain. The NAME
field contains the destination domain, and the DATA
field contains the priority and host for receiving mail.website.com. 17790 IN MX 10 mx.website.com.
website.com. 17790 IN MX 20 mx2.website.com.
NS
: Points to the DNS server servicing the domain.
PTR
: IP address to domain name mapping, needed for reverse name resolution.
SOA
: Describes the main zone settings.
SRV
: Contains addresses of servers providing internal domain services, such as Jabber.
To follow the instructions in this article, you need at least two Ubuntu cloud servers in the same data center. Any of these servers can be ordered from Hostman.
We will need two Ubuntu 20.04 servers, used as the primary and secondary DNS servers, ns1
and ns2
, respectively. Additionally, there will be extra servers using our configured servers.
You must have superuser privileges on each server.
We will use bind9
as the DNS server. Install the bind9
package from the Linux repository:
sudo apt update && sudo apt upgrade -y
sudo apt install bind9
Additionally, it is recommended to install network monitoring tools:
sudo apt install dnsutils
After installation, start the bind9
service:
sudo service bind9 start
The main configuration file of the server is /etc/bind/named.conf
. It describes the general settings and is usually split into several others for convenience. DNS setup begins by working with the parameters inside this file.
named.conf.options
This file contains the general server parameters. We will specify the DNS configuration data in it.
options {
dnssec-validation auto;
auth-nxdomain no;
directory "/var/cache/bind";
recursion no; # disallow recursive queries to the nameserver
listen-on {
172.16.0.0/16;
127.0.0.0/8;
};
forwarders {
172.16.0.1;
8.8.8.8;
};
};
To verify that everything is entered correctly, use one of the named daemon utilities, named-checkconf
.
sudo named-checkconf
If everything is correct, the bind server starts working.
The primary DNS server stores the main copy of the zone data file. All zones will be stored in the /etc/bind/master-zones
directory of the primary DNS server. Create the directory:
sudo mkdir /etc/bind/master-zones
Create a file to describe the zone:
sudo touch /etc/bind/master-zones/test.example.com.local.zone
And add SOA
, NS
, and A
records to it:
$ttl 3600
$ORIGIN test.example.com.
test.example.com. IN SOA (
ns.test.example.com.
abuse.test.example.com.
2022041201
10800
1200
604800
3600 )
@ IN NS ns.test.example.com.
@ IN NS ns2.test.example.com.
@ IN A 172.16.101.3
ns IN A 172.16.0.5
ns2 IN A 172.16.0.6
Next, run the check with the utility named-checkzone
.
sudo named-checkzone test.example.com. /etc/bind/master-zones/test.example.com.local.zone
This is another file included in the server's main configuration. We will specify local zones in it:
zone "test.example.com." {
type master;
file "/etc/bind/master-zones/test.example.com.local.zone";
};
After entering the necessary data, check the config and restart bind9
(the -z
flag checks zone files):
sudo named-checkconf
sudo named-checkconf -z
sudo service bind9 restart
sudo service bind9 status
Views allow flexible management of name resolution from different subnets. Specify in the /etc/bind/named.conf
file:
include "/etc/bind/named.conf.options";
acl "local" { 172.16.0.0/16; };
view "local" {
include "/etc/bind/named.conf.local";
match-clients { local; };
};
In the same file, you can specify directives for indicating which nodes and network addresses to accept or reject requests from. Then, restart bind9
:
sudo service bind9 restart
After the server restarts, you can request the SOA record for the server 172.16.0.5
from another computer on the local network:
dig @172.16.0.5 -t SOA test.example.com
At this stage, the primary DNS server setup is complete. The next sections cover the secondary server, mail server setup, and reverse zone configuration.
The initial steps are the same as for the primary server — installing bind9
and network utilities:
sudo apt update && sudo apt upgrade -y
sudo apt install bind9
sudo apt install dnsutils
sudo service bind9 start
Next, to store zone files, create the /etc/bind/slave
directory and grant the necessary permissions:
sudo mkdir /etc/bind/slave
sudo chmod g+w /etc/bind/slave
Proceed to configure the zone on the secondary server. Add the zone to the /etc/bind/named.conf.local
file:
zone "test.example.com." {
type slave;
file "/etc/bind/slave/test.example.com.local.zone";
masters { 172.16.0.5; };
};
And set up views in the main configuration file named.conf
:
include "/etc/bind/named.conf.options";
acl "local" { 172.16.0.0/16; };
view "local" {
match-clients { local; };
include "/etc/bind/named.conf.local";
};
After adding the settings, check the syntax, and then restart bind9
:
sudo named-checkconf
sudo named-checkconf -z
sudo service bind9 restart
If there are no errors, perform the zone transfer:
sudo rndc retransfer test.example.com
The rndc retransfer
command allows for a zone transfer without checking serial numbers. Briefly, the primary (ns1
) and secondary (ns2
) DNS servers work as follows: ns2
only checks the serial number of the zone and ignores the content of the entire zone file. If the serial number decreases, the zone transfer will be stopped. Therefore, it is crucial to increment the serial number every time you edit the zone. It is recommended to use the current date and an incremental number as the serial number.
Once you have set up the server and performed the zone transfer, you need to restrict the transfer to the secondary server’s IP address in the named.conf configuration on the primary server. To do this, add the allow-transfer directive with the IP address of the secondary DNS server in named.conf
:
zone "test.example.com." {
type master;
allow-transfer { 172.168.0.6; };
file "/etc/bind/master-zones/test.example.com.local.zone";
};
Then restart the server:
sudo service bind9 restart
After this step, all further operations will be performed on the primary server.
In this example, we use mx
as the hostname since it is a commonly accepted designation. Therefore, the FQDN (Fully Qualified Domain Name) will be mx.test.example.com
.
To add an MX record:
1) Add the mail resource records to the zone file located at /etc/bind/master-zones/test.example.com.local.zone
.
; Add the MX records to the zone file
@ IN MX 10 mx.test.example.com.
@ IN MX 20 mx2.test.example.com.
This adds two MX records with different priorities for the domain test.example.com
.
2) Update the serial number in the SOA (Start of Authority) record to reflect the changes.
$TTL 3600
@ IN SOA ns.test.example.com. admin.test.example.com. (
2024071101 ; Serial number
10800 ; Refresh
1200 ; Retry
604800 ; Expire
3600 ; Minimum TTL
)
3) Verify the zone file syntax with the following command:
sudo named-checkzone test.example.com. /etc/bind/master-zones/test.example.com.local.zone
This command checks the syntax of the zone file to ensure there are no errors.
4) Apply the changes by reloading BIND:
sudo service bind9 reload
This command reloads the BIND DNS server configuration to apply the updates made to the zone file.
Reverse DNS is the reverse of the forward DNS resolution, converting IP addresses back to domain names.
For example, the IP address 192.168.1.10
is represented in reverse notation as 10.1.168.192.in-addr.arpa
.
Because a hierarchical model is used, the management of the zone can be delegated to the owner of the IP address range. Essentially, a PTR record defines a domain name based on an IP address, which is conceptually similar to an A record. PTR records are primarily used for verifying mail servers.
To configure the reverse lookup zone, create a new zone file:
sudo nano /etc/bind/master-zones/16.172/in-addr.arpa.zone
And add the following data:
$TTL 3600
16.172.in-addr.arpa. IN SOA (
ns.test.example.com.
admin.test.example.com.
2022041202
10800
1200
604800
3600 )
IN NS ns.test.example.com.
IN NS ns2.test.example.com.
3.101.16.172.in-addr.arpa. IN PTR test.example.com.
5.0.16.172.in-addr.arpa. IN PTR ns.test.example.com.
6.0.16.172.in-addr.arpa. IN PTR ns2.test.example.com.
2.101.16.172.in-addr.arpa. IN PTR mail.test.example.com.
Check the configuration:
sudo named-checkzone 16.172.in-addr.arpa /etc/bind/master-zones/16.172.in-addr.arpa.zone
Then, open named.conf.local
:
sudo nano /etc/bind/named.conf.local
And specify the following zone:
zone "16.172.in-addr.arpa." {
type master;
file "/etc/bind/master-zones/16.172.in-addr.arpa.zone";
allow-transfer { 172.16.0.6; };
};
Restart the bind9
service:
sudo named-checkconf
sudo named-checkconf -z
sudo service bind9 restart
Check with the dig
utility:
dig @172.16.0.5 -x 172.16.0.5
Now you can perform a similar setup on the secondary server. Add the following configuration to named.conf.local
:
zone "16.172.in-addr.arpa." {
type slave;
file "/etc/bind/slave/16.172.in-addr.arpa.zone";
masters { 172.16.0.5; };
};
At this stage, we have completed work with local domain zones. You can now proceed to configure the external domain zone.
First, to handle queries from the external network, add the external IP address to the listen-on
directive in the named.conf.options
configuration file:
listen-on {
aaa.bbb.ccc.ddd/32; # our external IP
172.16.0.0;
127.0.0.0/8
}
Next, create the zone file (don't forget to change the serial number!) and add the external IP addresses to it:
sudo nano /etc/bind/master-zones/test.example.com.zone
Add the following content to the file:
$TTL 3600
$ORIGIN test.example.com.
test.example.com. IN SOA (
ns.test.example.com.
admin.test.example.com.
2022041205
10800
1200
604800
3600 )
@ IN NS ns.test.example.com.
@ IN NS ns2.test.example.com.
@ IN A aaa.bbb.ccc.ddd # first external address
ns IN A aaa.bbb.ccc.ddd
ns2 IN A eee.fff.ggg.hhh # second external address
Then, create a separate file for the external view zones to serve different domain zones to clients from different subnets:
sudo nano /etc/bind/named.conf.external
Add the following content to the file:
zone "test.example.com." {
type master;
file "/etc/bind/master-zones/test.example.com.zone";
allow-transfer { 172.16.0.6; };
};
After this, include the file in named.conf
by adding the following block:
acl "external-view" { aaa.bbb.ccc.ddd; };
view "external-view" {
recursion no;
match-clients { external-view; };
include "/etc/bind/named.conf.external";
};
Now check this zone and restart BIND9:
sudo named-checkconf -z
sudo named-checkzone test.example.com. /etc/bind/master-zones/test.example.com.zone
sudo service bind9 restart
sudo service bind9 status
On the secondary DNS server, you need to specify the external server address in named.conf.options
:
sudo nano /etc/bind/named.conf.options
Add the following configuration:
options {
dnssec-validation auto;
auth-nxdomain no;
recursion no;
directory "/var/cache/bind";
listen-on {
eee.fff.ggg.hhh/24;
172.16.0.0/16;
127.0.0.0/8;
};
};
Similarly to the primary server, create a new named.conf.external
file:
sudo nano /etc/bind/named.conf.external
Add the following content to the file:
zone "test.example.com." {
type slave;
file "/etc/bind/slave/test.example.com.zone";
masters { 172.16.0.5; };
};
Then add the following block to named.conf
:
acl "external-view" { eee.fff.ggg.hhh; };
view "external-view" {
recursion no;
match-clients { external-view; };
include "/etc/bind/named.conf.external";
};
And perform the transfer:
sudo rndc retransfer test.example.com IN external-view
When setting up a DNS server, it is very important to pay close attention to query logging. This helps with initial troubleshooting, and during normal server operation, it allows you to fully control the services.
BIND9 allows for comprehensive logging rules configuration—writing to a single file, separating different categories into different logs, and so on.
To write debugging information to one file, you need to create logging rules and include them in the main configuration. Create a log.conf
file:
sudo nano /etc/bind/log.conf
Add the following content:
logging {
channel bind.log {
file "/var/lib/bind/bind.log" versions 10 size 20m;
severity debug;
print-category yes;
print-severity yes;
print-time yes;
};
category queries { bind.log; };
category default { bind.log; };
category config { bind.log; };
};
Then include the file in the main configuration:
include "/etc/bind/log.conf";
And restart BIND9:
sudo service bind9 restart
You can create multiple such files with different settings and include them depending on the development stage or server load.
In this guide, we configured DNS on a server running Ubuntu OS using the bind9 package. After following the steps, the two configured DNS servers can be used for name resolution on the network. To use the custom DNS servers, configure your other servers to use 172.16.0.5
and 172.16.0.6
as their DNS servers.
This setup can serve as the foundation for further enhancements, such as setting up an email server.