How to Configure DNS Primary and Secondary Servers
Traducciones al EspañolEstamos traduciendo nuestros guías y tutoriales al Español. Es posible que usted esté viendo una traducción generada automáticamente. Estamos trabajando con traductores profesionales para verificar las traducciones de nuestro sitio web. Este proyecto es un trabajo en curso.
A single web server or a database going offline is a hassle, but what if all services became unreachable? That’s exactly what happens when Domain Name System (DNS) servers stop working.
Because networked services depend on DNS, it’s critical to add one or more secondary name servers for redundancy. Hardening DNS servers to protect against rogue updates and hiding the primary name server also helps ensure smooth DNS operation.
Our guide An Introduction to DNS on Linux explains how DNS works and how to build a primary name server. This guide configures a secondary name server for redundancy, adds secret keys for authentication, and a hidden primary name server for protection against attacks.
Before You Begin
Follow our Introduction to DNS on Linux guide to set up a functional primary name server (
ns1
).Create two Compute instances for our secondary name servers. This guide requires two new Ubuntu 22.04 LTS instances (
ns2
andns3
) in addition to the primary name server (ns1
).Follow our Setting Up and Securing a Compute Instance guide to update your systems. Also set the timezone, configure your hostnames, and create limited user accounts. To follow along with this guide, give your servers the hostnames
ns2
andns3
. Make them part of theyourdomainhere.com
domain (e.g.ns2.yourdomainhere.com
andns3.yourdomainhere.com
, replacingyourdomainhere.com
with your actual domain name). Also be sure to configure the hosts files with your hostnames and external IP addresses.
sudo
. If you’re not familiar with the sudo
command, see the
Users and Groups guide.Prepare the Primary DNS Server
Before setting up the secondary name server, configure the primary name server to send zone updates to it, and only it. To do this, configure a secret key that authenticates communications between primary and secondary name servers. The sample nsd.conf
file includes a comment showing how to generate a random string for use as a key.
Run this command on your primary name server:
ns1dd if=/dev/random of=/dev/stdout count=1 bs=32 | base64
The output should be similar to this:
7Q7KLOi44zuTjK/RavkFECLgglv6qkwN2y1GOdWFE/A= 1+0 records in 1+0 records out 32 bytes copied, 0.00053066 s, 60.3 kB/s
Copy and record the random string (e.g.
7Q7KLOi44zuTjK/RavkFECLgglv6qkwN2y1GOdWFE/A=
).Open the Name Server Daemon (NSD) configuration file
/etc/nsd/nsd.conf
:ns1sudo nano /etc/nsd/nsd.conf
Find and uncomment the
key:
section. Uncomment thename
statement and give the key a name (e.g.secretkey0
). Uncomment thealgorithm
statement and enterhmac-sha256
. Uncomment thesecret:
statement and use the random value generated above, in quotations.- File: /etc/nsd/nsd.conf
1 2 3 4 5 6 7 8 9
key: # The key name is sent to the other party, it must be the same name: "secretkey0" # algorithm hmac-md5, or sha1, sha256, sha224, sha384, sha512 algorithm: hmac-sha256 # secret material, must be the same as the other party uses. # base64 encoded random number. # e.g. from dd if=/dev/random of=/dev/stdout count=1 bs=32 | base64 secret: "7Q7KLOi44zuTjK/RavkFECLgglv6qkwN2y1GOdWFE/A="
Note This is not an actual secret key. Never paste secret or private keys into any public posting.Next, uncomment the
pattern:
section. A pattern is a macro that stores options for all zones. In this example, only one zone is set up. However, in production, where an NSD server may handle dozens to thousands of zones, patterns can save a lot of repetitive typing.Uncomment these lines to create a pattern, replacing
192.0.2.3
with the external IP address ofns2
:- File: /etc/nsd/nsd.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
pattern: # name by which the pattern is referred to name: "secondary_outbound" # the zonefile for the zones that use this pattern. # if relative then from the zonesdir (inside the chroot). # the name is processed: %s - zone name (as appears in zone:name). # %1 - first character of zone name, %2 second, %3 third. # %z - topleveldomain label of zone, %y, %x next labels in name. # if label or character does not exist you get a dot '.'. # for example "%s.zone" or "zones/%1/%2/%3/%s" or "secondary/%z/%s" #zonefile: "%s.zone" # The allow-query allows an access control list to be specified # for a zone to be queried. Without an allow-query option, any # IP address is allowed to send queries for the zone. # This could be useful for example to not leak content from a zone # which is only offered for transfer to secondaries over TLS. #allow-query: 192.0.2.0/24 NOKEY # If no master and slave access control elements are provided, # this zone will not be served to/from other servers. # A master zone needs notify: and provide-xfr: lists. A slave # may also allow zone transfer (for debug or other secondaries). # notify these slaves when the master zone changes, address TSIG|NOKEY # IP can be ipv4 and ipv6, with @port for a nondefault port number. notify: 192.0.2.3 secretkey0 # allow these IPs and TSIG to transfer zones, addr TSIG|NOKEY|BLOCKED # address range 192.0.2.0/24, 1.2.3.4&255.255.0.0, 3.0.2.20-3.0.2.40 provide-xfr: 192.0.2.3 secretkey0
This pattern tells the primary name server to notify a secondary name server of zone updates, and to respond to zone transfer requests from a specific nameserver. Both actions use your secret key.
If you have more secondary name servers, add them here with
notify
andprovide-xfr
statements for each.Modify any
zone:
statements to use the pattern(s):- File: /etc/nsd/nsd.conf
1 2 3 4 5 6 7
zone: name: "yourdomainhere.com" # you can give a pattern here, all the settings from that pattern # are then inserted at this point include-pattern: "secondary_outbound" # You can also specify (additional) options directly for this zone. zonefile: "zones/master/yourdomainhere.com.zone"
When done, press CTRL+X then Y and Enter to save and close the file.
Check the file’s syntax with
nsd-checkconf
:ns1nsd-checkconf /etc/nsd/nsd.conf
If the file returns no errors, restart the NSD server:
ns1sudo systemctl restart nsd
Now move on to secondary name server configuration.
Secondary Name Server Setup
This guide assumes that the Ubuntu 22.04 LTS secondary name server has a hostname of ns2
and that you know its IP addresses.
The new server can be in the same data center as the primary, but it doesn’t have to be. In fact, having name servers in different geographic locations helps protect against disasters in any one area. The tradeoff may be increased latency for some lookups.
Open an SSH session on the new secondary name server (
ns2
) and install NSD:ns2sudo apt install nsd
Configure the NSD control utility,
nsd-config
:ns2sudo nsd-control-setup
The output should appear as follows:
setup in directory /etc/nsd removing artifacts Setup success. Certificates created.
If not, check
/var/log/syslog
for errors.Copy
nsd.conf
to the secondary name server from the primary nameserver using thescp
secure-copy utility, substituting your domain name foryourdomainhere.com
:ns2sudo scp root@ns1.yourdomainhere.com:/etc/nsd/nsd.conf /etc/nsd
Gather
ns2
’s external IPv4 and IPv6 addresses. Follow this guide to Find Your Linode’s IP Address or use the following command:ns2ip a
Open
/etc/nsd/nsd.conf
:ns2sudo nano /etc/nsd/nsd.conf
Modify the
ip-address
statements in theserver:
section to use the secondary server’s (ns2
) IP addresses, including IPv6 addresses if you’ve configured them:- File: /etc/nsd/nsd.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
server: # Number of NSD servers to fork. Put the number of CPUs to use here. # server-count: 1 # Set overall CPU affinity for NSD processes on Linux and FreeBSD. # Any server/xfrd CPU affinity value will be masked by this value. # cpu-affinity: 0 1 2 3 # Bind NSD server(s), configured by server-count (1-based), to a # dedicated core. Single core affinity improves L1/L2 cache hits and # reduces pipeline stalls/flushes. # # server-1-cpu-affinity: 0 # server-2-cpu-affinity: 1 # ... # server-<N>-cpu-affinity: 2 # Bind xfrd to a dedicated core. # xfrd-cpu-affinity: 3 # Specify specific interfaces to bind (default are the wildcard # interfaces 0.0.0.0 and ::0). # For servers with multiple IP addresses, list them one by one, # or the source address of replies could be wrong. # Use ip-transparent to be able to list addresses that turn on later. ip-address: 192.0.2.3 ip-address: 2001:DB8::3
The rest of the
server:
,remote-control:
, andkey:
sections don’t require any additional changes, but thepattern:
andzone:
sections do.First, change the
pattern:
name
to something specific to the secondary name server (e.g.secondary_inbound
). Comment out thenotify
andprovide-xfr
statements. Uncomment theallow-notify
statement and change its value to the primary name server’s (ns1
) IP address followed bysecretkey0
. Do the same to therequest-xfr
statement, but also add the AXFR transfer type. AXFR is the DNS zone transfer protocol. Here is the updated pattern section:- File: /etc/nsd/nsd.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
pattern: # name by which the pattern is referred to name: "secondary_inbound" # the zonefile for the zones that use this pattern. # if relative then from the zonesdir (inside the chroot). # the name is processed: %s - zone name (as appears in zone:name). # %1 - first character of zone name, %2 second, %3 third. # %z - topleveldomain label of zone, %y, %x next labels in name. # if label or character does not exist you get a dot '.'. # for example "%s.zone" or "zones/%1/%2/%3/%s" or "secondary/%z/%s" #zonefile: "%s.zone" # The allow-query allows an access control list to be specified # for a zone to be queried. Without an allow-query option, any # IP address is allowed to send queries for the zone. # This could be useful for example to not leak content from a zone # which is only offered for transfer to secondaries over TLS. #allow-query: 192.0.2.0/24 NOKEY # If no master and slave access control elements are provided, # this zone will not be served to/from other servers. # A master zone needs notify: and provide-xfr: lists. A slave # may also allow zone transfer (for debug or other secondaries). # notify these slaves when the master zone changes, address TSIG|NOKEY # IP can be ipv4 and ipv6, with @port for a nondefault port number. # notify: 192.0.2.0 secretkey0 # allow these IPs and TSIG to transfer zones, addr TSIG|NOKEY|BLOCKED # address range 192.0.2.0/24, 1.2.3.4&255.255.0.0, 3.0.2.20-3.0.2.40 # provide-xfr: 192.0.2.0 secretkey0 # set the number of retries for notify. #notify-retry: 5 # uncomment to provide AXFR to all the world # provide-xfr: 0.0.0.0/0 NOKEY # provide-xfr: ::0/0 NOKEY # A slave zone needs allow-notify: and request-xfr: lists. allow-notify: 192.0.2.2 secretkey0 # By default, a slave will request a zone transfer with IXFR/TCP. # If you want to make use of IXFR/UDP use: UDP addr tsigkey # for a master that only speaks AXFR (like NSD) use AXFR addr tsigkey # If you want to require use of XFR-over-TLS use: addr tsigkey tlsauthname request-xfr: AXFR 190.0.2.2 secretkey0
In the
zone:
section, point to a zone file in thesecondary
directory. Use the new pattern name defined above for the secondary name server forinclude-pattern
. As usual, substitute your own domain name foryourdomainhere.com
.- File: /etc/nsd/nsd.conf
1 2 3 4
zone: name: "yourdomainhere.com" zonefile: "zones/secondary/yourdomainhere.com.zone" include-pattern: "secondary_inbound"
When complete, save and close the file.
Check the configuration:
ns2nsd-checkconf /etc/nsd/nsd.conf
If no errors are returned, restart NSD:
ns2sudo systemctl restart nsd
Test Both Name Servers
Two tests can verify if both name servers work as intended. First, run queries against both name servers to verify that both respond with DNS records. Second, add a new record on the primary name server (ns1
) and check if it propagates to the secondary name server (ns2
).
For both tests, use the dig
utility, which comes included in the Linode distribution of Ubuntu 22.04 LTS. The fairly verbose output thatdig
produces by default is not needed here, so use the +short
argument in all these commands. Also, query a specific name server by prepending the @
character to any hostname.
Here is a sample query against the primary name server:
ns2dig john.yourdomainhere.com +short @ns1.yourdomainhere.com
96.126.102.179
Now run the same test against the secondary name server:
ns1dig john.yourdomainhere.com +short @ns2.yourdomainhere.com
96.126.102.179
Congratulations! The primary and secondary name servers are now working as intended. Next, verify transfers work between the primary and secondary name servers by adding a new resource record on the primary name server.
On the primary name server, open the zone file for
yourdomainhere.com
(/etc/nsd/zones/master/yourdomainhere.com.zone
):ns1sudo nano /etc/nsd/zones/master/yourdomainhere.com.zone
Increment the zone file’s serial number. This is very important as NSD does not load changes to the zone unless the zone file’s serial number increments. In this example, simply increment the serial number’s final digit by 1:
- File: /etc/nsd/zones/master/yourdomainhere.com.zone
1 2
Old: 2023030701 New: 2023030702
Then add an A record for a new host:
- File: /etc/nsd/zones/master/yourdomainhere.com.zone
1
brian A 96.126.102.183
When finished, save and close the file.
Reload the zone:
ns1sudo nsd-control reload yourdomainhere.com
Run a
dig
query on the secondary name server for the new hostname:ns1dig -t a brian.yourdomainhere.com +short @ns2.yourdomainhere.com
192.0.2.15
This validates automatic zone transfers. Even if there are 100 secondary name servers, changes would only need to be made on the primary, and every secondary would still produce this output.
Hidden Primary Name Server Configuration
A hidden primary name server works the same way as the current primary when it comes to zone transfers. All secondary name servers still get zone updates from it. The only difference is that a hidden primary is never listed in the public DNS. It’s neither authoritative for any zone, nor do you delegate any authority to it at your registrar. Instead, all the “authoritative” name servers you list, both in registrar delegations and in each zone’s NS records, are actually secondary name servers that receive updates from the hidden primary.
Because attackers don’t know the hidden primary exists, they can’t try to compromise your configuration or zone files. Of course, you still need to update Linux and protect access to the hidden primary, as with any system.
Make use of the existing ns1
and ns2
by converting them to secondaries, and configuring ns3
to serve as the new hidden primary, like so:
ns1.yourdomainhere.com
(secondary)ns2.yourdomainhere.com
(secondary)ns3.yourdomainhere.com
(hidden primary)
There is no requirement that the hidden primary reside in the same data center as either of the secondaries. However, if one or more name servers are in the same data center, they can use private addresses (e.g. 192.168.173.25
) for zone transfers. These addresses aren’t routable on the public Internet.
Open an SSH session to the
ns3
instance and install NSD:ns3sudo apt install nsd
Configure the NSD control utility,
nsd-config
:ns3sudo nsd-control-setup
The output should appear as follows:
setup in directory /etc/nsd removing artifacts Setup success. Certificates created.
If not, check
/var/log/syslog
for errors.Copy
nsd.conf
fromns1
(the original primary name server) using thescp
secure-copy utility, and remember to replaceyourdomainhere.com
with your actual domain name:ns3sudo scp root@ns1.yourdomainhere.com:/etc/nsd/nsd.conf /etc/nsd
Also copy the entire zones directory structure:
ns3sudo scp -r root@ns1.yourdomainhere.com:/etc/nsd/zones /etc/nsd
Gather
ns3
’s external IPv4 and IPv6 addresses. Follow this guide to Find Your Linode’s IP Address or use the following command:ns3ip a
Open
/etc/nsd/nsd.conf
:ns3sudo nano /etc/nsd/nsd.conf
Replace the existing
ip-address
statements in theservers:
section withns3
’s addresses, including IPv6 addresses if you’ve configured them:- File: /etc/nsd/nsd.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
server: # Number of NSD servers to fork. Put the number of CPUs to use here. # server-count: 1 # Set overall CPU affinity for NSD processes on Linux and FreeBSD. # Any server/xfrd CPU affinity value will be masked by this value. # cpu-affinity: 0 1 2 3 # Bind NSD server(s), configured by server-count (1-based), to a # dedicated core. Single core affinity improves L1/L2 cache hits and # reduces pipeline stalls/flushes. # # server-1-cpu-affinity: 0 # server-2-cpu-affinity: 1 # ... # server-<N>-cpu-affinity: 2 # Bind xfrd to a dedicated core. # xfrd-cpu-affinity: 3 # Specify specific interfaces to bind (default are the wildcard # interfaces 0.0.0.0 and ::0). # For servers with multiple IP addresses, list them one by one, # or the source address of replies could be wrong. # Use ip-transparent to be able to list addresses that turn on later. ip-address: 192.0.2.4 ip-address: 2001:DB8::4
Next, add additional
notify
andprovide-xfr
statements in thepattern:
section. Replace the IP addresses with those ofns1
andns2
:- File: /etc/nsd/nsd.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
pattern: # name by which the pattern is referred to name: "secondary_outbound" # the zonefile for the zones that use this pattern. # if relative then from the zonesdir (inside the chroot). # the name is processed: %s - zone name (as appears in zone:name). # %1 - first character of zone name, %2 second, %3 third. # %z - topleveldomain label of zone, %y, %x next labels in name. # if label or character does not exist you get a dot '.'. # for example "%s.zone" or "zones/%1/%2/%3/%s" or "secondary/%z/%s" #zonefile: "%s.zone" # The allow-query allows an access control list to be specified # for a zone to be queried. Without an allow-query option, any # IP address is allowed to send queries for the zone. # This could be useful for example to not leak content from a zone # which is only offered for transfer to secondaries over TLS. #allow-query: 192.0.2.0/24 NOKEY # If no master and slave access control elements are provided, # this zone will not be served to/from other servers. # A master zone needs notify: and provide-xfr: lists. A slave # may also allow zone transfer (for debug or other secondaries). # notify these slaves when the master zone changes, address TSIG|NOKEY # IP can be ipv4 and ipv6, with @port for a nondefault port number. notify: 192.0.2.2 secretkey0 notify: 192.0.2.3 secretkey0 # allow these IPs and TSIG to transfer zones, addr TSIG|NOKEY|BLOCKED # address range 192.0.2.0/24, 1.2.3.4&255.255.0.0, 3.0.2.20-3.0.2.40 provide-xfr: 192.0.2.2 secretkey0 provide-xfr: 192.0.2.3 secretkey0
When done, save and close the file, but don’t restart NSD just yet. First, configure both existing name servers to pull updates from
ns3
, and changens1
from a primary to a secondary name server.Open
/etc/nsd/nsd.conf
on bothns1
andns2
:ns1 and ns2sudo nano /etc/nsd/nsd.conf
Edit the files so the statements in the
pattern:
andzone:
sections indicate that these are now secondary servers, and are to get their updates fromns3
:- File: /etc/nsd/nsd.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
pattern: # name by which the pattern is referred to name: "secondary_inbound" # the zonefile for the zones that use this pattern. # if relative then from the zonesdir (inside the chroot). # the name is processed: %s - zone name (as appears in zone:name). # %1 - first character of zone name, %2 second, %3 third. # %z - topleveldomain label of zone, %y, %x next labels in name. # if label or character does not exist you get a dot '.'. # for example "%s.zone" or "zones/%1/%2/%3/%s" or "secondary/%z/%s" #zonefile: "%s.zone" # The allow-query allows an access control list to be specified # for a zone to be queried. Without an allow-query option, any # IP address is allowed to send queries for the zone. # This could be useful for example to not leak content from a zone # which is only offered for transfer to secondaries over TLS. #allow-query: 192.0.2.0/24 NOKEY # If no master and slave access control elements are provided, # this zone will not be served to/from other servers. # A master zone needs notify: and provide-xfr: lists. A slave # may also allow zone transfer (for debug or other secondaries). # notify these slaves when the master zone changes, address TSIG|NOKEY # IP can be ipv4 and ipv6, with @port for a nondefault port number. # notify: 192.0.2.3 secretkey0 # allow these IPs and TSIG to transfer zones, addr TSIG|NOKEY|BLOCKED # address range 192.0.2.0/24, 1.2.3.4&255.255.0.0, 3.0.2.20-3.0.2.40 # provide-xfr: 192.0.2.2 secretkey0 # set the number of retries for notify. #notify-retry: 5 # uncomment to provide AXFR to all the world # provide-xfr: 0.0.0.0/0 NOKEY # provide-xfr: ::0/0 NOKEY # A slave zone needs allow-notify: and request-xfr: lists. allow-notify: 192.0.2.3 secretkey0 # By default, a slave will request a zone transfer with IXFR/TCP. # If you want to make use of IXFR/UDP use: UDP addr tsigkey # for a master that only speaks AXFR (like NSD) use AXFR addr tsigkey # If you want to require use of XFR-over-TLS use: addr tsigkey tlsauthname request-xfr: AXFR 192.0.2.3 secretkey0
- File: /etc/nsd/nsd.conf
1 2 3 4 5 6 7
zone: name: "yourdomainhere.com" # you can give a pattern here, all the settings from that pattern # are then inserted at this point include-pattern: "secondary_inbound" # You can also specify (additional) options directly for this zone. zonefile: "zones/secondary/yourdomainhere.com.zone"
When complete, save and close the files on both
ns1
andns2
.Restart NSD on all three name servers:
ns1, ns2, and ns3sudo systemctl restart nsd
From now on, any changes made on the hidden primary (ns3
) propagate to the secondary name servers (ns1
and ns2
). As before, verify this by adding a new resource record to the yourdomainhere.com
zone file on ns3
. After reloading the zone, query the secondary name servers to see the new record.
You don’t need to make any changes at your domain registrar. To anyone on the public Internet, the now-secondary name servers at ns1
and ns2
are still authoritative for yourdomainhere.com
.
Conclusion
Redundancy is important for any networked service, but none more so than DNS. Given the dependency of virtually all other services on a functioning DNS infrastructure, it’s important to ensure the loss of any one name server doesn’t affect availability. Given the critical role of the primary name server, security measures such as secret keys and a hidden primary can maximize uptime, not only for your DNS servers, but for all services that depend on it.
More Information
You may wish to consult the following resources for additional information on this topic. While these are provided in the hope that they will be useful, please note that we cannot vouch for the accuracy or timeliness of externally hosted materials.
This page was originally published on