Free cross-platform dynamic DNS with wildcards

This will roughly explain how to get wildcard DNS working for free (any-words-here.yoursubdomain.yourdomain.com) on a connection which gets assigned dynamic IPs. I’d like to make sure subdomain.example.com is always up to date with my home IP, and be able to request subdomains (like someword.subdomain.example.com) that resolve to the same IP. These are useful if you want to use multiple virtual hosts in apache hosted from a machine on your home network, accessible to the outside world using a fixed hostname.

Requirements

Your own domain (example.com)
Your have a server on the outside world, running PHP (for this example anyway)
A way of requesting a remote web page automatically

Introduction

Our previous internet provider gave me a static IP (2 actually!) on a standard ADSL broadband connection. I also own a domain (for this, I’ll say example.com) – so I setup a zone specifically for my house (subdomain.example.com) – this was nice and easy using any DNS provider as it never changed. I also created NS records pointing subdomain.example.com at my home IP, so that I could create requests for blah.subdomain.example.com

We’ve recently moved house. We’re now with Virgin, and they don’t provide static IPs – so I thought I could use something like dyndns.com or no-ip.com (which runs a small daemon which updates your IP to point to something like yourname.no-ip.com). However, these don’t support recursive wildcard DNS requests without paying for a subscription (i.e. something.yourname.no-ip.com) so I’d only be able to have a single domain name for my home, which makes using Virtual Hosts in apache not really possible…

Solution!

Find a free DNS host which support an API, and supports wildcard DNS records for a fixed zone. I’ve done the hard work for you, and found Zerigo

Setup a free account on Zerigo and creat a new zone for subdomain.example.com – my primary DNS is hosted elsewhere for example.com, so I just created an NS record for subdomain.example.com on my main DNS to point at a.ns.zerigo.com. You could probably host both on Zerigo if you wanted.

Then, create 2 hosts on this new zone – “” (empty hostname) and “*” (the wildcard host) – give these any old IP; they’ll be updated in a minute!

So, now if you do something like (from your machine):

nslookup banana.subdomain.example.com a.ns.zerigo.com

you should get the IP you’ve given both these hosts. If you do, everything’s working fine.

Now, the best bit about Zerigo is that it has a rather nifty REST api for updating DNS zones and hosts, and they provide a PHP client library along with some fairly simple examples. So I created a small PHP script (using their provided API – thank you!) which just updates your zone to point to the client IP requesting the script, provided it’s not the same as it used to be (with very simple authentication):

The PHP script to do it for you

<?php
$WILDCARD_ZONE="subdomain.example.com"

// rather nasty "authentication" - does the job though... (and it's fine provided the logs on your server are private!)
// just check the MD5 of a GET param is the same as one we're expecting
if (isset($_GET["key"]) && "abc123abc123abc123abc123abc123ab"===md5($_GET["key"])) {
        // get the last IP we updated it to - if it's not the same, write the new one into the file
        // for use next time.
        $oldIP=file_get_contents("oldIP");
        $remoteIP=$_SERVER['REMOTE_ADDR'];
        if ($oldIP != $remoteIP) {
                file_put_contents("oldIP", $remoteIP);
        }
        else {
                // IP hasn't changed, so nothing to do - save superfluous calls to the Zerigo API
                die("No change: $oldIP, $remoteIP");
        }
        // include the zerigo API
        require_once("zerigo-dns_api_php/zerigo_ns.php");

        ZerigoAPI::$api_user = 'you@zerigouser.com';
        ZerigoAPI::$api_key  = 'abc123abc123abc123abc123abc123ab';

        // get all zones on your account (up to 50 of them anyway)
        $zones = NSZone::find_all(array('per_page'=>50, 'page'=>1));

        // Now get the zone we're trying to update
        $homeZone = null;
        foreach ($zones as $zone) {
                if ($zone->domain == $WILDCARD_ZONE) {
                        $homeZone = $zone;
                }
        }
        // found the zone we want?
        if ($homeZone) {
                // update all the hosts that match what we're fudging (i.e. the empty host and the wildcard)
                foreach ($homeZone->hosts as $host) {
                        if ($host->hostname == "" || $host->hostname == "*") {
                                // bit of debug to go in my cron logs
                                echo "Updating " . $host->hostname . "." . $homeZone->domain;
                                echo " from " . $host->data . " to " . $remoteIP . "<br/>\n";
                                $host->data = $remoteIP;
                                // call the Zerigo API to update the remote IP for this host
                                if ($host->save()) {
                                        echo "Updated.<br/>\n<br/>\n";
                                }
                                else echo "Failed.<br/>\n<br/>\n";
                        }
                }
        }

        exit();
}
header("Status: 404 Not Found");

(You’ll also need the Zerigo PHP api stuff too, which can be found here: Zerigo PHP Libs)

Getting it to automatically update

I just set a box on my home network to fetch this every now and again – at the moment, I’ve just got a cron job that does it hourly and it keeps my remote IP up to date  (with a low (1 hour) TTL) on Zerigo’s DNS servers. I presume there’s a way in Windows to create a scheduled job that does it too, so this method is pretty cross-platform (and because PHP can run on pretty much anything, it works on all client/server setups).

Hooray!


Posted

in

, ,

by

Tags:

Comments

2 responses to “Free cross-platform dynamic DNS with wildcards”

  1. Silas S. Brown Avatar

    I can’t see that Zerigo still offer this service free (but I might have missed which part of their site to look at).

    Try afraid.org – seems reliable, lets you add NS records, and has a nice API for updating your IP. If you want to run your own DNS server for the subdomains then you could try getting an NS record from them. But if you have only a few hosts then you might as well just add the hostnames (they let you have a few before you have to start paying).

    Also if any provider lets you set CNAME records then you can use these to point as many domains as you like to resolve to a single dynamic domain somewhere, and only the dynamic domain needs to be updated. It does however make the dynamic domain a point of failure.

  2. Seb Avatar

    I think they are still offering the free one:

    http://www.zerigo.com/managed-dns/pricing

    Having said that, I’ve actually switched to using CloudNS for everything DNS on my domain now, as they support 3 zones with *full* NS control, and have a simple rest api you can call with curl from a cron job…

    http://www.cloudns.net/aff/id/16819/
    (yes, that’s an affiliate link, but if you do signup, would help me enormously 🙂 )

    See

Leave a Reply to Silas S. BrownCancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.