During the last few weeks I wrote MiniDynDNS to build my own dynamic DNS service. Something like DynDNS but all by myself. This post explains the basic steps needed to wire MiniDynDNS into the worldwide DNS system.
I'm using it to create DNS names that point to devices at home I want to access via the internet. This is pretty nice with IPv6 since every device gets its own public IPv6 address. But please make sure only the services you want to have available are actually listening on the public IPv6 address. Or configure your firewalls accordingly.
To build your own DynDNS you'll need a few bits and pieces:
- A server with a static IP address. Here we'll use
203.0.113.17
as a placeholder for that IP.
- A registered domain of your own.
example.com
shall proudly serve as a placeholder for that domain.
- Access to the nameserver or DNS records of that domain. We'll need to add some DNS records there.
The bigger picture
The whole idea of this operation is to create a subdomain that is managed by a program running on your server. Here we'll use dyn.example.com
but it can be anything as long as it's a subdomain of your registered domain. Whenever someone on the world resolves a name like weather.dyn.example.com
they're going to ask that program on your server to get the current IP of that name.
For that we first need a program running on your server that can answer DNS requests and allows us to update these IPs
when they change. Obviously we're going to use MiniDynDNS for that. That's why I wrote it.
Second we need to tell the global DNS system that the program running on your server is responsible ("authoritative") for dyn.example.com
subdomain. This is called "delegating" a subdomain. When you bought your own domain you also bought the right to delegate subdomains to whoever you deem worthy. With that in place whenever someone resolves a name in dyn.example.com
they'll ask MiniDynDNS on your server.
Note that you can only delegate a subdomain to a host, e.g. ns.example.com
. This host then has to resolve to 203.0.113.17
. You can delegate to whatever host you want but in the end this host has to resolve to your public IP. Here we'll use ns.example.com
as a placeholder for that.
The final part is a script running on whatever device or computer you want to have a dynamic domain name for. That script will periodically report its current IP to your MiniDynDNS.
If everything works correctly you can add any devices you want to your dyn.example.com
subdomain and access them from everywhere on the world. pi.dyn.example.com
, weather-station.dyn.example.com
, tv.dyn.example.com
, touchtable.dyn.example.com
, spidercam.dyn.example.com
or whatever. Get creative.
So lets get to it.
1. Run MiniDynDNS on your server
Download or clone MiniDynDNS from GitHub and do the "installation". Basically that's renaming config.example.yml
to config.yml
and setting the proper values for your setup. The domain
, soa
→ nameserver
and soa
→ mail
are the important ones.
For MiniDynDNS to answer incoming DNS requests it has to listen on port 53. That's where other servers or clients expect to get DNS requests answered. Changing that will probably break things.
Per default it will use port 80 for a simple HTTP API with which we can update DNS records. In case this port is already used by a webserver like Apache you can change it to something else like 8080. We only need it for the scripts that periodically report the IPs of your devices to the server.
You can tell your server system to start MiniDynDNS on server startup. For me it's just a funny hobby so I leave it running in a screen
terminal. You might also need to tell your servers firewall to open port 53 and 80 for incoming traffic (or whatever port you use for the HTTP interface). Otherwise the firewall will block everything and you'll just get timeouts.
Now your basic DynDNS server should already be up and running. To test it you can fire up a terminal and try this command:
nslookup foo.dyn.example.com 203.0.113.17
This tells nslookup
to resolve foo.dyn.example.com
by asking the DNS server 203.0.113.17
. If everything works well it should tell you that foo.dyn.example.com
has the IP address 192.168.0.1
.
This assumes that you use the default database (just renamed db.example.yml
to db.yml
). If you already changed your DB you have to change the domain name in the command accordingly.
2. Delegate dyn.example.com
to the MiniDynDNS server
Now on to tell the rest of the world that your server manages the dyn.example.com
by itself. For this you have to add two records to your normal nameserver. In my case the company where I registered my domain provides a webinterface for this task.
You have to add these two DNS records to your example.com
nameserver:
dyn NS ns.example.com
ns A 203.0.113.17
The first record tells the DNS system that the dyn.example.com
subdomain is delegated to ns.example.com
. The second record says that ns.example.com
has the IPv4 address 203.0.113.17
. Please remember to replace the domain name and the IP with your own values. If your server also has an IPv6 address you should add an AAAA record for that, too.
3. Update your IPs periodically
This differs greatly between IPv4 and IPv6.
With IPv4 only your router has a public IP address. For every service you have to create a port forwarding to the appropriate internal computer or device. So in any way there's only one public IP to report to the DNS server. Many routers already have build-in support for this. Usually it's hidden somewhere in the webinterface called "dynamic DNS", "DynDNS" or something like that.
In the case of my FritzBox router I have to enter the domain (foo.dyn.example.com
), a user name (just foo
), the password (bar
) and an update URL (http://ns.example.com/?myip=<ipaddr>
). The router will replace "<ipaddr>" with its current public IPv4 address. It seems like it then just fires this HTTP request every 30 minutes. Again these values are based on the default db.yml
file.
The required steps are probably quite different for other routers. You might even have to look into the manual or search a bit to figure out how to do this.
With IPv6 the situation is a bit simpler. Each device gets its own public IPv6 address. A script that runs every few minutes can simply report that IP to the DNS server. In case of a RaspberryPi running Raspbian this script will do the job:
IP=$( \
ip addr show dev eth0 scope global | \
grep --perl-regexp --only-matching '(?<=inet6 )2003:[0-9a-f:]+' | \
head --lines 1 \
)
curl -s http://foo:bar@ns.example.com/?myip=$IP
Again, "foo", "bar" and "ns.example.com" are values from the default db.yml
. Replace them with the values for your setup. In case you changed the port of the webinterface you also have to add a port to the HTTP request (something like http://foo:bar@ns.example.com:8080/?myip=$IP
for port 8080).
Save it to /home/pi/update_ip.sh
and make it executable with chmod u+x update_ip.sh
. When you run it (./update-ip.sh
) you should see something like "Your IP has been updated".
To execute the script every 5 minutes you just need to add a line to your crontab. The command crontab -e
should show you an text editor and by adding this line at the end you should be set:
*/5 * * * * /home/pi/update_ip.sh 2>&1 >> /home/pi/update_ip.log
The "*/5" at the beginning means "every 5 minutes". If you want to run the script every 30 minutes its "*/30".
Done!
Phew, this was more text than I expected. When you run the command nslookup foo.dyn.example.com
you should now see 192.168.0.1
as a result (again, default database values). Note that this command asks the nameserver provided by your environment (e.g. by your ISP). Thanks to the domain delegation this DNS request should end up at your nameserver which can then answer it. When you have a webserver running on one of your devices you can even use these domain names to access websites.
Anyway, with that setup you should be able to manage your own subdomains. The MiniDynDNS readme has some more information and useful commands so better take a look there, too.
Have fun with MiniDynDNS. :)