web dev & more!

DDNS with Cloudflare API

Published: January 22, 2019

Cloudflare is fantastic but they aren’t a common option for setting up DDNS on your average home router like other services are. Fortunately, it’s super simple to get around this minor inconvenience with the help of their thoroughly documented API. If you’re interested in hosting a website on your own network, are using Cloudflare’s DNS service, and have the problem of your IP changing frequently, then look no further; I’ve done the legwork already.

I took the liberty of borrowing some code I found from Rohan Jain. His post is great and explains how to get your script running as a systemd service. I was lazy and just set the script below to run every 5 minutes in cron job because it’s simple.

To get your DIY DDNS solution up and running follow these steps:

  1. save the bash script from below to a machine on your network
  2. get the appropriate credentials for the script (Cloudflare Email, Auth token, Zone ID, DNS ID, and domain name)
  3. put credentials in the script
  4. create a cron job that runs the script at your desired interval

This script can also be found at https://gist.github.com/Dilden/cbe4787b5e776eb13989df1ba8b54612

#/usr/bin/env sh

# Date
DATE=`date +%Y-%m-%d_%H:%M:%S`

# Get the ZoneID from: https://www.cloudflare.com/a/overview/<your-domain>
DNS_ZONE=YOUR_ZONE_ID_HERE

# Get the existing identifier for DNS entry:
# https://api.cloudflare.com/#dns-records-for-a-zone-list-dns-records
IDENTIFIER=YOUR_DNS_ENTRY

# Get these from: https://www.cloudflare.com/a/account/my-account
AUTH_EMAIL=YOUR_EMAIL
AUTH_KEY=YOUR_GLOBAL_AUTH_KEY

# Desired domain name
DOMAIN_NAME="YOU_DOMAIN_NAME_HERE"

# Get previous IP address
_PREV_IP_FILE="/tmp/public-ip.txt"
_PREV_IP=$(cat $_PREV_IP_FILE)

# Install `dig` via `dnsutils` for faster IP lookup.
eval dig &> /dev/null && {
    _IP=$(dig +short myip.opendns.com @resolver1.opendns.com)
} || {
    _IP=$(curl --silent https://api.ipify.org)
} || {
    exit 1
}


# If new/previous IPs match, no need for an update.
if [ "$_IP" = "$_PREV_IP" ]; then
    exit 0
fi

_UPDATE=$(cat <<EOF
{ "type": "A",
  "name": "$DOMAIN_NAME",
  "content": "$_IP",
  "ttl": 120,
  "proxied": true }
EOF
)

curl "https://api.cloudflare.com/client/v4/zones/$DNS_ZONE/dns_records/$IDENTIFIER" 
     --silent 
     -X PUT 
     -H "Content-Type: application/json" 
     -H "X-Auth-Email: $AUTH_EMAIL" 
     -H "X-Auth-Key: $AUTH_KEY" 
     -d "$_UPDATE" > /tmp/cloudflare-ddns-update.json && 
     echo $_IP > $_PREV_IP_FILE

echo "IP updated to: $_IP on $DATE";