We love and highly recommend Digital Ocean for your hosting needs – they have a ton of features and are very fast!

One of the features they provide is the doctl command line utility which allows you to set almost anything you need remotely. A common use case we’ve come across is updating a dynamic IP. In order to do that, we wrote a bash script that you can run manually or schedule with cron.

Digital Ocean API Access

Note that you will need to log in to your Digital Ocean account and create a read/write API key. When you log in, choose API from the left or use this link: https://cloud.digitalocean.com/account/api/

Adding the doctl command line

You’ll need to have the doctl command installed on your system, which you can do by following the installation steps at the project home page on GitHub.

Our script uses the default path of /snap/bin which would be the doctl path if you install from the Snap, but you can also set the path via the command line options.

Script Options

There are three required options you must use when calling the script:

  • –domain=<domain_name>
    • The name of the domain where the A record lives that will be updated.
  • –hostname=<record_set>
    • The name of the hostname set to update without the domain.
  • –accesstoken=<docker_api_key>
    • Provide your docker API key here.

There are also two optional settings:

  • –email=<email_address>
    • Optional: Enter an email where the log will be delivered. If no email is provided, the script will not attempt to send an email.
  • –doctlpath=<path_to_doctl>
    • Optional: Enter the path where the doctl command is on your system. It defaults to /snap/bin.

Example Usage

/opt/scripts/digitalocean-dynamic-ip.sh –domain=yourdomain.com –hostname=dynamichost –accesstoken=your_api_key_here –email=youremail@email.com

How to Use with Cron

If you’re on a Linux system, you can run this every 30 minutes (or whatever interval you like) with cron.

Open your crontab for editing with this command:

sudo crontab -e

Then add a line like this:

*/30 * * * * /opt/scripts/digitalocean-dynamic-ip.sh --domain=yourdomain.com --hostname=dynamichost --accesstoken=your_api_key_here --email=youremail@email.com

Get the Script!

You can always find the latest version of the script on our GitHub, but here it is in it’s entirety as well:

#!/bin/bash

# Version: 1.0
# Date: 2018/08/26
# Author: Steve Talley (Dusty Sun) <steve@dustysun.com>

usage=$(cat <<"EOF"
Usage:
    ./doctl-updatedns.sh [--help] --record=<record_set_name>
                        [--ttl=<ttl_seconds>] [--type=<record_type>]
                        --zone=<zone_id>
Update a Digital Ocean record with your external IP address. A log file is created in the same directory as this script.

OPTIONS
    --help
        Show this output

    --domain=<domain_name>
        The name of the domain where the A record lives that will be updated.

    --hostname=<record_set>
        The name of the hostname set to update without the domain.

    --accesstoken=<docker_api_key>
        Provide your docker API key here.

    --email=<email_address>
        Optional: Enter an email where the log will be delivered. If no email is provided, the script will not attempt to send an email.
    
    --doctlpath=<path_to_doctl>
        Optional: Enter the path where the doctl command is on your system. It defaults to /snap/bin.
EOF
)

SHOW_HELP=0
DOMAIN=""
HOSTNAME=""
ACCESSTOKEN=""
EMAIL=""
DOCTL_PATH="/snap/bin"

# Get current dir
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
LOGFILE="$DIR/digitalocean-dynamic-ip.log"

while [ $# -gt 0 ]; do
    case "$1" in
        --help)
            SHOW_HELP=1
            ;;
        --domain=*)
            DOMAIN="${1#*=}"
            ;;
        --hostname=*)
            HOSTNAME="${1#*=}"
            ;;
        --accesstoken=*)
            ACCESSTOKEN="${1#*=}"
            ;;
        --email=*)
            EMAIL="${1#*=}"
            ;;
        --doctlpath=*)
            DOCTL_PATH="${1#*=}"
            ;;
        *)
            SHOW_HELP=1
    esac
    shift
done

if [  -z "$DOMAIN" -o -z "$HOSTNAME" -o -z "$ACCESSTOKEN" ]; then
    SHOW_HELP=1
fi

if [ $SHOW_HELP -eq 1 ]; then
    echo "$usage"
    exit 0
fi

# Start logfile fresh 
echo `date` > "$LOGFILE"

# get the current ip
${DOCTL_PATH}/doctl --access-token ${ACCESSTOKEN} compute domain records list ${DOMAIN} --output json > /tmp/digitalocean.json

echo "import json" > /tmp/digitalocean.py
echo "import sys" >> /tmp/digitalocean.py
echo "from pprint import pprint" >> /tmp/digitalocean.py
echo "jdata = sys.stdin.read()" >> /tmp/digitalocean.py
echo "jsonObject = json.loads(jdata)" >> /tmp/digitalocean.py
echo "for x in jsonObject:" >> /tmp/digitalocean.py
echo "    if x[\"name\"]=='${HOSTNAME}':" >> /tmp/digitalocean.py
echo "        print(\"{}|{}\").format(x[\"data\"],x[\"id\"])" >> /tmp/digitalocean.py

DIGITALOCEAN_INFO=`cat /tmp/digitalocean.json | python /tmp/digitalocean.py`

DIGITALOCEAN_IP=`echo $DIGITALOCEAN_INFO |cut -d '|' -f1`
DIGITALOCEAN_ID=`echo $DIGITALOCEAN_INFO |cut -d"|" -f2`

echo Digital Ocean Record ID: ${DIGITALOCEAN_ID} >> "$LOGFILE"
echo Digital Ocean Original IP: ${DIGITALOCEAN_IP} >> "$LOGFILE"
# Get the external IP address from OpenDNS (more reliable than other providers)
IP=`dig +short myip.opendns.com @resolver1.opendns.com`

function valid_ip()
{
    local  ip=$1
    local  stat=1

    if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
        OIFS=$IFS
        IFS='.'
        ip=($ip)
        IFS=$OIFS
        [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
            && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
        stat=$?
    fi
    return $stat
}

if ! valid_ip $DIGITALOCEAN_IP; then
    echo "Unable to obtain valid IP address from Digital Ocean: $DIGITALOCEAN_IP" >> "$LOGFILE"
    exit 1
fi

if ! valid_ip $IP; then
    echo "Invalid IP address: $IP" >> "$LOGFILE"
    exit 1
fi

#compare local IP to dns record
if [ "$IP" ==  "$DIGITALOCEAN_IP" ]; then
    # code if found
    echo "IP for ${HOSTNAME}.${DOMAIN} is still $IP. No change was made to the record." >> "$LOGFILE"
    exit 0
else
    echo "IP has changed to $IP. Updating Digital Ocean record." >> "$LOGFILE"
    #update the IP record
    ${DOCTL_PATH}/doctl --access-token ${ACCESSTOKEN} compute domain records update ${DOMAIN} --record-name ${HOSTNAME} --record-data ${IP} --record-id ${DIGITALOCEAN_ID} --output json >> "$LOGFILE"
fi

if [ ! -z "$EMAIL" ]; then
    cat $LOGFILE | /usr/bin/mail -s "DOCTL: IP Address Update" -a "From: ${EMAIL}" $EMAIL 
fi

How Did This Work For You?

Do you have any questions on this? Did it work for you? We’d love to hear your feedback! Please leave a comment below or send us an email at support@dustysun.com.

Steve Talley

Pin It on Pinterest

Share This