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.
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.yml and setting the proper values for your setup. The
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
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
This assumes that you use the default database (just renamed
db.yml). If you already changed your DB you have to change the domain name in the command accordingly.
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
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
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 addr show dev eth0 scope global | \
grep --perl-regexp --only-matching '(?<=inet6 )2003:[0-9a-f:]+' | \
head --lines 1 \
curl -s http://foo:email@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:firstname.lastname@example.org: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".
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. :)