Authoritative-only name server on Debian

English | українська

Return to index


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. and - 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!


IP addresses

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.

Domain name

You need a domain name, such as, 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 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:

Not all TLD zone operators support IPv6 glue, regardles of chosen registrar. The 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.

Glue records

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 as an example, because I own that domain and I run these on it: and - 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 and, 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):

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 to and, 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.

Software installation

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

Bind9 configs

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.


Install the sample configs

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.

/etc/bind/bind.keys (do not 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 (,… all the way up to 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.

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.

/etc/bind/db.root (do not modify)

This file defines what the root name servers are. On the internet, there are 13 of them, starting from, to… all the way to

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 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.

/etc/bind/db.127 (do not modify)

Zone file for IP address (zone), resolving to localhost.

/etc/bind/db.empty (do not modify)

Zone file for empty RFC 1918 zone.

/etc/bind/name.conf.default-zones (do not modify)

localhost forward and reverse zones. (RFC 1912 compliance)

/etc/bind/named.conf.options (do not modify)

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.

/etc/bind/db.0 (do not modify)

Reverse rules for broadcast zone (zero addresses). Leave this as-is.

/etc/bind/db.255 (do not modify)


/etc/bind/db.local (do not modify)

Forward rules for local loopback addresses e.g. 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. For each specified zone, the path to a zone file is defined.

Please pay close attention.

File contents, in our reference configs:

zone "" {
	type master;
	file "/etc/bind/zones/";
zone "" {
	type master;
	file "/etc/bind/zones/";
zone "" {
	type master;
	file "/etc/bind/zones/";
zone "" {
	type master;
	file "/etc/bind/zones/db.ipv4ns1";
zone "" {
	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 name server. On that day, it had these IP addresses:

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 address, much like the above. For the entry pertaining to db.ipv4ns1, set the zone name accordingly. For example, the IP address would become

The IPv6 address 2001:8b0:b95:1bb4:4 entry, for the part pertaining to db.ipv6ns1, would be:

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 "" {
	type master;
	file "/etc/bind/zones/db.ipv4ns1";
zone "" {
	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 at the end of the string.

It should be noted: in this guide, for IPv6, we are using the deprecated 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:

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.

Zone file configuration

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 (
			 20221226	; Serial
			 604800		; Refresh
			  86400		; Retry
			2419200		; Expire
			 604800 )	; Negative Cache TTL

; Name servers
        IN      NS
        IN      NS

;ptr records
130     IN      PTR
131    IN      PTR

Firstly, observe these lines:

        IN      NS
        IN      NS

Change these to whatever your own name server zones are to be. For example, and

Now observe these lines:

130     IN      PTR
131    IN      PTR

In our sample configs, we configure and which, respectively, correspond to and 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 corresponds to; 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 (this is not technically correct, but a useful analogy).

So, the 130 “hostname” in the zone should have a PTR record set, corresponding to 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 (
			 20221226	; Serial
			 604800		; Refresh
			  86400		; Retry
			2419200		; Expire
			 604800 )	; Negative Cache TTL

; Name servers
       IN      NS
        IN      NS

;ptr records     IN      PTR     IN      PTR

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, 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:

Reverse these digits, and we would get:

This IPv6 address happens to be of prefix size /64, and IPv6 addresses are 128 bits in size, so basically we cut off half:

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:


This zone file is for, on which the sample files also configure and You must specify your own file for the domain name that you use, replacing

In the sample file (actually used in production on 26 December 2022, for, you shall see:

$TTL	604800
@	IN	SOA (
		       20221230		; Serial
			 604800		; Refresh
			  86400		; Retry
			2419200		; Expire
			 604800 )	; Negative Cache TTL
;	IN	NS  IN      NS	IN	CAA	0 issue ""	IN	CAA	0 iodef ""
ns1		IN	A
ns1		IN	AAAA	2001:8b0:b95:1bb5::2
ns2		IN	A
ns2		IN	AAAA	2001:8b0:b95:1bb5::3	IN	A  IN      AAAA    2001:8b0:b95:1bb5::4
www		IN	A
www		IN	AAAA	2001:8b0:b95:1bb5::4
aimbot		IN	A
aimbot		IN	AAAA 2001:8b0:b95:1bb5::1

As always, remember to change the Serial string when modifying a zone file.

The string in the SOA section is actually an email address ( 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:	IN	NS  IN      NS
ns1		IN	A
ns1		IN	AAAA	2001:8b0:b95:1bb5::2
ns2		IN	A
ns2		IN	AAAA	2001:8b0:b95:1bb5::3

Notice how 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, at least on 25 December 2022, these IPs are used:

For the purpose of DNS, the only the ns1/ns2 A/AAAA and 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 and; 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.

Wrapping up

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

Adding domain names

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.html

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:

Check the manuals, for these programs. They will be available on whatever Unix system you have such as Linux or BSD.

Reverse DNS, ISP side

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 2001:8b0:b95:1bb5::2
host 2001:8b0:b95:1bb5::3

You will find that these actually correspond to and, 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.

Test IPv6

Later on, when you’ve finished configuring everything, you can check IPv6 status using this excellent checker:

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.

Dubious mention: RNDC

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:

Documentation available here:

There is nothing more to say. Have fun!

Markdown file for this page:

Site map

This HTML page was generated by the untitled static site generator.