I recently moved my web server from an internet connection with a static IP address to an internet connection with a dynamic IP address, which presents some issues with DNS. I looked at some dynamic DNS services such as Dyn and no-ip (which I’ve used before and was happy with), but I decided that I’d rather implement my own solution. I found a VPS provider at ipxcore that had a virtual server for only $1.16 a month (well within impulse buy range), so I got one.
The first thing I did was install the Debian image and boot it up. I chose Debian because I wanted a binary package manager so I didn’t have to worry about compiling a bunch of packages on a small VPS with little RAM, and I figured that Debian would have less cruft than the Ubuntu image. Unfortunately, the default Debian image included a bunch of things pre-installed that I didn’t want including Apache, a mail server, and a bunch of other services. I spent 30 minutes or so removing packages trying to get back to a bare-bones system before I decided to try the Gentoo image. Gentoo has been my Linux distribution of choice for 7 years, so I’m fairly adept at getting it configured just the way I want it. Luckily, the Gentoo image provided by ipxcore contained a very minimal set of installed packages.
Following directions found on the Free BSD
Wiki and the Gentoo Wiki, I was
able to get BIND installed and configured. It was a lot simpler that I thought
it would be. I set up a zone file for timmontague.com that contained the SOA,
NS, MX, TXT and other various records that are static and won’t change based on
the dynamic IP address. I generated a cryptographic key to allow for remote DNS
updates via the nsupdate
command and copied it to my web server.
The first semi-difficult part was writing the script to automatically update
the DNS records, in particular determining the external IP address of the web
server (because it is behind a NAT). The dynamic DNS resources that I found
suggested running a small PHP or Perl script in a web server that simply printed
the REMOTE_ADDR
. I didn’t want to install a PHP on my minimal VPS,
and Perl also seemed a little overkill, so I decided to write a small CGI
program in C.
I installed a small web server
and configured it to run CGI scripts. When I attempted to access the script from
a remote location however, I kept getting 500 Internal Error messages
(There was an unusual problem serving the requested URL
'/myip.cgi'.
). It’s exceedingly difficult to Google for such errors, but
eventually I concluded that it was because the web server was sand-boxed, the
binary would have to be statically linked. I recompiled it using gcc -o
myip.cgi myip.c -static -L/lib -lc
and started working perfectly.
I wrote a bash script on my web server to automatically determine it’s external
IP address, and if it has changed, update the BIND server using
nsupdate
.
I set up cron to run the script every minute and it seems to be working fine, but so far (the last 4 days), the dynamic IP address hasn’t changed. I set the TTL to be 10 seconds, so when it does change, the downtime should be minimal.
The last step was updating the nameserver on my domain registrar’s website. I
updated the nameserver to ns.timmontague.com
, and added a glue
record for ns.timmontague.com
to 68.171.100.161
(the
static IP of my VPS). I waited a few hours for the changes to propagate, and it
worked!
All in all, setting up my own nameserver was much easier than expected. It only took a few hours to configure and install the BIND DNS server on a bare-bones VPS. In the end, my VPS is still incredibly small; the only extra packages I installed are:
app-admin/logrotate
app-admin/sudo
app-admin/sysklogd
app-editors/vim
mail-client/mailx
net-dns/bind
net-dns/bind-tools
net-firewall/iptables
sys-process/vixie-cron
www-servers/thttpd
I also set up backups on my VPS containing /etc/
,
/var/www/ns
, and /home/tim
. After gzip, the backups
are less than 150kB. It’s nice knowing that if I ever need to switch VPS
providers, I will be able to get another name server up and running with a
minimal amount of effort.