You own a domain name with a root server and want to run your own dynamic DNS service? Then this tiny DNS server might be what you are looking for. It implements just the parts that are required for dynamic DNS and focuses on easy configuration, standards compliance and security.
- DNS over UDP and TCP
- Dynamic update of A and AAAA records over HTTP
- HTTP update interface compatible with Fritz!BOX and others
- Future proof by implementing all recommended standards
- See DNS flag day for more information
- Tested with ISC DNS compliance tests
- Supports EDNS (RFC6891) with DNS cookies (RFC7873)
- Hardened against DNS amplification attacks (rate limiting of UDP requests without DNS cookies) and "low and slow" attacks (drop slow clients, round-robin connection limit)
- Small footprint (<1 MB RAM, <100kB on disk)
- Optional systemd integration
- Socket activation for fast system startup
- Root-less operation because ports are bound by systemd
- Uses
DynamicUser=trueto jail the service even more
- Can drop root privileges when run without systemd
- OpenSSL >= 1.x.x
- Systemd (optional)
mkdir build
cd build
cmake ../src -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release
make
sudo make install
Copy the example configuration file cfg/nanodnsd.conf to /etc and adjust to
your configuration. On termination the current state of the daemon is saved to
/var/lib/nanodnsd/nanodnsd.state.
Just do a HTTP GET or POST request with the following format:
http://<server>/api/update?hostname=<host>&ipv4=1.2.3.4&ipv6=1:2::7:8&ipv6prefix=1:2::/64&token=secret
The hostname and token parameters are mandatory. For IPv4, the ipv4
parameter updates the A record. For IPv6, there are two mutually exclusive
ways how the AAAA record can be specified. If the full IPv6 address of the
host is available, use the ipv6 parameter. More often, though, your router
will receive an IPv6 prefix and could expose more than one host behind it. For
that, the ipv6prefix parameter is used in conjunction with an
ipv6interface= key for each exposed hosts in nanodnsd.conf. If both ipv6
and ipv6prefix parameters are given, the former takes precedence. If no IPv4
and/or IPv6 address is given, the respective record will be removed.
nanodnsd does not support HTTPS. Use a reverse proxy to provide HTTPS instead.
In the example we assume that you own the domain mydomain.test and you would
like to let the dynamic host appear under the dyn.mydomain.test sub-domain,
e.g. home.dyn.mydomain.test. Additionally you have a server that has the IP
address 1.2.3.4 resp. 11:22::33:44.
First of all you need a DNS provider that let's you define NS records in your
domain. Unfortunately this does not seem to be universally the case so make
sure you check your provider or move the domain to one that has support for
NS records. The NS record is required to delegate a subdomain to another
name server.
Give your server a public name so that it can be reached as DNS server. For
clarity we choose ns.mydomain.test. Hence define the following records in
your zone:
Host TTL Class Type Address
---- --- ----- ---- -------
ns 86400 IN A 1.2.3.4
ns 86400 IN AAAA 11:22::33::44
If your server has already a name there is nothing wrong with re-using it. But
having a dedicated name for the name server purpose makes a bit more clear.
Then define the dyn subdomain with a NS record pointing to the host name of
your server. This states that any host under dyn.mydomain.test is managed by
the ns.mydomain.test server.
Host TTL Class Type Address
---- --- ----- ---- -------
dyn 86400 IN NS ns.mydomain.test
You could also announce your DNS server under the dyn subdomain, e.g.
ns.dyn.mydomain.test. This is not recommended because it will create a
circular lookup dependency. It is still possible but requires a static entry in
the DNS server for itself and the definition of glue records to your zone.
On the server you have to install nanodnsd and copy the example configuration
file (cfg/nanodnsd.conf) to /etc. You will then have to
adapt it to your likening. The [server] section is the most important one
and you will have to set the domain, nameserver and email keys to your names.
The sample configuration names match this example.
[server]
domain=dyn.mydomain.test
nameserver=ns.mydomain.test
email=hostmaster@mydomain.test
You must have an email account that is actually capable of receiving mails at
the given address. It is recommended to keep the name hostmaster as most
people will assume that this is the account that manages the zone. Inside the
DNS SOA record some email address characters must be escaped. nanodnsd will
take care of that automatically.
Commented out values in the configuration file are default values.
Host names are statically defined in the configuration file. Sections for a
host start with @ and the rest of the section name is the actual host name.
To update an entry dynamically you must define a token. This is an arbitrary
string and is used as authentication for the HTTP update request.
[@home]
token=somesecterpassphrase
By default the resource records of the host name will expire after one day.
Unless they are refreshed the resource records of the host name will be deleted
after one day. You can adjust the time with an expire entry. The default unit
is seconds but you can also specify minutes (1m), hours (1h) and days
(1d). Note that this is not the TTL of the resource record. The TTL is
currently hard coded to 60s in defs.h.
Entries without a token cannot be updated. Use them to define static entries in
the zone. You can define the A and AAAA records directly in the
configuration file:
[@static]
a=127.0.0.1
aaaa=::1
Go to the DynDNS tab in the Fritz!BOX admin interface and enter the following settings (adapt to your domain names):
- DynDNS Provider: "User-defined"
- Update URL:
http://ns.mydomain.test/dns/api/update?hostname=<domain>&ipv4=<ipaddr>&ipv6=<ip6addr>&token=<pass> - User name:
-(must be entered but is not used bynanodnsd) - Password:
somesecterpassphrase
Leave out the &ipv6=<ip6addr> part if your provider does not assign an IPv6
address yet. This parameter will set the DNS record to the Fritz!BOX itself,
e.g., if you configured a VPN endpoint. In case you want to expose a host
behind the Fritz!BOX, use &ipv6prefix=<ip6lanprefix> and add the interface
address of the exposed host in nanodnsd.conf as ipv6interface=. You can
find the IPv6 interface address in the port sharing setting for the host.
By default, the server will print some statistics every day.
statistics:
requests: ipv4=0 ipv6=0 udp=0 tcp=0 edns=0
responses: total=0 trunc=0 edns0=0
queries: success=0 empty=0 formerr=0 servfail=0 nxdomain=0 notimp=0 refused=0 badvers=0 badcookie=0 dropped=0
cookies: none=0 malformed=0 client_only=0 invalid=0 correct=0
You can adjust the interval in nanodnsd.conf with the stats_interval key.
Setting the interval to 0 disables printing of statistics altogether.