Simple Dynamic DNS

31 Dec 2014

I recently purchased a Raspberry Pi as a very low power home server. One of the many uses for this always-on server is to update a DNS record whenever my public IP changes - this essentially allows me to connect to my home network when I’m outside of it.

About two years ago, I started using DNSimple.com for all of my domains, and one of its great features is an API to manage your domains. The DNSimple API makes building your own “Dynamic DNS system” super simple.

I think this is generally useful, so I wanted to share it.

For the purposes of this tutorial, I’m going to use example.com as the top-level domain, and assume it’s being managed by DNSimple. We’ll also assume home.example.com is the domain that we wish to keep pointed at our home IP.

Let’s get started.

Preliminaries:

First, log into DNSimple and get your account API token from this page.

After you have your account token, navigate to the “example.com” domain and add a new A Record for “home” with a TTL of 60 (1 minute). The IP can be anything, so let’s use 1.1.1.1 for now. If we’re successful, this will be updated in a few minutes anyway.

Once we have created this record, in the DNS overview, hover over the black ? icon. This will indicate the record id which will be required later.

Server Configuration:

Now that we have the preliminary information, we can get to the easy part.

Log into your home server (this is tutorial assumes Linux, but with modifications a similar setup is possible on OS X and Windows).

In your home directory, create a new bash script and make it executable:

$ touch dns_update.sh
$ chmod +x dns_update.sh

Let’s now open dns_update.sh in your favorite text editor, and copy the following script into it. NOTE: THIS SCRIPT WILL NOT WORK BEFORE YOU FOLLOW THE NEXT STEP!!

#! /bin/bash  

ip=$(curl -s https://api.ipify.org/)  

curl -s -H 'X-DNSimple-Token: <account-email-address>:<account-token>' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-X PUT \
-d "{\"record\" : {\"content\":\"$ip\" }}" \
https://api.dnsimple.com/v1/domains/<domain>/records/<record-id> > /dev/null

Now that we have the skeleton of our update script in place, we need to update the following tokens in it using the values we grabbed in the preliminary steps of this tutorial, namely:

  • <account-email-address>
  • <account-token>
  • <domain> (“example.com”, NOT “home.example.com”)
  • <record-id> (The record ID for “home.example.com”)

Save this file, and then run the script from the shell:

$ ./dns_update.sh

At this point, if you navigate to this record in the DNSimple web UI it should contain your current public IP address. (Also notice that we’re using an awesome public API from “ipify.org” to detect our public address).

This script is designed to produce no output by piping it to /dev/null, but you can certainly experiment by removing > /dev/null from the last line of the script.

If everything is working, we have one last step to keep this running; We need to add a cronjob that runs once per minute.

Open the crontab editor so that we can add the update job:

$ crontab -e

Add the following line (and keep in mind how fussy the cron format requirements can be!):

* * * * * <path-to-script>/dns_update.sh

Notice that you will need to update <path-to-script> to point to the full directory where dns_update.sh is stored. Under normal circumstances, this will be your home directory, and the chronjob is also scheduled to run under this account, so the permisions should be OK.

Confirmation:

If you’ve followed the tutorial above carefully, you can confirm everything is working by navigating to th A record in the DNSimple web UI, changing it back to an IP like 1.1.1.1, wait 60-70 seconds, and refresh the web page.

If your cronjob runs successfully, your public IP should be shown in the web UI.

I hope this helps you out and saves you some time!