RICHARD HALLETT

2019-01-20 20:24

Updating dynamic home server IP using AWS

I run a small Raspberry Pi server from my home IP, it doesn't do a lot, it mostly runs a permanent connection to IRC via irssi because I do still use IRC (a topic for a different post). I have always in the past had a public static IP, however recently I've moved where it's now dynamic. Sometimes I want to be able to access my box externally and so I thought I'd write a little bash script that lets me update a DNS entry for my public ip.

Requirements

  • AWS CLI -- For doing the update to AWS Route53
  • dig -- Part of standard *nix dns-utils, used to get the ip
  • cron -- To run the script daily

Basic script structure

1. Get the current IP

There are some excellent answers floating around the internet and I opted for using DNS to obtain the IP, you could however use a third party webservice and get it over HTTP.

dig +short myip.opendns.com @resolver1.opendns.com

2. Check against cached IP

Don't do any updates if we have the same IP already set. I did consider making a DNS check for this too, but a local file seemed just as good.

if grep -Fxq "$IP" "$IPFILE"
then
    echo "No IP change required."
    exit 0
fi

## Later in script... just store it...

echo "$IP" > "$IPFILE"

3. Make the AWS request

I'm using Route53 to manage my DNS, this means I can use their AWS CLI tools to do the update, see AWS documentation In general though you

  1. Build the json request file.
  2. Use AWS CLI to make the request with that json file

You will need to ensure you've preconfigured AWS CLI with your access keys.

aws route53 change-resource-record-sets --hosted-zone-id HZXXXXXX --change-batch file://request.json

Full bash script for your viewing pleasure.

#!/bin/bash
# Update amazon route53 with new IP on a record
# e.g. usage for finding your home router.

# Config
DNSRECORDNAME=$1 # A record syntax
TTL=300 # DNS TTL
HOSTEDZONEID=$2 # ID of your Route53 AWS hosted zone

if [ -z "$1" ]
  then
    echo "Please specify the A record to update with the public IP"
    exit 0
fi

if [ -z "$2" ]
  then
    echo "Second argument needs to be your Route53 Hosted Zone ID"
    exit 0
fi

# Get the IP
IP=`dig +short myip.opendns.com @resolver1.opendns.com`
IPFILE="$PWD/$DNSRECORDNAME-ip.iplock"

echo "Found IP: $IP"

# Ensure we have something existing for the IP file.
if [ ! -e "$IPFILE" ]
then
    touch "$IPFILE"
fi

# Don't try any updates if we have same IP as last time.
if grep -Fxq "$IP" "$IPFILE"
then
    echo "No IP change required."
    exit 0
fi

# Build update record
UPDATERECORDFILE=$(mktemp /tmp/update-home-ip.XXXXXXXX)

cat > ${UPDATERECORDFILE} <<- EOM
{
    "Comment": "Updating IP for home server.",
    "Changes": [
        {
            "Action": "UPSERT",
            "ResourceRecordSet": {
                "Name": "$DNSRECORDNAME",
                "Type": "A",
                "TTL": $TTL,
                "ResourceRecords": [
                    {
                        "Value": "$IP"
                    }
                ]
            }
        }
    ]
}
EOM

cat $UPDATERECORDFILE

# Send the AWS command
echo "Attempting to update to: $IP"
aws route53 change-resource-record-sets --hosted-zone-id $HOSTEDZONEID --change-batch file://"$UPDATERECORDFILE"

# Clean up
rm "$UPDATERECORDFILE"

# Store the updated IP we got for next time.
echo "$IP" > "$IPFILE"