Cloudflare DDNS Script

Categories: DNS Cloudflare

I had an issue with the public IP changing a few times a day. The firewall I’m using has some builtin DDNS services, but Cloudflare isn’t one of them. So I decided to create my own. The script uses Amazons checkip service to get the current public ip and if it doesn’t match with the dns record then the record will be updated.

I use cron to run the script every hour and log the output

0 * * * * sh /path/to/cloudflare-ddns-update.sh >> /var/log/cloudflare-ddns-update.log

The script can be downloaded here: cloudflare-ddns-update.sh or you can see the content below

#!/bin/bash

# Update a Cloudflare DNS A record with the Public IP of the source machine

# Prerequisites:
# - DNS Record has to be created manually at Cloudflare
# - Cloudflare API Token with edit dns zone permissions https://dash.cloudflare.com/profile/api-tokens
# - curl, jq needs to be installed

# Proxy - uncomment and provide details if using a proxy
#export https_proxy=http://<proxyuser>:<proxypassword>@<proxyip>:<proxyport>

# Cloudflare zone is the zone which holds the record
zone="mydomain.com"
# dnsrecord is the A record which will be updated
dnsrecord="example.mydomain.com"

## Cloudflare authentication details
## keep these private
cloudflare_api_token="my-super-secret-api-token"


function update_ip() {
  # get the zone id for the requested zone
  zoneid=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$zone&status=active" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $cloudflare_api_token" | jq -r '{"result"}[] | .[0] | .id')

  echo "Zoneid for $zone is $zoneid"


  # get the dns record id
  dnsrecordid=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records?type=A&name=$dnsrecord" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $cloudflare_api_token" | jq -r '{"result"}[] | .[0] | .id')

  echo "DNSrecordid for $dnsrecord is $dnsrecordid"


  # update the record
  curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records/$dnsrecordid" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $cloudflare_api_token" \
    --data "{\"type\":\"A\",\"name\":\"$dnsrecord\",\"content\":\"$ip\",\"ttl\":1,\"proxied\":false}" | jq
}

function get_ip() {
  # Get the public IP address
  ip=$(curl -s -X GET https://checkip.amazonaws.com)
  dnsip=$(dig $dnsrecord +short @1.1.1.1)

  echo "Public IP is $ip"

  if [[ "$dnsip" == "$ip" ]]; then
    echo "$dnsrecord is currently set to $ip; no changes needed"
    exit
  fi

  update_ip
}

echo ""
echo "-- $(date '+%d/%m/%Y %H:%M:%S') --"
# Run function get_ip
get_ip