LowEndBox - Cheap VPS, Hosting and Dedicated Server Deals

Setup a DNS Nameserver Using NSD

You can still buy little 128MB VPSes for $10-15 per year and they are perfect for serving DNS.  A nameserver does not take much memory or CPU. Indeed, once it’s setup, you’ll probably find your nameserver isn’t doing much at all, because so much is cached with other DNS servers. It just serves as the authority.  Of course, if you have bigger VPSes, they can do double duty as DNS nameservers as well.

Why not just use your registrar’s DNS?  Why not indeed – often that is a great option.  But if you want more control or if you want to make updating DNS records part of some automated workflow, then you’ll want to run your own nameservers.

This tutorial is geared towards a super-simple (dare we say lowend?) DNS setup. We’ll be using NSD, a very lightweight DNS server. While the most-widely used package is BIND, BIND is designed to support every possible option and feature, which is overkill for most people. If you just want to setup DNS for your servers and act as the authority for your domain, NSD is a much simpler solution. I’m also going to give you the basics and defaults, without getting into explaining every single option.

DNS can be complex! But this will get you going on a basic setup.

Things I won’t be covering:

  • reverse DNS: typically this is setup through your hosting provider
  • zone transfers: but I’ll show you how to setup two authoritative NSD servers and synchronize them
  • MX records: but it’s obvious how to set them up once you’ve mastered the steps below

Here is how we’ll configure NSD:

  • Two servers, each of which listen for DNS on their public interfaces.
  • /etc/nsd/nsd.conf will contain the NSD configuration specific to that server
  • /etc/nsd/zones will contain all the zone files (the DNS records for your domain(s))
  • We’ll use rsync to keep both servers in sync. NSD supports zone transfers, but it complicates the setup and is unnecessary if all you’re doing is DNS for a few domains and it doesn’t change much. If you have a lot of DNS changes and a complex setup, then this tutorial isn’t for you :-)

In this example, we’re setting up DNS for this configuration:

Nameserver #1: ns1.example.com at
Nameserver #2: ns2.example.com at
bigvps.example.com is a web server at
www.example.com is an alias for bigvps

Of course, you can’t host DNS for example.com – only the owner of example.com can. So replace ‘example.com’ with your own domain.

I’m using CentOS 7 but the procedure is very similar for other distros and chiefly only differs in the way you get the package for your OS.

Step One: Install nsd

We’ll start on ns1. I recommend using your distro’s package manager. For CentOS, you will need to use the EPEL repo.

yum -y install epel-release
yum install nsd
systemctl enable nsd

On Debian:

apt-get install nsd
systemctl enable nsd

Step Two: Open firewall ports

If you’re not using a firewall, you can skip this. If you’re using iptables, then you’ll need to open port 53 for udp. The exact configuration will depend on how you’ve setup your firewall, but it’ll be something that looks like this:

iptables -A INPUT -p udp --dport 53 -j ACCEPT

Of course, if you’re firewalling outgoing as well, you’d need to open a port on OUTPUT, too.  If you’re using a firewall package such as ConfigServer, etc. check your firewall documentation.  The main thing is that DNS needs port 53 UDP incoming and outgoing

Step Three: Configure nsd.conf

The main config file is in /etc/nsd/nsd.conf. Here is an example. You should probably save the file that comes with nsd for future reference:

cp /etc/nsd/nsd.conf /etc/nsd/nsd.conf.dist

Now edit /etc/nsd/nsd.conf as follows:

# The 'server:' section is the configuration for the DNS server
# this is the IP address it will listen on for DNS requests
# change this to the public-facing IP address of your VPS

# no need to tell people what version we're running
hide-version: yes

# the database to use
database: "/var/lib/nsd/nsd.db"

# log file
logfile: "/var/log/nsd.log"

# Number of NSD servers to fork.
server-count: 1

# we'll use a separate "zone list" file to make rsync easier
include: "/etc/nsd/zones/zone_list.conf"

Very simple!

Step Four: Configure zone_list.conf

This file is simply a list of all the zones. You could put this info in the main nsd.conf file, but our goal is to use rsync to keep the two nameservers in sync. We don’t want to rsync nsd.conf itself, because the ip-address field is unique to each server. We only want to rsync what changes, which is the zone files. So we’ll be rsyncing the zone files and the zone_list.conf, which is a list of the zone files.

The zone files can be owned by nsd or root. I have mine owned by root, so the nsd user can read them but not change them.

mkdir /etc/nsd/zones
vi /etc/nsd/zones/zone_list.conf

zone_list.conf should look like this:

name: example.com
zonefile: /etc/nsd/zones/example.com

This means “there will be a zone named example.com, and you can find its records in /etc/nsd/zones/example.com”. You can define as many zones here as you want.

Step Four: Lather, Rinse, Repeat on ns2

Do steps 1-3 for ns2.example.com. The only thing you need to change is the ip-address line in /etc/nsd/nsd.conf

Step Five: Configure zone_list.conf

This is probably the most complicated part. The format of the zone file is the same one BIND uses.

Back on ns1, edit /etc/nsd/zones/example.com:

$ORIGIN example.com. 
$TTL 3600

@ IN SOA ns1.example.com. admin.example.com. (
2011102301 ; serial number
28800 ; Refresh
7200 ; Retry
864000 ; Expire
86400 ; Min TTL

IN NS ns1.example.com.
IN NS ns2.example.com.

ns1 IN A
ns2 IN A
bigvps IN A
www IN CNAME bigvps

Well, what a lot of arcane syntax! Let’s take it line by line, but first, let me point out something very important: the dots at the end of domain names as shown here are very important. When you say “ns1.example.com.” (with the trailing dot) it means “treat that as the FQDN). If you just typed “ns1.example.com” you’d actually mean “ns1.example.com.example.com” which is not what you want.

Now let’s look through the file:

$ORIGIN example.com.

“This is the origin of all DNS information on example.com”. This line must be first. Again, note the trailing dot.

$TTL 3600

TTL means “time to live” which means “other DNS servers, you should cache this for 3600 seconds (one hour)”. That is a good setting.

@ IN SOA ns1.example.com. admin.example.com. (

“SOA” is “Start of Authority”. @ is shorthand for “example.com.” The two names that follow it are the primary DNS server and then an email contact, rewritten in a dot notation format. In this case, admin.example.com. means “admin@example.com”.

2020050101 ; serial number
28800 ; Refresh
7200 ; Retry
864000 ; Expire
86400 ; Min TTL

Since we’re not doing zone transfers, only the ‘serial number’ really matters. But it’s important! Every time you change this file, you need to increment the serial number.

An old trick is to use a YYYYMMDDXX format, so the first change on May 1, 2020 is 2020050101, the second change on that day would be 2020050102, etc. You could of course just use 1, 2, 3, etc., but the date format is commonly done.

The point of the serial number increment is that this tells other DNS resolvers (and yours) if the file has changed. Otherwise, they don’t bother reparsing it.

I’m not going to go into the other records (refresh, retry, etc.) If you want to read up on them, try this link:


IN NS ns1.example.com.
IN NS ns2.example.com.

These define what nameservers are valid for this domain. You need to have at least two (at least, you really should :-)

ns1 IN A
ns2 IN A
bigvps IN A
www IN CNAME bigvps

Finally, we get into the actual records. Here we’ve defined three “A” records and one “CNAME” record. There are other types, but these are the most common. MX (for mail exchange) is the next most common type.

An A record is a forward DNS record. In this case, if you ask the nameserver “what is the IP address for bigvps.example.com” it will tell you “”. We’ve defined three such records here.

A CNAME record is an alias. You can have as many aliases as you want. For example, you might have Apache/NGINX setup to host forum.example.com, http://www.example.com, and gallery.example.com on the same host:

bigvps IN A
www IN CNAME bigvps
forum IN CNAME bigvps
gallery IN CNAME bigvps

Step Six: rsync

Now you’ve finished the zone list setup on ns1. You should have an entry for example.com in your /etc/nsd/zones/zone_list.conf file, and the above DNS record in /etc/nsd/zones/example.com file. You want to get these files to ns2. From ns1:

cd /etc/nsd
rsync -avz zones ns2:/etc/nsd

You could also use scp if you wished.

Step Seven: start nsd

On both ns1 and ns2, we first need to “compile” the zones and then we can start:

nsdc rebuild
/etc/init.d/nsd start

Do the same thing on ns2.

Later when you add more records, you can do this:

  • Modify on ns1. Don’t forget to increment serial numbers :-)
  • If you add a new domain (zone), put the corresponding zone: entry in /etc/nsd/zones/zone_list.conf
  • rsync to ns2 to keep it in sync

On both ns1 and ns2, execute “nsdc rebuild” and “nsdc reload”. This will load the changes without having to stop/start nsd.

Step Eight: Your Registrar

You’ll need to use your registrar’s web site to set the nameservers for your domain. For example.com, you need to define both the nameserver (ns1.example.com) and the IP address. For other domains you want to use ns1.example.com/ns2.example.com as DNS authorities, you just specify the DNS servers. So, for example, if you bought yahoo.com and wanted to use ns1.example.com and ns2.example.com to do the DNS, you’d set the DNS nameservers for yahoo.com to ns1.example.com and ns2.example.com (and of course create the zone file/zone list entry).



No Comments

    Leave a Reply

    Some notes on commenting on LowEndBox:

    • Do not use LowEndBox for support issues. Go to your hosting provider and issue a ticket there. Coming here saying "my VPS is down, what do I do?!" will only have your comments removed.
    • Akismet is used for spam detection. Some comments may be held temporarily for manual approval.
    • Use <pre>...</pre> to quote the output from your terminal/console, or consider using a pastebin service.

    Your email address will not be published. Required fields are marked *