Dynamic DNS with AWS Route 53 – the Good, the Bad and the Ugly

aws aws-route53 aws-lambda aws-api-gateway Fritz!Box DynDNS DynDNS53

What to do with an AWS account, an own domain and the desire to fiddle with some AWS services? One obvious thing is to abandon dynamic DNS services like FreeDNS and host the names of two DSL routers (a Fritz!Box 9490 and a Fritz!Box 3270) in Route 53. So what are the options?

My search turned up three types of options. I’ll discuss them in non-canonical order though: The Bad, the Good and the Ugly

The Bad – local programs

The simplest solutions crop up in the Google query for route53 dyndns: Most of them are programs running on a computer behind the router. They update Route 53 periodically using the API of Route 53. The simplest one are shell scripts using the aws(1) CLI commands and are triggered periodically by cron(8).

This approach fails short in several ways:

  1. I don’t want to run additional computers 24/7 just to update the DNS.

    Less moving parts are better.

  2. I want to access both routers even when no computers are running behind the routers.

    The usecases are remote administration, connecting the routers via VPN and accessing files stored directly on them.

  3. The router knows best when its public IP changes and also the value of the new IP1.

    There’s no need to do that every five minutes or so.

  4. The AWS credentials must be on the clients – in hostile territory.

    It’s generally a bad idea to distribute IAM credentials and especially so for Route 53. In Route 53 there is currently no way to allow one client to change only one specific DNS record. The IAM permissions only work on the complete DNS zone:

    Not all Route 53 resources support permissions. You can’t grant or deny access to the following resources: […] Individual records […] Amazon Route 53 - Developer Guide

Fortunately both Fritz!Boxes support “Dynamic DNS” via some well known providers but also allow to specify custom URLs with placeholders. This eliminates the additional computer and this class of solutions.

So the search goes on.

The Good – “Building a Serverless Dynamic DNS System with AWS”

“Building a Serverless Dynamic DNS System with AWS” (12/2015) by Sean Greathouse, Solution Architect has been published on the AWS Blog and on medium.com, the code is in GitHub.

The great article explains how to setup two Lambdas, the API-Gateway and Route 53 for dynamic DNS updates. Configuration is stored in S3 or in Dynamo-DB (the GitHub version). The article goes the extra mile to explain the stuff with nice diagrams and the Github repository contains a CloudFormation template to automate the setup.

The bad part (for my usecase) is: The protocol is not compatible to anything I’ve encountered so far. The article contains an example request for updating the IP. It looks like this (reformatted for clarity):


The hash part is the SHA-256 digest of the IP, the FQDN and the secret password. It serves as an authentication token. But the Fritz!Box currently supports only Base-64 encoding using the <b64>mydata</b64> placeholder but no hashing.

The second gotcha is: The example request does not feature a query parameter for the IP address. It is not accessible in the hash because a hash is not reversible. So it might be determined automatically by using the source address of the HTTP connection.

The third gotcha pertains the response: The result of the Lambda is a JSON document which the Fritz!Box cannot handle.

Another nitpick: The CloudFormation template contains everything in one big file. While this may be convenient for distribution it is quite bad for development because the code cannot be edited or debugged in an IDE using the appropriate language tooling.

So while the article is great and good for learning some AWS things but this solution requires considerable work upfront to get off the ground using standard clients.

The Ugly – DynDNS53

DynDNS53 is a project by Scott Armitage (aka. sTywin) on GitHub. The supported protocol looks good – a subset of the DynDNS protocol also used by Google-Domains. This means:

This is exactly what the Fritz!Boxes supports using custom URLs!

The repository features one AWS Lambda written in Python and instructions to setup the AWS API-Gateway, IAM and so on.

This project ticked most of my boxes:

Contrary to the Greathouse project the code is …minimal… Indeed it is so minimal that the configuration is part of the code and the setup instructions are more than twice the code size.

Fortunately there are some open pull requests which

Especially the Makefile is great for initial setup – setting up the API Gateway using the AWS Console is a duty not for humans but for condemned sinners in hell.

It is good that the pull requests are there and that they make live much easier. But that they are not merged shows that the original author doesn’t maintain the project any more :-( Therefore I have forked it, merged the pull requests and improved the code in other ways.

Some might complain about missing features, some might value the minimalism. I thought this is a good start with room for improvement while learning more AWS stuff.

… and some odd ends

The three solutions above cover most of the ground for providing a few routers with dynamic DNS services. The following solutions didn’t make the race but are notable in some way:

Although these projects didn’t make the race for various reasons they show interesting approaches and hence deserve a honourable mention.


So – in the end – did DynDNS53 the job at hand? As life always is: Yes, but…

The plan was to have no additional server to manage. AWS Lambda and API Gateway take care of that. But the API Gateway accepts only contemporary HTTPS which the older Fritz!Box (the 3270) does not support. The newer one has no problem with that. Therefore a small NGINX server forwards the HTTP requests for the older box to the API Gateway. Which means – a managed server :-(

  1. : Programs running behind the router have to do some acrobatics to get the public IP of the router. And getting both the IPv4 and IPv6 address is a small stunt. ↩︎

  2. It is quite interesting to setup an empty webserver as a simple honeypot and – without telling anyone the IP or URL – to watch the constant attacks pelting on every open port. At least for a while. After that it gets quite annoying. ↩︎