Wednesday, April 25, 2018

Creating your own dynamic DNS domain in under 10 minutes

A few years back I subscribed to a discounted dynamic DNS service - which has been very useful tbh. It was time to renew (or keep updating those hosts manually each month), then realized I could do my own thing for a fraction of the service subscription cost (and the domain name would be mine for as long as I needed).

My solutions consists on a AWS account making use of route53, a domain purchased from namescheap and a cron job. For dynamic dns on surveillance cameras or storage appliances this might not work out of the box.

First thing, the domain. I wanted something super cheap and found an offer of less than a euro per year for a ".site" domain:



Went straight for 5 years, which was something around 5 euros.

I already had a working AWS account, if not you can find the steps in Amazon Web Services site.

Create a route53 public zone, with the name of the domain you purchased:


 Configure your hosting to make use of the DNS servers provided by AWS (red box):


Add the A records for your devices - i.e. AWS host, or home computer:


Now we have to configure an IAM user capable of updating the DNS records. Go to IAM accounts, groups, create a new one (i.e. dnsupdater) and provide a security policy similar to this one (depending on your needs):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "route53:Get*",
        "route53:List*",
        "route53:Update*",
        "route53:ChangeResourceRecordSets",
        "route53:TestDNSAnswer"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}
Create a user, get the keys and add it to the group.

In your computer, install AWS cli tools with pip install awscli and follow the console instructions to use your credentials.

Setting up the script, I have two files in the folder; template.json and updatedns.sh

The template looks as follows:


{
   "Comment": "Updated record",
   "Changes": [
       {
           "Action": "UPSERT",
           "ResourceRecordSet": {
               "Name": "home.mytest.site",
               "Type": "A",
               "TTL": 300,
               "ResourceRecords": [
                   {
                       "Value": "XXX.XXX.XXX.XXX"
                   }
               ]
           }
       }
   ]
}

You'll have to enter your zone ID in the script:


#!/bin/bash

hostname="home.mystest.site"
current=`host home.mytest.site | awk '{ print $4}'`
external_ip=`curl -s checkip.dyndns.org | sed -e 's/.*Current IP Address: //' -e 's/<.*$//'`
template="/opt/scripts/dns/template.json"
zone_id="/hostedzone/<enter your zone ID>"
dns_template="/opt/scripts/dns/template.json"

echo "My DNS: $current"
echo "My IP: $external_ip"

if [ $current != $external_ip ]; then
       echo "updating zone!"
       sed -i -E "s/\"Value\"\: \".+\"/\"Value\": \"$external_ip\"/g" $dns_template
       aws route53 change-resource-record-sets --hosted-zone-id $zone_id --change-batch file://$dns_template  
fi

Then add it as a cronjob:

$ crontab -l
*/30 * * * *    /opt/scripts/dns/updatedns.sh > /dev/null


All set !