I use DNS overrides with WebFaction to point several subdomains to my home servers. My internet service provider, however, provides my router a dynamic IP address that changes every time my DSL modem is disconnected and then reconnected to their system. Each time this happens, it disrupts service to the home servers because WebFaction is still pointing to the old IP address. I decided to do some searching on the WebFaction forums to see if there was an easy solution to this issue. I was happy to see that I was not the first one with this issue, and WebFaction's solution was to write an XMLRPC API function allow users to create and delete DNS overrides with their own code.
Reading through this post reminds me of why I love WebFaction so much. Their customer posed the question to them on December 29th, and despite the New Years holiday their staff member Remi had a brand new API method written just for them by January 2nd. Thanks WebFaction!
So, to take advantage of this, I wrote a Python script which I call hourly through cron on my Ubuntu testing server. I wanted to share the script so that others who use Webfaction can take advantage of this feature, also. To start out, I created a config file in my home directory to store the IP address, so that my script will only hit WebFaction if the address has changed. I store the config information at
~/.adoleo/global.config, and it contains the following:
[network] pub_ip = 18.104.22.168
ConfigParser from the standard Python library, I can easily read this file in my script to determine if the public IP has changed. In order to determine my public IP, I used another part of Python's standard library,
urllib2, to reach out to www.whatismyip.com.
pub_ip = urllib2.urlopen("http://whatismyip.com/automation/n09230945.asp") pub_ip = pub_ip.read()
Here is the script I came up with in it's entirety. I am releasing this code under the BSD License, details of which can be found here.
#!/usr/bin/env python import sys import os import xmlrpclib import urllib2 import ConfigParser from datetime import datetime def main(argv): dns_overrides = ( 'override.example.com', 'another_override.example.com', ) pub_ip = urllib2.urlopen("http://whatismyip.com/automation/n09230945.asp") pub_ip = pub_ip.read() config_loc = os.path.expanduser('~') + '/.adoleo/global.config' now = datetime.now() now = now.strftime('%m/%d/%Y - %I:%M %p') if os.path.exists(config_loc): config = ConfigParser.SafeConfigParser() config.read(config_loc) prev_ip = config.get('network', 'pub_ip') if pub_ip == prev_ip: print now + ": IP has not changed." sys.exit() else: print now + ": IP has changed - updating IP." config.set('network', 'pub_ip', pub_ip) configfile = open(config_loc, 'wb') config.write(configfile) else: print now + ": Creating new config file and updating IP." config = ConfigParser.SafeConfigParser() config.add_section('network') config.set('network', 'pub_ip', pub_ip) configfile = open(config_loc, 'wb') config.write(configfile) server = xmlrpclib.ServerProxy('https://api.webfaction.com/') session_id, account = server.login('webfaction_username', 'password') for override in dns_overrides: server.delete_dns_override(session_id, override) server.create_dns_override(session_id, override, pub_ip) print 'tOverride for %s updated.' % override if __name__ == '__main__': main(sys.argv[1:])
Once you've modified that code to meet your needs, you can set it up in
crontab -e on your Unix-like box to run with whatever frequency you want. I've got mine running hourly, with the output redirected to a log file.
@hourly python /path/to/update-ip.py >> /path/to/logs/update-ip.log
And that's it! You now have an automated DNS override updater. The WebFaction-specific code is only a very small part of this, so you could conceivably alter it to work with other hosting services if you're not using WebFaction. Enjoy!