Namecheap, Dynamic IPs, ddclient, and Hosting Multiple Sites on a Single Server
How to run a single Ubuntu server with a dynamic IP address that hosts several different sites: this post will show you how using the Namecheap domain name registrar.
Introduction
Last week, I went looking for a solution to the following problem: I have a single Linux server with a dynamically assigned IP address and I want to host several sites on this server. My registrar is Namecheap.com, and their advice is to use a Linux tool called ddclient.
Unfortunately, namecheap.com’s example doesn’t cover multiple hosts. A Google search pointed me to thornelabs.net, where the author describes a patch that can be applied to ddclient. Ddclient is written in Perl, so patching is a possibility, but one that feels a bit unsatisfactory.
Digging into the Perl script, I discovered that it provides a post-execution hook. This suggests a non-patch strategy: simply chain subsequent ddclient calls.
Here’s my base ddclient.conf file:
# Configuration file for ddclient generated by debconf
#
# /etc/ddclient.conf
use=web, web=dynamicdns.park-your-domain.com/getip
protocol=namecheap
login=inferentialist.com
postscript=/usr/sbin/ddpost
password=CD012345678901234567890123456789
@
/usr/sbin/ddpost is the following python script:
#!/usr/bin/python
import argparse
import tempfile
import os
import subprocess
import syslog
import sys
parser = argparse.ArgumentParser(description='run ddclient on secondary hosts')
parser.add_argument('ip_addr', help='script should be passed current ip address')
args = parser.parse_args()
ip_addr = args.ip_addr
host_passwords = {
'inferentialist.com': 'AA012345678901234567890123456789',
'statscache.org' : 'BB012345678901234567890123456789',
'twittalytics.com': 'CC012345678901234567890123456789',
'dlennon.org': 'DD012345678901234567890123456789'
}
host_subdomains = {
'inferentialist.com': ['blog', 'api'],
'statscache.org' : ['@'],
'twittalytics.com': ['@'],
'dlennon.org': ['@']
}
config_template = """
use=ip
ip={ip_addr}
protocol=namecheap
login={host}
password={password}
{subdomain}
"""
ddconfig_template = """ddclient -file /tmp/{host}.conf -cache /tmp/{host}.cache -quiet"""
for host in host_passwords.keys():
password = host_passwords[host]
for subdomain in host_subdomains[host]:
config_name = "/tmp/{0}.conf".format(host)
cache_name = "/tmp/{0}.cache".format(host)
config = config_template.format(**locals())
with open(config_name, "w") as f:
f.write(config)
ddconfig_cmd = ddconfig_template.format(**locals())
sys_msg = None
try:
subprocess.check_call(ddconfig_cmd.split(' '))
sys_msg = "SUCCESS: [ddclient postscript] updating {subdomain}.{host}: good: IP address set to {ip_addr}".format(**locals())
except subprocess.CalledProcessError:
sys_msg = "FAILED: [ddclient postscript] updating {subdomain}.{host}".format(**locals())
syslog.syslog(sys_msg)
for fname in [config_name, cache_name]:
try:
os.unlink(fname)
except OSError:
pass
This will dynamically update three sites, inferentialist.com, blog.inferentialist.com, and dlennon.org. Note that each site specified in this pipeline should have a corresponding “A” record on namecheap.com. Moreover, subdomains should use the same password as “@” (e.g. root) domains.
The python script also adds entries to the /var/log/syslog.