DIY Dynamic DNS with Route 53

I haven't needed dynamic DNS service for a while, but I have a new use case that calls for it. I looked around at the existing free options, and had a flash of that "if you're not paying for it, you're the product" feeling.

Suddenly, it hit me. I have DNS hosted somewhere that I can update via API. (AWS Route 53). This is easy!

The only dependency is that your computer be

  1. Configured with AWS credentials in a named profile
  2. Have cli53 installed
  3. Have curl, bash and dig installed.
  4. Already have a zone configured in Route53.

Tweak the below script to match your AWS profile and managed zone.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash

# Requires cli53 (i.e. `brew install cli53` on mac)

# Update these values for yourself
export AWS_PROFILE='myprofile'
ZONE="mydomain.com"
HOSTNAME="dynamichost"
# this would configure dynamichost.mydomain.com with your current public IP

export PATH="/usr/local/bin:/usr/bin/:$PATH"
REMOTE_IP=$(curl -s ipecho.net/plain)
CURRENT_VALUE=$(dig +short $HOSTNAME.$ZONE)

if [[ $REMOTE_IP =~ [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+ ]] ; then
    if [[ $CURRENT_VALUE != $REMOTE_IP ]] ; then
        cli53 rrcreate --replace $ZONE "$HOSTNAME 60 A $REMOTE_IP"
    fi
fi

It uses dig +short first to check the current value of the setting, so it doesn't bother with changing the values in Route 53 unless a change is needed.

Even though it's been deprecated, I still use crontab, as it works and is a lot simpler than launchd.

To install this, copy the script somewhere on your machine, then run crontab -e. A simple cron like this will run the script once every 2 minutes:

*/2 * * * * /Path/To/Your/script.sh

And you're done! You will have a 60 second TTL DNS entry which only gets updated when your actual public IP changes, at what will probably be $0 additional cost, if you're already hosting the zone in R53.

The Serverless Tool Nobody Talks About

I'm a big fan of the recent rise of "Serverless" computing, spearheaded by AWS's Lambda. Many people have pointed out that "Serverless is made of servers", which is a fair point. ("Functions as a Service" is probably better.) But they aren't servers that I have to pay for when I'm not using, keep patched, manage runtimes for, and so on. There are obviously tons of use cases where FaaS won't work -- but when it will, why not?

It hit me the other day, though, that I've used another tool that lets code be written and run -- even sophisticated use cases like running on a schedule, interacting with other web services, and so on -- which vastly predates AWS Lambda. That tool is Google Apps Script.

Here's a problem I had been thinking of solving with Lambda (mostly as an exercise in building an end-to-end app, but also because it was a real problem I had.)

My kids get allowance: $1/week for every year old they are. We still want them to physically get the funds, so they can have the tangible reality of collecting it, having to give it back when they buy things they've saved for, and allocate between Spend/Save/Give categories.

The problem is, I had a terrible track record of remembering to hand it out on our typical period. And a lot of the time I did remember, it coincided with a lack of small bills or coins.

What I needed was a system which would 'buffer' for me. The desired features were:

  • Deposit a kid-appropriate number per week
  • Allow me to decrement it when "paying out" -- and properly secured, so that nefarious parties (or creative hacker inclined 7 year olds) could not tweak the balances
  • Allow the older kids to have read-only views of the values that they could consult via the web. (Desktop bookmarks on iOS.)
  • Have an audit trail of when and what changes were made.

I sketched this with Lambda. All very possible, but non-trivial.

  • Data could be stored in DynamoDB, or even -- given the low write volume -- as structured data in S3.
  • Auth is still a little complicated, even if you using Cognito, but could be linked to Google or Facebook, or even tied to a simple token stored in KMS.
  • Read-only access is simple, if publishing the values to a s3 website-enabled bucket.
  • Editing could be a pretty simple Single Page App, hosted in the bucket, that targeted an API Gateway endpoint.
  • Periodically incrementing the values is also easy, with a scheduled Lambda task.
  • The audit trail could be stored in DynamoDB or Cloudwatch Logs.

So it's very doable, but that's also a lot of overhead. If I wanted to build a SaaS allowance product, though, it could be a pretty excellent starting point, with a pretty incredible scaling/cost profile!

However, here's what it took in Google Apps.

  • Create a new spreadsheet.
  • Set up the basic structure of the document
Spreadsheet
  • Launch the script editor (Tools > Script Editor)
Launch Script Editor
  • Enter the simple code
Code Listing

In copy/paste compatible form:

function divvyAllowance() {
    var ss = SpreadsheetApp.getActiveSpreadsheet();
    for (var i = 2; i <= 4; i++) {
        incby = ss.getRange('B' + i).getValue();
        balance = ss.getRange('C' + i);
        balance.setValue(balance.getValue() + incby);
    }
}
  • Click the 'clock' icon in the script editor to enter the schedule, and set the function to run weekly.
Schedule

And that is it! It meets all the requirements, at no additional cost -- in fact, no cost at all, in many Google plans.

  • I can use the Google Sheets app to check on the values if I'm being consulted about a kid's current balance while in a store.
  • I can share write access with my wife, too.
  • I can give the kids read-only URLs to consult if need be
  • The sheets Revision History will track every edit, including the automated ones.

So, of course, this provides far lower control, customization, and possibly even scalability as the full-bore serverless implementation outlined above. But it's also VASTLY more simple and manageable. So, thanks Google, for being Serverless pioneers, and still being a good option for a lot of these use cases!

Contents © 2016 Joshua Barratt - Powered by Nikola