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
- Linux OS (Raspbian in my case)
- The
aws-cli
package - (Optional) a web server, if you’re making a site
Services
- Web server, if you’re making a site
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:
- The AWS CLI (if you followed the guide above to software, you have this)
curl
andgrep
(ditto)- Whoever is running the script needs read/write access to
/usr/local/update-route53.ip
and/tmp/route53_changes.json
- In the home directory of the user running the script, you need a folder called
.aws
which contains a file,config
, that looks like this:
[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.