Set Up BIND Authoritative DNS Server on CentOS 8/RHEL 8
This tutorial will be showing you how to set up and run your own authoritative name server on CentOS 8/RHEL 8 with the widely-used BIND 9 software.
Note: This tutorial shows the command-line method. If you want to edit DNS records from a web GUI, I recommend setting up authoritative DNS servers with Webmin, which is a free and open-source server control panel.
What’s An Authoritative DNS Server?
If you own a domain name and want your own DNS server to handle name resolution for your domain name instead of using your domain registrar’s DNS server, then you will need to set up an authoritative DNS server.
An authoritative DNS server is used by domain name owners to store DNS records. It provides authoritative answers to DNS resolvers (like 8.8.8.8 or 1.1.1.1), which query DNS records on behalf of end-users on PC, smartphone, or tablet.
About BIND
BIND (Berkeley Internet Name Domain) is an open-source, flexible and full-featured DNS software widely used on Unix/Linux due to its stability and high quality. It’s originally developed by UC Berkeley, and later in 1994, its development was moved to Internet Systems Consortium, Inc (ISC).
BIND can act as an authoritative DNS server for a zone and a DNS resolver at the same time. A DNS resolver can also be called a recursive name server because it performs recursive DNS lookups for end users. However, taking two roles at the same time isn’t advantageous. It’s a good practice to separate the two roles on two different hosts.
In a previous article, I explained the steps of setting up a local DNS resolver on CentOS 8/RHEL 8. This tutorial will show you how to set up BIND9 on CentOS 8/RHEL 8 as an authoritative-only DNS server with recursion disabled.
Prerequisites
To follow this tutorial, you should have already bought a domain name. I registered my domain name at NameCheap because the price is low and they give whois privacy protection free for life.
You also need two servers. One server is for the master DNS server and the other is for the slave DNS server. Ideally the two servers should be at different physical locations. If one DNS server is offline, the other DNS server can still answer DNS queries for your domain name.
Each server needs only 512MB RAM and here are the hosting providers that I recommend. I have used all of them.
- Vultr: Start at $2.5/month. You can create an account at Vultr via my referral link to get $50 free credit.
- DigitalOcean: Start at $5/month. You can create an account at DigitalOcean via my referral link to get $100 free credit.
Note that you need to deposit a small amount ($5) to verify you are not a bot, in order to get the credits. Once you have bought two servers, install CentOS 8/RHEL 8 on them and follow the instructions below.
Please note that you need root privilege when installing software. You can add sudo at the beginning of a command, or use su -
command to switch to the root user.
Set up Authoritative DNS Server on CentOS 8/RHEL 8 with BIND9
You need to run commands in this section on both servers.
Log into the two servers via SSH and run the following commands to install BIND 9 on CentOS 8/RHEL 8 server from the default repository. BIND 9 is the current version and BIND 10 is a dead project.
sudo dnf update sudo dnf install bind bind-utils
Check the version information.
named -v
Sample output:
BIND 9.11.13-RedHat-9.11.13-6.el8_2.1 (Extended Support Version) <id:ad4df16>
To check the version number and build options, run
named -V
Now we can start BIND 9 with:
sudo systemctl start named
And enable auto start at boot time:
sudo systemctl enable named
You can check its status with:
systemctl status named
Hint: If the above command doesn’t quit immediately, press Q.
The BIND server will run as the named
user, which is created during installation, and listens on TCP and UDP port 53, as can be seen by running the following command:
sudo ss -lnptu | grep named
Usually, DNS queries are sent to the UDP port 53. The TCP port 53 is for responses size larger than 512 bytes.
The BIND daemon is called named. (A daemon is a piece of software that runs in the background.) The named
binary is installed by the bind
package and there’s another important binary: rndc
, the remote name daemon controller. The rndc
binary is used to reload/stop and control other aspects of the BIND daemon. Communication is done over TCP port 953.
For example, we can check the status of the BIND name server.
sudo rndc status
By default, the BIND9 server on CentOS 8/RHEL 8 listens on localhost only. To provide authoritiave DNS service to resolvers on the public Internet, we need to configure it listen on the public IP address. Edit the BIND main configuration file /etc/named.conf
with a command-line text editor like Nano.
sudo dnf install nano sudo nano /etc/named.conf
In the options
clause, you can find the following two lines.
listen-on port 53 { 127.0.0.1; }; listen-on-v6 port 53 { ::1; };
This makes named
listen on localhost only. Comment out these two lines (add double slashes at the beginning of each line), so BIND will listen on public IP address.
// listen-on port 53 { 127.0.0.1; }; // listen-on-v6 port 53 { ::1; };
Since we are setting up an authoritative DNS server, we need to disable recursion. Find the following line in this file.
recursion yes;
Change the value to no
to disable recursion.
recursion no;
I also recommend adding the following directives in the options
clause.
// hide version number from clients for security reasons. version "not currently available"; // enable the query log querylog yes; // disallow zone transfer allow-transfer { none; };
Save and close the file. (To save a file in Nano text editor, press Ctrl+O
, then press Enter
to confirm. To exit, press Ctrl+X
.)
Then test the config file syntax.
sudo named-checkconf
If the test is successful (indicated by a silent output), then restart named
.
sudo systemctl restart named
Now we need to port 53 in the firewall to allow resolvers to send DNS queries.
sudo firewall-cmd --permanent --add-port={53/udp,53/tcp}
Reload firewall for the change to take effect.
sudo systemctl reload firewalld
Master DNS Server Configuration
Pick one of the two servers as the master DNS server. We will name it ns1.example.com
.
The master DNS server holds the master copy of the zone file. Changes of DNS records are made on this server. A domain can have one or more DNS zones. Each DNS zone has a zone file which contains every DNS record in that zone. For simplicity’s sake, this article assumes that you want to use a single DNS zone to manage all DNS records for your domain name.
By default, BIND enables the root zone and a localhost zone. To add a zone for your domain name, edit /etc/named.conf
file.
sudo nano /etc/named.conf
Add the following lines at the bottom of this file. Replace example.com
with your own domain name. Replace 12.34.56.78 with the IP address of slave DNS server.
zone "example.com" { type master; file "/var/named/named.example.com"; allow-query { any; }; allow-transfer { 12.34.56.78; }; };
In the above configuration, we created a new zone with the zone
clause and we specified that this is the master zone. The zone file is /var/named/named.example.com
, where we will add DNS records. This zone allows query from any IP address. The allow-query
directive in this zone will override the global allow-query
directive. Zone transfer will be only allowed for the slave DNS server.
Instead of creating a zone file from scratch, we can use a zone template file. Copy the content of named.empty
to a new file.
sudo cp /var/named/named.empty /var/named/named.example.com
A zone file can contain 3 types of entries:
- Comments: start with a semicolon (;)
- Directives: start with a dollar sign ($)
- Resource Records: aka DNS records
A zone file typically consists of the following types of DNS records.
- The SOA (Start of Authority) record: defines the key characteristics of a zone. It’s the first DNS record in the zone file and is mandatory.
- NS (Name Server) record: specifies which servers are used to store DNS records and answer DNS queries for a domain name. There must be at least two NS records in a zone file.
- MX (Mail Exchanger) record: specifies which hosts are responsible for email delivery for a domain name.
- A (Address) record: Converts DNS names into IPv4 addresses.
- AAAA (Quad A) record: Converts DNS names into IPv6 addresses.
- CNAME record (Canonical Name): It’s used to create alias for a DNS name.
- TXT record: SPF, DKIM, DMARC, etc.
Now let’s edit the zone file.
sudo nano /var/named/named.example.com
By default, it looks like this:
You can change it to this instead.
Where
- The
$TTL
directive defines the default Time to Live value for the zone, which is the time a DNS record can be cached on a DNS resolver. This directive is mandatory. - The
$ORIGIN
directive defines the base domain. - Domain names must end with a dot (.), which is the root domain. When a domain name ends with a dot, it is a fully qualified domain name (FQDN).
- The @ symbol references to the base domain.
IN
is the DNS class. It stands for Internet. Other DNS classes exist but are rarely used.
The first record in a zone file is the SOA (Start of Authority) record. This record contains the following information:
- The master DNS server.
- Email address of the zone administrator. RFC 2142 recommends the email address [email protected]. In the zone file, this email address takes this form: hostmaster.example.com because the @ symbol has special meaning in zone file.
- Zone serial number. The serial number is a way of tracking changes in zone by the slave DNS server. By convention, the serial number takes a date format:
yyyymmddss
, where yyyy is the four-digit year number, mm is the month, dd is the day, and ss is the sequence number for the day. You must update the serial number when changes are made to the zone file. - Refresh value. When the refresh value is reached, the slave DNS server will try to read of the SOA record from the master DNS server. If the serial number becomes higher, a zone transfer is initiated.
- Retry value. Defines the retry interval if the slave DNS server fails to connect to the master DNS server.
- Expiry: If the slave DNS server has been failing to make contact with master DNS server for this amount of time, the slave will stop responding to DNS queries for this zone.
- Negative cache TTL: Defines the time to live value of DNS responses for non-existent DNS names (NXDOMAIN).
TXT records are usually enclosed in double quotes. If you add DKIM record, you also need to enclose the value with parentheses.
Save and close the file. Next, we should set named
as the group owner of the /var/named/named.example.com
file, or named won’t be able to load this zone.
sudo chown root:named /var/named/named.example.com
Then run the following command to check if there are syntax errors in the main configuration file. A silent output indicates no errors are found.
sudo named-checkconf
Then check the syntax of zone files.
sudo named-checkzone example.com /var/named/named.example.com
If there are syntax errors in the zone file, you need to fix it, or this zone won’t be loaded. The following message indicates there are no syntax errors.
zone example.com/IN: loaded serial 2020111216 OK
Then restart BIND9.
sudo systemctl restart named
Slave DNS Server Configuration
Now we use the other server as the slave DNS server, which will be named ns2.example.com
.
First, edit the named.conf
file.
sudo nano /etc/named.conf
Add the following line at the end of this file. This will add a slave zone. Replace 12.34.56.78 with the IP address of the master DNS server.
zone "example.com" { type slave; file "/var/named/slaves/named.example.com"; allow-query { any; }; masters { 12.34.56.78; }; };
In the above configuration, we specified that this is a slave DNS server for the example.com
zone. This zone allows query from any IP address. The allow-query
directive in this zone will override the global allow-query
directive. It will accept zone transfers only from the master DNS server.
Save and close the file. Then run the following command to check if there are syntax errors in the main configuration file.
sudo named-checkconf
If no errors are found, restart BIND9.
sudo systemctl restart named
The zone file on slave DNS server are loaded from a zone transfer, which is used to synchronize DNS record changes from master DNS server to slave DNS server. After BIND9 restarts, zone tranfer will start immediately. Check the BIND9 log with the following command.
sudo journalctl -eu named
You can see messages like below, which indicates the zone transfer is successful.
named[31518]: transfer of 'example.com/IN' from 12.34.56.78#53: Transfer completed: 1 messages, 16 records, 886 bytes, 0.004 secs (221500 bytes/sec)
More about Zone Transfer
The slave DNS server will contact the master again when the refresh time in SOA record is reached and if the serial number on the master is greater than that on the slave, a zone transfer will be initiated. There are two types of zone transfers:
- Full zone transfer (AXFR): The full copy of zone file is transferred.
- Incremental zone transfer (IXFR): Only DNS records that are changed are transferred.
Both types of zone transfer use TCP port 53. By default, BIND on the slave DNS server will request an incremental zone transfer and BIND on the master DNS server will only allow incremental zone transfer when the zone is dynamic.
The zone transfer interval is a major factor of the propagation speed of DNS record changes. Instead of waiting for the slave DNS server to make contact, the BIND master will notify the slave when changes are made to the zone. This can considerably reduce the time to propagate zone changes to the Internet.
Reverse Zone
A reverse zone contains PTR record that maps an IP address to a DNS name. It is the counterpart of DNS A record. PTR record often is necessary for mail servers to pass spam filters. This record does not belong to a domain. It’s managed by the organization that gives you an IP address. You need to create PTR record at your hosting provider’s control panel or ask your ISP, so I’m not going to cover creating reverse zones in BIND.
Change NS Record and Create Glue Record
Now you need to go to your domain registrar’s website to change the NS record for your domain, so the Internet would know that you are now using your own DNS server. Normally you use hostnames in the NS record like ns1.example.com
and ns2.example.com
.
name server 1: ns1.example.com name server 2: ns2.example.com
If you have a domain name example.com
and you use a subdomain for the authoritative DNS servers (ns1.example.com
and ns2.example.com
), then you also need to create a glue record at your domain registrar, so the Internet can know the IP address of your DNS server. The glue record is an A record for ns1.example.com
and ns2.example.com
.
ns1.example.com IP-address-of-master-server ns2.example.com IP-address-of-slave-server
The above information will be sent to a registry operator who runs TLD DNS servers via the Extensible Provisioning Protocol (EPP), so that TLD DNS servers know the name and IP addresses of the authoritative DNS servers for your domain name. Depending on the domain registrar you use, your NS record might be propagated instantly, or it might take up to 24 hours to propagate. You can go to https://dnsmap.io to check if your new NS record is active.
I will show you how to do this at NameCheap.
If you bought a domain name at NameCheap, then log into your NameCheap account. Select the Domain list
menu on the left sidebar, then click the Manage button on the far right.
Select Advanced DNS.
Scroll to the bottom of the page, you will find the personal DNS server section. Click the Add NameServer button to add your own name servers: ns1.example.com
and ns2.example.com
. You need to enter the IP addresses of your name servers.
After adding your two name servers, click the search button to check if they are added successfully. If so, the glue records will appear at the bottom of this page.
Now click the Domain
tab, and use your custom DNS server.
Depending on the domain registrar you use, your NS record might be propagated instantly, or it might take up to 24 hours to propagate. You can go to https://dnsmap.io to check if your new NS record is active.
After the glue record and NS record have been propagated to the Internet, your DNS servers would be responding to DNS queries for your domain name. You can check the query log with:
sudo journalctl -eu named
You can also use the dig
utility to check the NS record of your domain name.
dig NS example.com
If the NS record and glue record have been propagated to the Internet, you should see your name servers in the answer section. If you see the SERVFAIL
error, it’s probably because you didn’t open UDP port 53 on your name servers.
Things to Know
- The term
master DNS server
only implies that this server stores the master copy of the zone file. It has no higher priority when it comes to DNS resolution. - Always update the SOA serial number when you make changes to a zone file.
Named Automatic Restart
If for any reason your Named process is killed, you need to run the following command to restart it.
sudo systemctl restart named
Instead of manually typing this command, we can make Named automatically restart by editing the named.service
systemd service unit. To override the default systemd service configuration, we create a separate directory.
sudo mkdir -p /etc/systemd/system/named.service.d/
Then create a file under this directory.
sudo nano /etc/systemd/system/named.service.d/restart.conf
Add the following lines in the file, which will make Named automatically restart 5 seconds after a failure is detected.
[Service] Restart=always RestartSec=5s
Save and close the file. Then reload systemd.
sudo systemctl daemon-reload
To check if this would work, kill Named with:
sudo pkill named
Then check Named status. You will find Named automatically restarted.
systemctl status named
Enabling the Resolver
BIND can act as an authoritative DNS server for a zone and a DNS resolver at the same time. It’s a good practice to separate the two roles on two different machines and in this article we disabled the resolver in BIND. If you really want to enable the resolver, follow the instructions below.
Edit the BIND configuration file.
sudo nano /etc/named.conf
Find the following line.
recursion no;
Change no
to yes
.
recursion yes;
Then find the allow-query { localhost; };
line. You can add additional IP addresses like below, so only trusted clients send recursive queries to your DNS resolver and your server won’t be an open resolver.
allow-query { localhost; 12.34.56.78; };
Replace 12.34.56.78 with your own IP address. Save and close the file. Make sure your zone definition in the /etc/named.conf
file has the following option, so the Internet can query DNS records in your zone.
allow-query { any; };
Then restart BIND.
sudo systemctl restart named
Go to https://openresolver.com/ to test if your BIND server is an open resolver.
Wrapping Up
That’s it! I hope this tutorial helped you set up authoritative DNS server on CentOS 8/RHEL 8 with BIND9. As always, if you found this post useful, then subscribe to our free newsletter to get more tips and tricks. Take care 🙂
Hi,
My rate are 5 stars and i don’t know why sent 1 star
Very nice material…
please correct number of stars to 5 because i could not change my rate…
Thanks a lot
Hi,
I kept getting:
Don’t you need to set the following in /etc/named.conf?
Yes, you need to allow query from the public Internet.
You can add
allow-query { any; };
to a zone clause and keep the globalallow-query { localhost; };
directive. A directive in azone
clause overrides that in theoptions
clause.Thanks for the feedback. Any ideas on a good UI? I only know of webmin.
This is a really good tutorial, and I just used it while migrating my name server from CentOS 6 to 8.
I think I found one mistake. When you advise:
“You can add additional IP addresses like below, so only trusted clients send recursive queries to your DNS resolver and your server won’t be an open resolver.”
… and after that show a change in allow-query, you probably mean allow-recursion instead. It’s logical to allow query to anyone but limit recursion to only trusted users. Anyone must be able to query the domains where your server is authoritative.
I see this has already created some confusion, so please correct your tutorial to make it even better!
hello
i had configure authoritative dns server as you describe on your page.
i have register domain but not from the manecheap
i had configure internal and external zone. main problem is internal zone can resolve name and can access internet, internal webpage
but it does not work on externally .
if i access my web server from external network then it show the error the page not found
show what will be the problem here
view “internal” {
match-clients { localhost; localnets; };
allow-query { localhost; localnets; };
allow-recursion { localhost; localnets; };
allow-query-cache { localhost; localnets; };
recursion yes;
zone “.” IN {
type hint;
file “named.ca”;
};
zone “myzone.zone” {
type master;
file “internal/myzone.zone”;
allow-transfer { localhost; localnets; };
};
zone “lo.myzone” {
type master;
file “internal/lo.myzone.zone”;
allow-transfer { localhost; localnets; };
};
zone “199.168.192.in-addr.arpa” {
type master;
file “internal/lo.myzone.rev”;
allow-transfer { localhost; localnets; };
};
include “/etc/named.rfc1912.zones”;
include “/etc/named.root.key”;
};
view “external” {
match-clients { any; };
allow-query { any; };
allow-recursion { none; };
allow-query-cache { none; };
recursion no;
zone “myzone.com” {
type master;
file “external/myzone.com”;
allow-transfer { none; };
};
};
zone file
$TTL 3H
@ IN SOA ns.mydomain.net. root.ns.mydomain.net. (
0 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
IN NS ns.mydomain.net.
IN MX 10 mail.ns.mydomain.net.
localhost IN A 127.0.0.1
@ IN A 192.168.199.200
ns IN A 192.168.199.200
www1 IN A 192.168.199.215
mail IN A 192.168.199.200
; AAAA ::1
www IN CNAME www1.ns.mydomain.net.