title: Authoritative-only name server on Debian x-toc-enable: true ...
This guide was last tested on Debian 11.
An authoritative name server is the one responsible for handling a zone, which in this context would be your domain name. Authoritative-only means that the server only handles your domain names, as defined, and nothing else.
Typically, when you order webhosting from a hosting company, they will give you
access to their name servers (e.g. ns1.webhostingcompany.com
and ns2.webhostingcompany.com
) - many CDN and domain name registrars also
provide this to customers. It is here where your domains are configured,
specifying where your servers (e.g. HTTP, email) are located on the internet.
In this tutorial, you will learn how to do it yourself. It can be done inexpensively in an afternoon. This guide does not show you how to create an open resolver like what you would use to resolve just about any domain; this can be covered later in a separate guide.
Let's get started!
You need two IPv4 addresses and two IPv6 addresses, with port 53 open on all of them. IP routing and packet filtering are beyond the scope of this tutorial, and it is assumed that you already have this covered.
You might check the router section for guidance, if you do not yet meet the above requirement.
You need a domain name, such as example.com
, and your registrar must
support setting glue records (including IPv6 ones). Your registrar should
ideally support DNSSEC, in case you want to use that.
The registrar gandi.net is excellent, and meets this criteria. It is a solid company, very friendly to libre software projects.
This list contains references to many registrars, including Gandi. On this list, you may find ones that support IPv6 Glue:
https://www.sixxs.net/faq/dns/?faq=ipv6glue
Not all TLD zone operators support IPv6 glue, regardles of chosen registrar.
The sixxs.net link, above, provides a list of TLD zones known to support IPv6
glue, e.g. org
and info
can do it. Check the list BEFORE registering a
domain name!
If your current domain name registrar does not meet this criteria, you should consider migrating your domain name(s) to another registrar.
Log in to your domain name registrar account, e.g. Gandi account, and
look for a section pertaining to your domain name. In this guide, I'm going
to use my domain name shlinux.org
as an example, because I own that domain
and I run these on it: ns1.shlinux.org
and ns2.shlinux.org
- the Fedfree
site uses these name servers, for its DNS configuration.
Normally, if you outsource your DNS hosting, you just set the NS record for
your domain name, in your registrar login, specificing ns1.domain.com
and ns2.domain.com
, or whatever you have; here, you are only specifying
names.
Because you're running your own DNS, you must also specify an IP address, in the glue record of your name server domain. You do not have to use the same top-level domain name for the two name servers, but for simplicity we will assume that you are going to use the same domain.
The glue record exists because the NS record is still set accordingly, but it's referring to itself. The glue record is basically equivalent functionally to an A/AAAA record.
Set the glue records to all those IPs which you intend to use. In my example, I have these records (on my Gandi account, which I use for my own name servers):
ns1.shlinux.org
(IPv4): 81.187.172.130
ns1.shlinux.org
(IPv6): 2001:8b0:b95:1bb5::2
ns2.shlinux.org
(IPv4): 81.187.172.131
ns2.shlinux.org
(IPv6): 2001:8b0:b95:1bb5::3
You can actually specify more than this, but we will assume that you have two IPv4 and two IPv6 addresses, which is the minimum requirement for dual stack name servers.
You must also still set the usual NS records. I set my name servers
for shlinux.org
to ns1.shlinux.org
and ns2.shlinux.org
, and the glue
record makes it work.
The name server itself shall also declare the name NS records, and A/AAAA records, thus: ns1, ns2 (correct for the above example, but you should adapt accordingly). More on this later.
Install Debian, on the target machine. You must configure it, so that it has 2 public IPv4 and 2 public IPv6 addresses, directly pingable from the internet on all addresses, with port 53 open on all of them.
If you need a tunnel connection, for routing static IPs to your machine, you may check the guides in the router section.
Great! Now install bind9 on the machine. We shall configure ISC's bind9
.
Install it with the package manager:
apt-get install bind9
We will not be configuring a slave name server, in this tutorial; such will be covered later as a follow-up to this one. In this guide, we will assume that bind9 master and slave are both running on the same host, with 2 public IPv4 and 2 public IPv6 addresses allocated. This technically means that there is no slave, but it does work, so long as you have 2 IPv4 and (if using IPv6) 2 IPv6 addresses assigned on your host, all publicly routed with port 53 open.
For your convenience, Fedfree has included reference configs for you to use, on the Fedfree website. You may simply download it and install it:
Download this file: debian-bind-no-slave.tar.xz
NOTE: The sample configs do not provide for DNSSEC, nor will DNSSEC be configured in this tutorial; such will be covered, in a follow-up guide.
Extract it:
tar -xf debian-bind-no-slave.tar.xz
You should have have a directory named bind
. This is a series of sample
configurations, but they are actually used in the real world, for my
hosting (at least in December 2022). I've not included all zone files in
there, for all domains, because that would be excessive for the purpose of this
tutorial.
DO NOT simply use these configs as-is, of course. They won't work for you, because they contain configuration for my IPs and domains. In the next sections, we will go through everything.
Firstly, with bind9 already installed, delete /etc/bind
like so (as root):
rm -Rf /etc/bind
You will replace the bind
directory in /etc
, with the bind
directory
that you just extracted, from debian-bind-no-slave.tar.xz
Like so (as root):
cp -R bind /etc/bind
In the next sections, we will cover various files, explaining what they are and, where modifications are required, what to modify.
This file is provided by the Internet Systems Consortium, and should not
be modified directly. It contains keys which override the built-in ones
that bind9 comes with. These are used for the 13 root name servers that
exist (a.root-servers.net
, b.root-servers.net
... all the way up
to m.root-servers.net
) which handle top level domains. DNS is centralised,
but NS/Glue records are set upstream which delegate to an authoritative
name server for your zone, e.g. example.com
.
Again, never modify this file directly. However, you check should at least once every month for a new version. It doesn't change often, but you can find newer versions of this file here:
The version provided by Fedfree, identical to the one taken from ISC, was up to date as of 25 December 2022.
This file defines what the root name servers are. On the internet, there
are 13 of them, starting from a.root-servers.net
,
to b.root-servers.net
... all the way to m.root-servers.net
.
This file should not be modified directly. It is provided by InterNIC, and you should check for updates at least once every month (it doesn't change very often, but once per month should be more than thorough enough).
You can find updated versions on ftp.internic.net
(FTP protocol) in the
directory /domain/
, file name named.cache
.
The version provided by Fedfree, identical to the one takes from InterNIC, was up to date as of 25 December 2022.
Zone file for IP address (zone) 127.0.0.1
, resolving to localhost.
Zone file for empty RFC 1918 zone.
localhost forward and reverse zones. (RFC 1912 compliance)
This file does not need to be modified. Explaining some of the settings inside it:
allow-transfer { none; };
The allow-transfer
line pertains to master and slave. Because we're not
configuring a slave, we can ignore this entirely.
recursion no;
If recursion
is enabled, this would become a resolver, the kind you
would set up for resolving any domain name on the internet. We only want
this to be an authoritative domain name server, for our domains, so this
is set to no
.
dnssec-validation auto;
This pertains to DNSSEC, when we are resolving names from other name servers. This setting is entirely irrelevant, for the purposes of the tutorial. We can leave this alone (but please do leave it there).
auth-nxdomain no;
If auth-nxdomain
set to yes
, our server would respond authoritatively
even for zones not in our control. We only want it to be authoritative
for our zones, so we set this to no
.
listen-on-v6 { any; };
This one should be self-explanatory. It enables BIND to listen on IPv6
addresses. We want dual stack IPv4 and IPv6 operation, so the
the any
setting makes this work accordingly.
Reverse rules for broadcast zone (zero addresses). Leave this as-is.
Ditto.
Forward rules for local loopback addresses e.g. 127.0.0.1
or ::1
,
resolving to localhost
.
This is the main configuration file for bind9. In our case, using the sample files, this simply links to sub-configuration files such as named.conf.options as described above.
File contents, for reference:
include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
include "/etc/bind/named.conf.default-zones";
This file is important. In here, we define zones e.g. shlinux.org
.
For each specified zone, the path to a zone file is defined.
Please pay close attention.
File contents, in our reference configs:
zone "libreboot.org" {
type master;
file "/etc/bind/zones/db.libreboot.org";
};
zone "shlinux.org" {
type master;
file "/etc/bind/zones/db.shlinux.org";
};
zone "fedfree.org" {
type master;
file "/etc/bind/zones/db.fedfree.org";
};
zone "130.172.187.81.in-addr.arpa" {
type master;
file "/etc/bind/zones/db.ipv4ns1";
};
zone "2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.5.b.b.1.5.9.b.0.0.b.8.0.1.0.0.2.ip6.arpa" {
type master;
file "/etc/bind/zones/db.ipv6ns1";
};
Remove the libreboot/shlinux/fedfree entries and put your own ones in there,
for your domain names. In this guide, we will assume that you place your own
zone files under the directory /etc/bind/zones
. The zone files shall
contain within them, all DNS entries such as AAAA/A, NS, TXT, CAA and so on.
Information about what goes in these files will be covered later on in the
guide.
In the above entries, you see the final two look very strange indeed!
These are reverse zones, for IP addresses. These are taken (on 25 December
2022) for the ns1.shlinux.org
name server. On that day, it had these IP
addresses:
81.187.172.130
(IPv4 ns1.shlinux.org
)81.187.172.131
(IPv4 ns2.shlinux.org
)2001:8b0:b95:1bb5::2
(IPv6 ns1.shlinux.org
)2001:8b0:b95:1bb5::3
(IPv6 ns2.shlinux.org
)We will cover those zone files first, when we get to zone files. For now,
you should modify the file named.conf.local
like so:
Your ns1 IPv4 address first: run this command:
host IPv4address
You will get an in-addr.arpa
address, much like the above. For the entry
pertaining to db.ipv4ns1
, set the zone
name accordingly. For example,
the IP address 1.2.3.4 would become 4.3.2.1.in-addr.arpa
.
The IPv6 address 2001:8b0:b95:1bb4:4
entry, for the part pertaining
to db.ipv6ns1
, would
be: 4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.4.b.b.1.5.9.b.0.0.b.8.0.1.0.0.2.ip6.arpa
You will note that the IP addresses are backwards, in the above examples. These are the built-in reverse DNS entries for your IPs. All IPv4 and IPv6 addresses have them.
Taking the two fictional examples as above, we would modify those entries, thus:
zone "4.3.2.1.in-addr.arpa" {
type master;
file "/etc/bind/zones/db.ipv4ns1";
};
zone "4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.4.b.b.1.5.9.b.0.0.b.8.0.1.0.0.2.ip6.arpa" {
type master;
file "/etc/bind/zones/db.ipv6ns1";
};
In the IPv6 example, it's backwards and each digit of the hexademical groups
of 4, are dot-separated. So for example, 2001:
at the start of an IPv6
address (as in the above example) is 1.0.0.2.ip6.arpa
at the end of the
string.
It should be noted: in this guide, for IPv6, we are using the deprecated ip6.arpa format alongside AAAA addresses, as opposed to the newer A6/DNAME entries; in practise, the old way works just fine, and it's simpler. It will never not work. More information about that is available here:
https://docstore.mik.ua/orelly/networking_2ndEd/dns/ch10_16.htm
A6 records could be covered at a later date, but they are (for now) not covered in this guide.
These are unused in our example configuration, but they pertain to RFC 1918
Enable it or don't. It's up to you. Uncomment the line for it
under named.conf.local
.
Let's talk turkey.
First of all, BEFORE configuring domain names, we must take care of the
files db.ipv4ns1
and db.ipv6ns1
. We will cover these first, and then
we will cover the domain name used for running your name servers (again, we
assume that you are running ns1
and ns2
on the same domain name).
The file name has "ns1" in it, but this file shall contain PTR
and NS
records pertaining to both ns1
and ns2
. In the sample files provided, you
shall see:
$TTL 604800
@ IN SOA shlinux.org. leah.libreboot.org. (
20221226 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
; Name servers
IN NS ns1.shlinux.org.
IN NS ns2.shlinux.org.
;ptr records
130 IN PTR ns1.shlinux.org.
131 IN PTR ns2.shlinux.org.
;
Firstly, observe these lines:
IN NS ns1.shlinux.org.
IN NS ns2.shlinux.org.
Change these to whatever your own name server zones are to be. For
example, ns1.boobworld.com
and ns2.boobworld.com
.
Now observe these lines:
130 IN PTR ns1.shlinux.org.
131 IN PTR ns2.shlinux.org.
In our sample configs, we configure ns1.shlinux.org
and ns2.shlinux.org
which, respectively, correspond to 81.187.172.130
and 81.187.172.131
.
These IP addresses are of /28
subnet size (32 take 4 makes 28; 2 to the
power of 4 is 16, then you take the subnet+broadcast address and router
address within the subnet, which would then yield 13 useable IP addresses).
Remember, the IPv4 address 81.187.172.130
corresponds
to 130.172.187.81.in-addr.arpa
; in this case, becasue it's a /28, but
because that is within the 130
octet, you can therefore think
of 130
as kind of like a subdomain of 72.187.81.in-addr.arpa
(this is
not technically correct, but a useful analogy).
So, the 130
"hostname" in the zone should have a PTR record set,
corresponding to ns1.shlinux.org
. The PTR record is sometimes referred to
as "reverse DNS".
Same deal for the 131 entry.
Please also observe:
20221226 ; Serial
The serial line must be changed, whenever you modify a zone file. Use of an ISO date is recommended (YYYYMMDD), but you can put almost anything there.
You must modify this file, according to your IP addresses and zone name.
This file accomplishes the same thing as db.ipv4ns1
but for IPv6.
In our sample files, we see:
$TTL 604800
@ IN SOA shlinux.org. leah.libreboot.org. (
20221226 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
; Name servers
IN NS ns1.shlinux.org.
IN NS ns2.shlinux.org.
;ptr records
2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR ns1.shlinux.org.
3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR ns2.shlinux.org.
Most of these entries are precisely the same. In fact, all of them are, but the rules for IPv6 are different:
Take the line that says 2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0
, for instance:
This line corresponds to 2001:8b0:b95:1bb5::2
. The ::
is shorthand,
but the full address would
be: 2001:08b0:0b95:1bb5:0000:0000:0000:0002
. Remove the : characters and
separate each digit by dots, we would
get: 2.0.0.1.0.8.b.0.0.b.9.5.1.b.b.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2
.
Reverse these digits, and we would
get: 2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.5.b.b.1.5.9.b.0.0.b.8.0.1.0.0.2
This IPv6 address happens to be of prefix size /64
, and IPv6 addresses
are 128 bits in size, so basically we cut off half:
2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0
shall correspond via PTR record,
to ns1.shlinux.org
Same for ns2, using the same method by its IPv6 address
of 2001:8b0:b95:1bb5::3
.
You must modify this file, according to your own IPv6 addresses and zone name.
More information about this is available here:
https://docstore.mik.ua/orelly/networking_2ndEd/dns/ch10_16.htm
This zone file is for shlinux.org
, on which the sample files also
configure ns1.shlinux.org
and ns2.shlinux.org
. You must specify your own
file for the domain name that you use, replacing db.shlinux.org
.
In the sample file (actually used in production on 26 December 2022, for shlinux.org), you shall see:
$TTL 604800
@ IN SOA ns1.shlinux.org. leah.libreboot.org. (
20221230 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
shlinux.org. IN NS ns1.shlinux.org.
shlinux.org. IN NS ns2.shlinux.org.
shlinux.org. IN CAA 0 issue "letsencrypt.org"
shlinux.org. IN CAA 0 iodef "mailto:leah@libreboot.org"
ns1 IN A 81.187.172.130
ns1 IN AAAA 2001:8b0:b95:1bb5::2
ns2 IN A 81.187.172.131
ns2 IN AAAA 2001:8b0:b95:1bb5::3
shlinux.org. IN A 81.187.172.132
shlinux.org. IN AAAA 2001:8b0:b95:1bb5::4
www IN A 81.187.172.132
www IN AAAA 2001:8b0:b95:1bb5::4
aimbot IN A 81.187.172.129
aimbot IN AAAA 2001:8b0:b95:1bb5::1
As always, remember to change the Serial
string when modifying a zone file.
The string leah.libreboot.org
in the SOA section is actually an email
address (leah@libreboot.org
). Please change this to something else,
because I do not want to receive reports about your domain name. Thanks!
In the above example, we see these entries:
shlinux.org. IN NS ns1.shlinux.org.
shlinux.org. IN NS ns2.shlinux.org.
ns1 IN A 81.187.172.130
ns1 IN AAAA 2001:8b0:b95:1bb5::2
ns2 IN A 81.187.172.131
ns2 IN AAAA 2001:8b0:b95:1bb5::3
Notice how shlinux.org.
refers to itself for the two NS
records.
This is a self-referencing domain name, and we configured the IPs in
previous sections of this guide.
Because this is self-referencing, our zone file specifies the regular A and AAAA records pointing to the IPs for these names. In the case of shlinux.org, at least on 25 December 2022, these IPs are used:
ns1.shlinux.org
(IPv4): 81.187.172.130
ns1.shlinux.org
(IPv6): 2001:8b0:b95:1bb5::2
ns2.shlinux.org
(IPv4): 81.187.172.131
ns2.shlinux.org
(IPv6): 2001:8b0:b95:1bb5::3
For the purpose of DNS, the only the ns1
/ns2
A/AAAA and shlinux.org.
NS records matter. It's perfectly acceptable for a zone running name servers
to also specify normal web stuff for example (www
A and AAAA records) as
above, and it could even run email (email-related DNS records are not present,
in the above sample).
To summarise, we have:
So, with this, all the right glue should now be in place, and you can just use your name server!
In my case, I set NS records for domains to ns1.shlinux.org
and ns2.shlinux.org
; I then create the corresponding zone files, and write
whatever records I want in there, for each domain. I host many domains, on
the shlinux name server. Too many. My domain names are like Where's Wally
characters, at this point, but I will never outsource my DNS hosting.
When you're sure that BIND is properly configured, you can start BIND:
systemctl start bind9
You can stop it like so:
systemctl stop bind9
You can restart it like so:
systemctl restart bind9
As can be gleaned from the above sections, edit the
file /etc/bind/named.conf.options
and specify the domain, with a path
to the zone file.
You will then create that zone file.
For more general guidance about non-self-referencing zone files, please refer to zonefile-bind.md
You will also find other example zone files, in the sample configs that you used when following this guide. Feel free to use them as a reference.
Basically, these programs can be used in various ways to test your domains, as configured in the name server:
dig
host
ping
Check the manuals, for these programs. They will be available on whatever Unix system you have such as Linux or BSD.
WE have also configured reverse DNS, but your ISP is the one that assigns IP addresses, whether that be a hardline or a tunnel provider.
You might want to set PTR/rDNS records, just for fun.
Do this:
host 81.187.172.130
host 81.187.172.131
host 2001:8b0:b95:1bb5::2
host 2001:8b0:b95:1bb5::3
You will find that these actually correspond to ns1.shlinux.org
and ns2.shlinux.org
, publicly. My name server runs in front of an
L2TP tunnel router via Andrews & Arnold Ltd (AAISP), using the same setup
as described
in router/debian-l2tp-aaisp.html - and
A&A lets you set rDNS for IPs. I've done so, for all IPs that I use.
rDNS is especially important for email hosting, which you will presumably want to setup, if you're wily enough to follow this DNS guide.
Later on, when you've finished configuring everything, you can check IPv6 status using this excellent checker:
https://www.mythic-beasts.com/ipv6/health-check
Most importantly, the tester linked above checks for connectivity on an IPv6-only setup, so that you know whether IPv6-only internet users can access your services. Keep this link handy! Mythic Beasts is also an excellent VPS hosting provider, that I may well feature in a future guide for how to run your own OpenVPN or WireGuard tunnel server, on which to then run a local tunnel router for home server hosting.
Any issues with BIND will be reported in /var/log/syslog
.
BIND comes with a daemon called RNDC, which can be used to remotely control the name server, using a secret key.
It is to be considered a security liability, for most production use, unless configured correctly and used properly (this last part is where most people screw up). An improperly configured RNDC daemon shall permit any person on the internet to mess with your name server.
It is neither covered nor enabled by anything in this guide, nor by the sample configurations provided.
If you have zone files in place, for a set of domains, edits to those
zone files do not require a restart of bind9. So long as the serial
entry is updated accordingly, you should be file, and you could edit
the zone files in a chrooted SFTP session via OpenSSH.
The RNDC daemon can be useful, and may be covered in a future follow-up tutorial.
You may find the upstream bind documentation useful. BIND is maintained by the Internet Systems Consortium, and you can find the website here:
The upstream Git repository, at least on 25 December 2022, can be found here:
https://gitlab.isc.org/isc-projects/bind9
Documentation available here:
https://gitlab.isc.org/isc-projects/bind9/-/tree/main/doc
There is nothing more to say. Have fun!