Self-Hosted Dynamic DNS with BIND9 & PHP

Posted on .

There are several free Dynamic DNS services available, but the ones I have used require the user to respond to an email every 30-days to confirm the account is still in use. DynDns no longer offer free accounts, and some recent news that no-ip.com domains have been ceased by US courts and handed over to Microsoft means I felt relieved I was now running my own system for some time now. And so could you.

This system uses BIND9 to host the DNS and PHP to handle the update requests. Setting up BIND and Apache/Nginx/PHP is outside the scope of this guide.

A user updates their IP by visiting a unique link. In the guide you will find methods of automating dns updates with Linux, OSX and Windows.

I suggest hosting the script on HTTPS or a non-standard port as some Internet Providers (I know Virgin does) use transparent cache proxies for web traffic meaning the web server doesn’t see the correct IP.

In my examples I am creating a domain named dyndns.example.com and have a webserver at web1.example.com, and a nameserver at ns1.example.com. Guide is based on Debian Wheezy, but should be distribution independent.

Creating DNSSEC keys
First you will need to create a set of DNSSEC keys for the 2 systems to authenticate with.

Note: Using “-r /dev/urandom” tells the command to use the less secure non-blocking random generator. Without it, you may find the command blocks until enough random entropy has been gathered to generate the keys.

You will then have 2 new files, in my case Kweb1.example.com.+165+60641.key and Kweb1.example.com.+165+60641.private

In the .private file there is a field “key”:

Kweb1.example.com.+165+60641.private

Adding BIND config
You then need to add this key to BIND and create the zone config. I personally create a new file /etc/bind/named.conf.dyndns and add an extra include directive in /etc/bind/named.conf

Add to /etc/bind/named.conf

Create /etc/bind/named.conf.dyndns

Note: I point zonefiles to /etc/bind/db/, either edit the location or create the directory (remember to give bind write permissions to this directory)
Example zone file
You will need to start your zonefile with the basics.

Create /etc/bind/db/dyndns.example.com

Setting up the web server
This code relies on the program nsupdate. On Debian this is available in the dnsutils package. On Redhat based systems it is in the bind-utils package.

The PHP code has settings and user authentication in the first 2 arrays, $settings and $acl.

The array $acl is made up of 2 fields. These are used as the ID and KEY for authentication. The ID is the subdomain to be updated (ie. customer1.dyndns.example.com).

In order to authenticate and update the IP, a user only needs to visit the page with the correct details. (ie. https://web1.example.com/update.php?id=customer1&key=YRnog2nMaXyzumya2VQX)

The script needs access to the key files generated earlier. I placed them in a new directory include/.

The ttl setting determines how long the internet should cache each DNS entry. A lower TTL would make changes propagate quicker, but would increase the number of requests for busy entries.

The script will attempt to create a log/ directory. If your webserver doesn’t have permission to do this, you would need to do it manually and give the webserver write permission.

You should deny public access to the include and log directories. If using Apache, you can add a .htaccess file to each directory to deny access.
.htaccess

The script logs failed requests and successful updates to log/access_YEARMONTH.log

Automatic Updates on Linux/OSX
Because this system just visits a URL to update the IP, there is no need for special software. All you need to do is visit the link.

You can make this automatic by adding an entry to your systems crontab that will visit the link for you on a regular basis.
crontab

Note: It is important to include the link in quotes as the & symbol has a special meaning on some shells.

Automatic Updates on Windows
For Windows I have written a small VBScript program that can be ran by a scheduled task. The script has been tested on XP/Vista/7/8.

  dynamic-dns.vbs (478 bytes, 3,190 hits)

The PHP code

  update.php (3.8 KiB, 8,576 hits)

Leave a Reply

You may leave the Name and Email fields blank to post anonymously.