Site Builder

Hardware

You’ll need a machine capable of running Linux. Of course you can go as off the rails as you want- this is your project- but I have had good success with a Raspberry Pi (in my case, a 4GB Pi 4). I see no particular reason you can’t do this with a Pi 3 or even Pi 2 (A Pi Zero may or may not have the horsepower for it- I’m genuinely not sure).

Software

Services

Dynamic DNS via Route53

Route53 Config

AWS, or Amazon Web Services, has all the infrastructure you could ever possibly need to do this work.

Go into the AWS console, and go to Route 53. [note to self: pictures here later].

Create a Hosted Zone. AWS is pretty good at walking you through this- you need to enter a domain name (this example will use farwalker.ca). You may add a description, and this should be a Public Hosted Zone.

Inside your Hosted Zone, you’ll see, auto-created for you, records of types NS (Nameserver) and SOA (Start of Authority). You can leave those alone, their values are already correct.

You’ll need to create a Type A Record (Authority) with the name of your domain (“farwalker.ca” again here for me) and a value of your own IP (see further on for how to change this).

If you want, you can also create CNAME (Canonical Name) records. These are basically aliases, or shortcuts. For example, I have a Record of type CNAME that is named “www.farwalker.ca” and has a value of “farwalker.ca” - someone typing “www.farwalker.ca” will get routed to “farwalker.ca” - and no, those aren’t always the same thing unless, as here, you take some effort to make them so.

In the Hosted zone details, you can also find your Hosted Zone ID- write this down. I’m going to use the (random, fake) example “A49B52C120GWORP”. This is a unique string of letters and numbers that identifies your particular zone out of all the zones AWS knows about. Throughout the rest of this page, this will be referred to as your Zone ID.

IAM Config

Go to IAM. Create a user; mine is called Route53-Dynamic-Updater-User. Under the Security Credentials tab, push the button marked “Create access key”. AWS will give you an access key- make SURE you write this down, as you can NEVER get this again (if you forget it or it’s lost to a crash, you can always just make a new one). This is your Access Key. Now swap over to the Policies page and create a new policy. Use the JSON tab, and fill it in with the following JSON, replacing ZONEID with your Zone ID:

{
    "Version": "2012-10-17",
    "Id": "minimal route53 policy for ddns",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "route53:ListHostedZones",
                "route53:GetChange"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "route53:ChangeResourceRecordSets"
            ],
            "Resource": "arn:aws:route53:::hostedzone/ZONEID"
        }
    ]
}

Review your policy, name it, and save it (Mine is Route53-farwalker.ca-Dynamic). Go back to Users, select your user (Route53-Dynamic-Updater-User), and under the Permissions tab, hit “Add Permissions”. Select “Attach existing policies directly”, and attach your new policy to your user.

That user can now identify itself with your Access Key, and has exactly enough permissions to tweak your one zone (so it can make updates if your IP address changes).

Scripting on your system

This is the script you need to run, either by hand or automatically, to keep your DNS up to date- don’t forget to replace ZONEID with your Zone ID (and farwalker.ca with your own domain name):

#!/bin/bash
HOSTED_ZONE_ID="ZONEID"
NAME="farwalker.ca."
TYPE="A"
TTL=300

#Get current IP
IP=$(curl https://checkip.amazonaws.com)

#Check for malformation
if [[ ! $IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
  exit 1
fi

#Check for identicality
if grep -Fxq "$IP" /usr/local/update-route53.ip; then
  echo "IP still $IP (see also $(cat /usr/local/update-route53.ip))"    
  exit 2
fi
#Update current IP and talk about it
echo "New IP detected: $IP"

cat > /tmp/route53_changes.json << EOF
    {
      "Comment":"Updated From DDNS Shell Script",
      "Changes":[
        {
          "Action":"UPSERT",
          "ResourceRecordSet":{
            "ResourceRecords":[
              {
                "Value":"$IP"
              }
            ],
            "Name":"$NAME",
            "Type":"$TYPE",
            "TTL":$TTL
          }
        }
      ]
    }
EOF

aws route53 change-resource-record-sets --hosted-zone-id $HOSTED_ZONE_ID --change-batch file:///tmp/route53_changes.json && echo "$IP" > /usr/local/update-route53.ip;

You’ll need a few things:

[default]
region = us-east-1
aws_access_key_id = YOUR_ACCESS_KEY_ID_HERE
aws_secret_access_key = Secret_Access_Key_Here

(N.B. if you’re doing this in a region other than us-east-1, change region accordingly)

The script checks to see if your IP has changed since the last time it ran. If it has, it updates your Route53 record to point to your current IP. You can check that it works with aws route53 get-hosted-zones, as the user who is going to be running the script as part of a cronjob.

Unless otherwise specified, the contents of this page are ©2020-2022 Sean M. Ainsworth. All rights, including reproduction or modification, are reserved.