z3bra, the stripes apart

Name that domain

10 July, 2014

Hello folks !

I recently reinstalled my home server, and during the process, I decided to throw away the heavy BIND nameserver from my application stack. I decided to go with the light couple tinydns + dnscache.

This wasn't really "easy" to do so, as there are really few resources on the web explaining the step to get this working (If you're aware of one, please send me a link, I'll be glad to share it). So here is a full tutorial !


  1. create tinydns zone file
  2. make tinydns listen on
  3. create the ip files for dnscache
  4. create the servers file for dnscache containing
  5. Fire it up
  6. Enjoy.

The whole installation

First of all, I had to find out what were my needs. It seems stupid to say so, but I have the bad habit to dive into configuration, barely knowing what I'm trying to do. Here's what I wanted:

The DNS nameserver will be running on a machine with IP My local network will be named domain.lan. I want all my machines to contact to resolve URIs, and the server will provide authoritative answers for domain.lan, and forward everything else to some other servers.

How should we organise things then ?

Here's how I see it:

Let's set this up then!


tinydns is fairly simple to use, and even more simple to configure. But it's nothing you've ever seen before. You can configure tinydns from a single file:

─── cat /etc/tinydns/root/data

That's a basic configuration file to use with tinydns. It will resolve domain.lan and pc1.domain.lan to ip and pc2.domain.lan to

For more infos on the syntax, check the alpine wiki page.

Once your config file is created, you can generate the data that tinydns will use. Remember to correctly set the ROOT variable to define the directory where tinydns will store it's data:

# ROOT=/var/cache/tinydns/ tinydns-data

As we said earlier, we want tinydns to listen on the loopback interface. To do so, we have to export the variable IP before running the binary.

# ROOT=/var/cache/tinydns/ IP= tinydns

And there you go ! Tinydns is listenning on address
To check if it's correctly running, you can use nslookup.

# cp /etc/resolv.conf.old /etc/resolv.conf.orig
# cat <<EOF > /etc/resolv.conf
# nslookup pc2.domain.lan
Server:    (null)
Address 1: ::1 localhost
Address 2: dns.domain.lan

Name:      pc2.domain.lan
Address 1: 10.0.0.g.2
# mv /etc/resolv.conf.orig /etc/resolv.conf

It works ! Don't use tinydns as a resolv.conf entry though. Because it's authoritative and ONLY serves our domain.lan zone, it would not be efficient...


No DNS server can answer all the queries, so in most case, if the DNS can't provide an answer, it will just forward the query to another depending on some internal rules.

That's how we're gonna set up dnscache. Intercept queries from the local network, forward every query for domain.lan to tinydns, and everything to a standard list of known root servers.

But first, we need to tell dnscache to answer every query from local domain. Let's say my current configuration is the following:

Network :
Netmask :
Gateway :
DNS     :

We need to listen on for DNS queries. To set this up, take a look at the /etc/dnscache/ip/ directory:

─── ls /etc/dnscache/ip
─── wc 127
0         0         0 /etc/dnscache/ip/127

A single file named 127, which is totally empty... What does that mean ? Upon startup, dnscache will read this directory and check the filenames to know which IP address it should accept queries from.

The filename also act as a netmask, so in this case, 127 really means

Back to our configuration. We want dnscache to accept queries from our local network: Just create the corresponding file:

# :> /etc/dnscache/ip/10.0

And we're done !

Now, we need to tell dnscache who will answer the queries it receives. This is done in the /etc/dnscache/servers/ directory. We can see that there is already a file here:

─── ls /etc/dnscache/servers/
─── cat /etc/dnscache/servers/@

This is a list of the root servers extracted from this list.

In this directory, each file represent a domain, and the content of this file is the list of the servers to contact in order to resolve those names.
"@" is a special name for the "fallback" entry.

In our case, we want tinydns to resolve names from "domain.lan", and forward everything else to the root servers in the "@" file. To query tinydns, we need to forward queries to Here's how to do this:

# cat <<EOF > /etc/dnscache/servers/domain.lan

That's all. Pretty simple isn't it ?

It's now time to start dnscache. It needs (like tinydns) two environment variables: ROOT for the configuration directory path, and IP for the address of the interface to listen on (note that you can use to listen on all interfaces).

# ROOT=/etc/dnscache IP= dnscache

You can now check if everything is working fine with nslookup:

# cp /etc/resolv.conf.old /etc/resolv.conf.orig
# cat <<EOF > /etc/resolv.conf
# nslookup pc2.domain.lan
Server:    (null)
Address 1: ::1 localhost
Address 2: dns.domain.lan

Name:      pc2.domain.lan
Address 1: 10.0.0.g.2
# mv /etc/resolv.conf.orig /etc/resolv.conf

And there you are ! You can now specify the IP address of your server in the resolv.conf on your local computers.