How to run DynDNS - DDNS yourself

Me being the way I am, that is always looking for a good challenge and also running a web development and hosting company it looked kind of silly to me to depend upon services like for dynamic dns. But ever since I started running my own DNS using PowerDNS it was lingering at the back of my head how little it needs to be done to have my own dyndns.

Finally I got to it this week and when I did it took me a total of 20 minutes to set it all up. So you might call it trivial. My idea was to use SSH key authentication to execute domain update script remotely. The only other thing I needed to solve independently of all of the online services was how to detect my public IP. Finally I resorted to using PHP since my dedicated server runs LAMP anyways.

So, without further poetry, here is the result of my hard labor:

The public IP detection PHP script

$ cat whatismyip.php
<?php echo $_SERVER['REMOTE_ADDR']; ?>

That's a neat script. I don't want to hear anything other than words of praise for this achievement.

Now comes the script that resides on the server where PowerDNS is running and is used to update the ddns database.

The database update BASH script

$ cat 
#!/usr/bin/env bash


mysql -u $MYSQL_USER -p$MYSQL_PASSWORD -h $MYSQL_HOST powerdns -e \
"UPDATE records SET CONTENT=\"$1\", CHANGE_DATE=\"`date +%s`\" WHERE name=\"$2\""

As you can see this one is also a marvelous development achievement. If you don't understand it I suggest you don't mess with any of this stuff.

But now comes the hard part. A script that is running on the client machine. That is the machine for which you want a domain that is dynamically updated.

Client update BASH script

$ cat
#!/usr/bin/env bash

IP=`wget -qO-`
ssh [email protected] "/home/vlatko/bin/ $IP $DOMAIN"

This script is run by the cron process using an entry like this:

$ cat /etc/crontab
# Update dynamic DNS for
* *     * * *   vlatko  /home/vlatko/bin/

You need to pay attention to the fact that this crontab line works due to the fact that I have established an SSH key authentication between my two machines so that the line: ssh [email protected] "/home/vlatko/bin/ $IP $DOMAIN" does not require password input.

So the whole workflow goes like this:

  1. Every minute crontab starts a script on the client machine. That is the machine for which you want a dyndns domain.
  2. The script determines the public IP address of the client machine by calling the whatismyip.php script using wget.
  3. Once the IP is determined the client machine executes a domain update script via SSH line that performs the actual update of the PowerDNS database completing the full workflow.

There is one more thing worth noting. The dynamic domain that you are updating needs to have a very short TTL in order to have it propagate quickly enough through the DNS network. If you don't understand what DNS propagation is you can learn more by reading an excellent article at DevShed: What is DNS propagation and why does it take so long?

I know you guys have a ton of improvements on these lines of mine. I would love to have them in the comments section below. No login, just punch your ideas in and let's see how we can improve upon this peace of software.


Stephen Milton made the same thing for BIND. Check it out here:

Your thoughts

Mark, 17-08-13 17:17
For getting a basic DDNS system running, your scripts look absolutely beautiful - the simplicity and the minimalism there is a great demo of the Unix philosophy!

I have also created a Dynamic DNS system running on top of PowerDNS/MySQL, which uses a web interface rather than SSH (more accessible, and would be more secure if I bothered to test it properly). It allows creation, updating and deletion of dynamic hosts, and may be found on github:

To script an update via the web interface, use "curl" on Linux/Unix, or hand-craft a HTTP GET command and feed it into "telnet" on Windows.
steve, 26-06-11 08:37
If you want to give some other services a try other than dyndns there are tons more to choose from such as those listed at

Add comment

* - required field