Thursday, March 12, 2009

How to build a dynamic DNS server with Slicehost

Or, How to give your local machine a permanent home on the interweb.

For years I had a method of accessing Linux boxes or Windows machines that lacked permanent IPs.   I would:  (1)  find my IP at some 'whats-my-ip.com' site, (2)  e-mail it to myself, and (3) pray that it wouldn't change while I was away.

Unfortunately, particularly for DSL connections, this faith-based method frequently failed.

In an ideal world, we wouldn't need local storage or local CPU power.  But the cold, hard truth of network latency -- which ever larger data sets don't help -- means that most of us need local machines.  And life is a lot easier when these local machines have -- or least appear to have -- permanent addresses on the interweb, like "bigdata.dataspora.com" -- even if their actual IPs are changing. 

What follows is a the solution that I've implemented for my setup.  Basically it's a cron script that runs on our office server ('bigdata') and checks its WAN IP address hourly.  If this IP address has changed, it updates the DNS record for 'bigdata.dataspora.com'  on our top-level server (hosted at Slicehost).  The script lives in the /etc/cron.hourly directory of my local server.

Slicehost has a nice API that makes this process relatively painless, and this script was modified from their documentation (link can be found in the comments).  Three important prerequisites for this code to work:  

  • you need to Enable API access via  https://manage.slicehost.com/api/   
  • you must have a 'bigdata.dataspora.com' (insert your domain) Type A record at slicehost pointing to some IP address, and... 
  • you must have Jared Kuolt's pyactiveresource Python library installed.

So, without further ado, here's the little script that makes your local machine a self-updating DNS dynamo!



#!/usr/bin/python
## dynamic-dns.py
## author: Michael Driscoll

## 12 mar 2009
##
## A script that dynamically updates DNS records on Slicehost
##
## For more detailed information, see Slicehost's excellent API docs
## http://articles.slicehost.com/2008/5/13/slicemanager-api-documentation
##
## This code requires Jared Kuolt's pyactiveresource library, via
## http://code.google.com/p/pyactiveresource/
##


from pyactiveresource.activeresource import ActiveResource
import urllib
import os

## Let's define some constants for securely connecting to the Slicehost API
## API access key and resulting URL string
api_password = 'your-API-key-goes-here'
api_site = 'https://%s@api.slicehost.com/' % api_password

## the type and name of the single record I'm updating
record_type = 'A'
record_name = 'bigdata'

## The URL for any server that can return your IP in plaintext
## I hand-rolled mine with a one line file called 'myip.php':
##

ip_site = 'http://labs.dataspora.com/tools/myip.php'

## where to store the last ip detected
ip_path = '/etc/lastip'

## if last ip exists, read it in
if (os.path.exists(ip_path)):
   f = open(ip_path, 'r')
   lastip = f.read()
   f.close()
else:
   lastip = ''

## Let's get our current ip
ip = urllib.urlopen('http://labs.dataspora.com/tools/myip.php').read()

## If they differ, update our last ip file and Slicehost
if (ip != lastip):
## update our file
   f = open(ip_path, 'w')
   f.write(ip)
   f.close()

## update Slicehost
class Record(ActiveResource):
   _site = api_site

results = Record.find(record_type="A", name=record_name)
record = results[0]
record.data = ip
record.save()

2 comments:

Anonymous said...

Dustin Brewer has written a similar script, available at:

http://code.google.com/p/slicehostdynamicdns

The only noticeable difference is that yours doesn't ping Slicehost unless the IP is changed.

Anonymous said...

Michael's was easier to read I thought.