Published 2022-01-30.
Time to read: about 4 minutes.
Now that I have fiber-optic internet service in my apartment, with 500 GB/s upload and download, I thought I would save money by hosting my scalacourses.com
website on an Ubuntu server that runs here, instead of AWS. My home IP address is quite stable, and only changes when the fiber modem boots up. The modem is branded as a Bell Home Hub 4000, but I believe it is actually made by Arris (formerly known as Motorola).
It makes little sense to pay the commercial cost of dedicated dynamic DNS services (typically $55 USD / year) when it is so easy to automate, and the operational cost is less than one cent per year.
Because I continue to use AWS Route53 for DNS, I wrote a little script that automatically checks my public IP address, and upserts a Route53 record for my home IP address whenever the IP address changes.
The approach shown here could be used for all DNS servers that have a command-line interface, not just AWS Route53. Alternatives include Azure DNS, Cloudflare DNS, DNSMadeEasy, DNSimple, Google Cloud DNS, and UltraDNS.
Forwarding HTTP Requests
I added some entries to the modem so incoming HTTP traffic on ports 80 and 443 would be forwarded to ports 9000 and 9443 on my home server, gojira
.

Using the Script
The script saves the IP address to a file, and periodically compare the saved value to the current value. Then the script modifies the Route53 record for a specified subdomain whenever the value of my public IP address changes.
Here is the help information for the script :
$ dynamicDns dynamicDns - Maintains a dynamic DNS record in AWS Route53
Saves data in '/home/mslinn/.dynamicDns'
Syntax: dynamicDns [OPTIONS] SUB_DOMAIN DOMAIN
OPTIONS: -v Verbose mode
Example usage: dynamicDns my_subdomain my_domain.com dynamicDns -v my_subdomain my_domain.com
Here is a sample usage:
$ dynamicDns my_subdomain my_domain.com { "ChangeInfo": { "Id": "/change/C075751811HI18SH4L8L0", "Status": "PENDING", "SubmittedAt": "2022-01-30T21:10:09.261Z", "Comment": "UPSERT a record for my_subdomain.my_domain.com" } }
Invoking the Script from Crontab
A personal crontab
can be modified by typing:
$ crontab -e
I pasted in the following 2 lines into crontab
on my Ubuntu server, running at home. These lines invoke the script via crontab
when it boots, and every 5 minutes after that.
@reboot /path/to/dynamicDns my_subdomain my_domain.com */5 * * * * /path/to/dynamicDns my_subdomain my_domain.com
That's it, crontab
will run the script within the next 5 minutes.
Script Source Code
Here is the bash script:
#!/bin/bash # Author: Mike Slinn mslinn@mslinn.com # Written 2022-01-30 export SAVE_FILE_NAME="$HOME/.dynamicDns" function help { echo "$( basename $0 ) - Maintains a dynamic DNS record in AWS Route53 Saves data in '$SAVE_FILE_NAME' Syntax: $( basename $0) [OPTIONS] SUB_DOMAIN DOMAIN OPTIONS: -v Verbose mode Example usage: $( basename $0) my_subdomain mydomain.com $( basename $0) -v my_subdomain mydomain.com " exit 1 } function upsert { export HOSTED_ZONES="$( aws route53 list-hosted-zones )" export HOSTED_ZONE_RECORD="$( jq -r ".HostedZones[] | select(.Name == \"$DOMAIN.\")" <<< "$HOSTED_ZONES" )" export HOSTED_ZONE_RECORD_ID="$( jq -r .Id <<< "$HOSTED_ZONE_RECORD" )" aws route53 change-resource-record-sets \ --hosted-zone-id "$HOSTED_ZONE_RECORD_ID" \ --change-batch "{ \"Comment\": \"UPSERT a record for $SUBDOMAIN.$DOMAIN\", \"Changes\": [{ \"Action\": \"UPSERT\", \"ResourceRecordSet\": { \"Name\": \"$SUBDOMAIN.$DOMAIN\", \"Type\": \"A\", \"TTL\": 300, \"ResourceRecords\": [{ \"Value\": \"$IP\"}] } }] }" echo "$IP" > "$SAVE_FILE_NAME" } if [ "$1" == -v ]; then export VERBOSE=true shift fi if [ -z "$2" ]; then help; fi set -e export SUBDOMAIN="$1" export DOMAIN="$2" export IP="$( dig +short myip.opendns.com @resolver1.opendns.com )" if [ ! -f "$SAVE_FILE_NAME" ]; then if [ "$VERBOSE" ]; then echo "Creating $SAVE_FILE_NAME"; fi upsert; elif [ $( cat "$SAVE_FILE_NAME" ) != "$IP" ]; then if [ "$VERBOSE" ]; then echo "Updating $SAVE_FILE_NAME" echo "'$IP' was not equal to '$( cat "$SAVE_FILE_NAME" )'" fi upsert; else if [ "$VERBOSE" ]; then echo "No change necessary for $SAVE_FILE_NAME"; fi fi