Setup Dynamic DNS using Linode ¶
Being a fan and veteran of both DNS services dyndns.org and no-ip.org I was always very slightly annoyed that I could not do this with my personal domain name. The annoyance went up a little more when DynDNS started forcing me to log in every 3 months just to let them know I am still alive.
Since moving to Linode this weekend, I setup my own short DNS updating script. Update the variables APIKEY, DOMAIN, and RECORD to your desired settings and let her rip. Here are my settings for reference. This way when I hit home.pushingkarma.com, it routes to my home network.
Install the Linode Python Bindings¶
Unfortunatly the Linode team didn't include a setup.py with the their release of the Python API Bindings, so we'll need to manually install them. You can go download the Linode Python Bindings from GitHub. The easiest way to to just clone their repo using the command git clone https://github.com/tjfontaine/linode-python.git.
Once you have a copy of them on your system, you can symlink or copy them to some location on your Python path. I put mine in the directory [PYTHON]/site-packages/linode/.... If you are unsure where your Python path is, you can spin up Terminal and run the following commands. You'll most commonly want to find the one ending with the string site-packages.
$ python
> import sys
> sys.path
The Update Script¶
#!/usr/bin/python
"""
linode-dns.py
Author: Michael Shepanski
Date: Jan 17, 2010
A script to update a DNS record on Linode to your external IP.
References:
http://atxconsulting.com/content/linode-api-bindings
https://github.com/tjfontaine/linode-python/
"""
import pycurl
import re
from linode import api
from StringIO import StringIO
APIKEY = '[SECRET_API_KEY]'
DOMAIN = 'pushingkarma.com'
RECORD = 'home'
CHECKIP = "http://checkip.dyndns.org:8245/"
def get_extenral_ip():
""" Return the current external IP. """
print "Fetching external IP from: %s" % CHECKIP
html = StringIO()
curl = pycurl.Curl()
curl.setopt(curl.URL, CHECKIP)
curl.setopt(curl.WRITEFUNCTION, html.write)
curl.perform()
curl.close()
external_ip = re.findall('[0-9.]+', html.getvalue())[0]
return external_ip
def set_dns_target(utarget, udomain=DOMAIN, urecord=RECORD):
""" Update the domain's DNS record with the specified target. """
linode = api.Api(APIKEY)
for domain in linode.domain_list():
if domain['DOMAIN'] == udomain:
# Check the DNS Entry already exists
for record in linode.domain_resource_list(domainid=domain['DOMAINID']):
if record['NAME'] == urecord:
if record['TARGET'] == utarget:
# DNS Entry Already at the correct value
print "Entry '%s:%s' already set to '%s'." % (udomain, urecord, utarget)
return record['RESOURCEID']
else:
# DNS Entry found; Update it
print "Updating entry '%s:%s' target to '%s'." % (udomain, urecord, utarget)
return linode.domain_resource_update(domainid=domain['DOMAINID'],
resourceid=record['RESOURCEID'], target=utarget)
# DNS Entry not found; Create it
print "Creating entry '%s:%s' target as '%s'." % (udomain, urecord, utarget)
return linode.domain_resource_create(domainid=domain['DOMAINID'],
name=urecord, type='A', target=utarget, ttl_sec=3600)
print "Error: Domain %s not found." % udomain
if __name__ == '__main__':
set_dns_target(get_extenral_ip(), DOMAIN, RECORD)
print "Done."
Setup a Cronjob¶
Add this line to your crontab using crontab -e to run the script once an hour.
0 * * * * python /path/to/script/linode-dns.py
Thats It! -- You should be good to go.