Dynamic DNS with Rackspace Apps Control Panel

I use Rackspace Apps for email across all of my domains, and I am using them as a domain registrar, too. A few days ago, I wanted to create a subdomain, like example.vaderpi.com, that pointed to my computer at home. I didn’t want to use one of the free dynamic dns services, and I wanted to be able to create the subdomain for a domain that I already own.

Through the Rackspace Apps control panel, I can change all of the DNS entries for any of the domains that they are hosting. To create a subdomain, all I have to do is create an A record entry for “example” that points to my home ip address. I used whatismyip.org to look that up. Clicked “save”, and then the address started resolving right away. Perfect. Well, at least until my ISP hands out a different ip address.

What I needed was a programmatic way to detect that my ip address has changed and then update the A record entry for example.vaderpi.com with the new ip address.

I dug through the Rackspace Apps API documentation looking for a published way to do this, but I was unable to find one. Then I realized that I could just treat the control panel website as an API by driving it with a headless browser, like HtmlUnit.

There are several ruby gems that provide the ability to drive headless browsers. I took a quick look at celerity, mechanize, steam, and webdriver. I settled in on using steam, because it seemed like it had the fewest number of layers between it and the headless browser. I had also never used it before, and wanted to get a feel for how well it worked.

I have posted the resulting script as a github gist. Take a peek. Comments and forks are welcome. Note that all domain names, user names, and passwords have been replaced with made up examples.

As for running the script, I set up an @hourly entry in cron. The script only contacts the Rackspace Apps control panel if it detects an ip address change, so the risk of accidentally hammering their web server with this, should be low. (I point that out in case any of my old coworkers stumbles across this. :))

The current implementation can only update an existing DNS entry, but it should not be too hard to extend it to support creating additional DNS entries. Anyone that goes to implement this should make sure to correctly handle clicking the add link if there are not any empty rows in the entry table.

In addition to supporting creating new entries, there are a few improvements that I would like to make to this script. (1) I’d like to have an external service resolve the domain. This is going to become critical, because I want my the domain to resolve to the private ip address for devices that are on the private network. (2) I’d like to not rely on whatismyip.org.

I’m thinking of writing a small web service that I can install on my server that will address both of these. The service will be able to do DNS resolution, and it will be able to detect the public ip address of the caller.


Leave a Reply