Skip to content

Instantly share code, notes, and snippets.

@itay-grudev
Last active February 27, 2018 14:16
Show Gist options
  • Save itay-grudev/754544a9a75eea4ef2fbdf38cfc34f18 to your computer and use it in GitHub Desktop.
Save itay-grudev/754544a9a75eea4ef2fbdf38cfc34f18 to your computer and use it in GitHub Desktop.
Bash Script for free reliable Dynamic DNS (DynDNS) using the Digital Ocean API
#!/bin/bash
##
# This script check whether the server's public IP has changed and updates an
# A DNS record with the Digital Ocean API.
# /etc/dodyndns configuration file:
# SERVER_IP=127.0.0.1
# RECORD_ID=
#
# DYNDNS_DOMAIN_PREFIX=dyndns
# DIGITAL_OCEAN_DOMAIN=example.com
# DIGITAL_OCEAN_API_TOKEN=asdfghjkl1234567890
# DNS_TTL=60
# ADMIN_EMAIL="admin@example.org"
# ADMIN_NAME="John Doe"
#
# Copyright: Itay Grudev (c) 2018
# License: MIT
#
source /etc/dodyndns
# Acquire the computer's public address
IP_DIG=$(dig +short myip.opendns.com @resolver1.opendns.com 2>/dev/null)
if [[ $IP_DIG =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
IP=$IP_DIG
else
IP_CURL=$(curl -s https://checkip.amazonaws.com 2>/dev/null)
if [[ $IP_CURL =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
IP=$IP_CURL
fi
fi
# If the script is unable to retrieve the server's external ip address it
# should simply exit silently assuming this is normal downtime
if [ -z "${IP// }" ]; then
exit 0
fi
# If the reported IP addresses has changed to the one on record
if [ "$SERVER_IP" != "$IP" ]; then
function inform_admin_of_error() {
/usr/sbin/sendmail $ADMIN_EMAIL <<-EOF
From: Server: $(hostname) <$LOGNAME@$(hostname)>
To: $ADMIN_NAME <$ADMIN_EMAIL>
Content-Type: text/plain; charset=UTF-8
X-Priority: 1 (Highest)
X-MSMail-Priority: High
Importance: High
Subject: Urgent! Unable to update the server's A record.
Dear $ADMIN_NAME,
The public IP address of $(hostname) has changed from "$SERVER_IP" to "$IP".
But due to a problem with the Digital Ocean API updating the A record of the server was not successful.
Services are most likely unavailable and urgent changes to the DNS A records are probably required.
Kind Regards,
$LOGNAME@$(hostname) via crontab
EOF
}
# Verify the authenticity of the new IP address by comparing SSH fingerprints
TMP_KNOWN_HOSTS=$(mktemp)
ssh-keyscan 127.0.0.1 > $TMP_KNOWN_HOSTS
sed -i "s/127\.0\.0\.1/$IP/" $TMP_KNOWN_HOSTS
RESPONSE=$(ssh -n -o "UserKnownHostsFile $TMP_KNOWN_HOSTS" -o "StrictHostKeyChecking yes" $IP true 2>&1)
rm TMP_KNOWN_HOSTS
if ! [[ $RESPONSE = *"Host key verification failed."* ]]; then
# If everything checks out and there is no MITM update the Digital Ocean DNS
# record. Though we first need to delete the old record.
if [ ! -z "$RECORD_ID" ] && [ "$RECORD_ID" != " " ] && [ "$RECORD_ID" != "null" ]; then
curl -s -X DELETE \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${DIGITAL_OCEAN_API_TOKEN}" \
"https://api.digitalocean.com/v2/domains/${DIGITAL_OCEAN_DOMAIN}/records/${RECORD_ID}" 2>&1 >/dev/null
fi
NEW_RECORD_ID="$(curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${DIGITAL_OCEAN_API_TOKEN}" \
-d "
{
\"type\": \"A\",
\"name\": \"$DYNDNS_DOMAIN_PREFIX\",
\"data\": \"$IP\",
\"ttl\": $DNS_TTL
}" \
"https://api.digitalocean.com/v2/domains/${DIGITAL_OCEAN_DOMAIN}/records" | \
jq '.domain_record.id')"
# Verify the record id is valid
NUMERICAL_REGEX='^[0-9]+$'
if ! [[ $NEW_RECORD_ID =~ $NUMERICAL_REGEX ]]; then
inform_admin_of_error
exit 1
fi
# Verify the new domain name was saved
SAVED_RECORD_ID="$(curl -s -X GET \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${DIGITAL_OCEAN_API_TOKEN}" \
"https://api.digitalocean.com/v2/domains/${DIGITAL_OCEAN_DOMAIN}/records/${NEW_RECORD_ID}" | \
jq '.domain_record.id')"
# Verify the record id is numeric
if [[ "$NEW_RECORD_ID" == "$SAVED_RECORD_ID" ]]; then
# Update the configuration settings
sed -i "s/SERVER_IP=.\+/SERVER_IP=$IP/" /etc/dodyndns
sed -i "s/RECORD_ID=.\+/RECORD_ID=$NEW_RECORD_ID/" /etc/dodyndns
else
inform_admin_of_error
exit 1
fi
fi
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment