Dynamic DNS Support with CloudFlare

I’ve been using Route53 and aws-cli to dynamically update DNS for my home server for a long time. This time I tried CloudFlare with dynamic DNS support.

First install cloudflare-cli:

$ npm install -g cloudflare-cli

Configure your bash script:

#!/bin/bash

# Setup envrionment
export PATH=/usr/local/bin:/usr/local/sbin:$PATH

# First install cloudflare-cli on OS X:
# npm install -g cloudflare-cli

# Add this script to cron, run it every 10 mins:
# */10 * * * * bash ~/Dropbox/Mac/Backups/Scripts/server-update-cloudflare.sh

# CloudFlare API key
TOKEN="your_token_here"

# CloudFlare account
ACCOUNT="test@example.com"

# Domain name
DOMAIN="example.com"

# The record you want to update e.g. hello, use the bare domain if you want to update root (@) record
RECORD="example.com"

# cfcli location
CFCLI=`which cfcli`

# Log file location
LOGFILE="/tmp/update-cloudflare.log"

# Get the external IP address
IP=`dig +short myip.opendns.com @resolver1.opendns.com`
IPOLD=`$CFCLI listrecords | pcregrep -o1 -e '.+?A.+?example\.com.+?([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).+'`
IPVPN=`ifconfig | grep -o ppp`
# Valid IP
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
}
# Compare IPs
if ! valid_ip $IP; then
  echo "[`date`] ERROR: Invalid IP '$IP'" >> "$LOGFILE"
  exit 1
fi
# Check if the IP has changed
if [ "$IP" == "$IPOLD" ] || [[ $IPVPN ]]; then
  echo "[`date`] SAME: $IP $IPVPN" >> "$LOGFILE"
  exit 0
else
  echo "[`date`] UPDATE: $IPOLD >>> $IP" >> "$LOGFILE"
  $CFCLI -k $TOKEN -e $ACCOUNT -d $DOMAIN editrecord $RECORD $IP
fi

Run it with cron:

*/10 * * * * bash ~/Dropbox/Mac/Backups/Scripts/server-update-cloudflare.sh