By Ben Nitkin on
Years ago, when I first bought nitkin.net, I thought it'd be pretty neat to give my home server a domain, say, home.nitkin.net. At the time, IMeanWebHosting handled DNS through CPanel. CPanel doesn't have an API to update DNS records, so DDNS was a long shot. Instead, I wrote up a little script that'd simply track my home's IP address, and figured I could update the records by hand when things changed. (As it turns out, RCN never changed our IP in the 2 years that home.nitkin.net was up for, so the whole DDNS thing was entirely unnecessary. (That's all back here, along with some introductory material.)
But times change, people move, and shared servers are outgrown. I graduated from school and moved out to Colorado (anyone want to hire an electrical engineer who's pretty good at website stuff and Linux?), and switched hosting providers.
IMeanWebHosting was everything I could hope for in a shared provider, but was lacking some features I wanted - SSL and root access being the big things. In poking around, I found DigitalOcean, a VPS provider. For $5 a month, they give me access to my very own internet-connected computer with, as they say, 1 CPU, 512 MB of RAM, and 20GB of hard drive space. The shared hosting came with a shared CPU, maybe 30MB of ram, and 3GB of space. Upgrade time! Setting up a web server, a mail server, SSH, and migrating everything over took a little while. But I'm wandering again.
The salient point is that DigitalOcean has an OAuth-based API that I can use to play with both the server and the domain name records they host. That means that with a simple API query, I can update the DNS record! (The exclamation point means that I'm excited. Just FYI.)
I came up with this little script. Given an OAuth token (generated from the DigitalOcean API) and a user-defined password, it'll update the DNS records. When called, it checks that the password provided in its URL matches the internally defined one, then goes about checking and updating the DNS record. I have my router, which supports custom DDNS, download this URL weekly:
http://nitkin.net/ddnsupdate.php?pass=xxx&domain=nitkin.net&ip=@IP&record=8651647
That's kind of a mouthful. The first bit, obviously, is just the path to the script. The pass argument is validated against the $PASS variable in the script below; if they don't match, the script exits. The domain and record arguments are used to form the API call. Look over the DigitalOcean API to find the correct record number. Finally, the ip argument specifies the new IP address. (Alternately, the script can autodetect the ip; it's commented out.)
Last, but certainly not least, here's the DDNS script. The DigitalOcean API is a little funny about when to use GET versus PUT versus POST, so one of the URL submissions uses an exec, and the other uses libcurl. Shrug.
<?php /* * DDNS Script * Ben Nitkin (Summer 2015) */ $TOKEN="xxx"; $PASS="yyy"; //Validate password against $PASS if ($_GET["pass"] != $PASS) { print "Incorrect password.\n"; return; } //Extract data from the request $record=$_GET["record"]; $domain=$_GET["domain"]; $ip=$_GET["ip"]; //Uncomment to autodetect remote IP address //$ip= $_SERVER["REMOTE_ADDR"]; //Get current record status, just for verification. $ch = curl_init('https://api.digitalocean.com/v2/domains/'.$domain.'/records/'.$record); //Header stuff to make API work. $HEADERS = array(); $HEADERS[] = 'Content-Type: application/json'; $HEADERS[] = 'Authorization: Bearer '. $TOKEN;curl_setopt($ch, CURLOPT_HTTPHEADER, $HEADERS); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $lines = curl_exec($ch); //Update the thing. PHP doesn't handle PUT requests well, //so we're using shell. $request = "curl -X PUT -H 'Content-Type: application/json' -H 'Authorization: Bearer ".$TOKEN."' -d '{\"data\":\"".$ip."\"}' \"https://api.digitalocean.com/v2/domains/".$domain."/records/".$record."\""; $final = exec($request); if ($final == $lines) print "IP Address appears unchanged."; else print "IP Address updated:\nPrior: $lines\nFinal: $final"; ?>