Skip to content

Instantly share code, notes, and snippets.

@jthigh
Forked from chappy84/cloudflare_dyn_dns.sh
Created September 17, 2023 23:08
Show Gist options
  • Save jthigh/6db70f624064554e30a50c9ec2ad30ed to your computer and use it in GitHub Desktop.
Save jthigh/6db70f624064554e30a50c9ec2ad30ed to your computer and use it in GitHub Desktop.
CloudFlare Dynamic DNS Shell Script
#!/bin/sh
#
# CloudFlare Dynamic DNS
#
# Updates CloudFlare records with the current public IP address
#
# Takes the same basic arguments as A/CNAME updates in the CloudFlare v4 API
# https://www.cloudflare.com/docs/client-api.html#s5.2
#
# Use with cron jobs etc.
#
# e.g.
#
# manually run:
# cloudflare_dyn_dns.sh -key 404613183ab3971a2118ae5bf03d63e032f9e -email [email protected] -zone example.com -name extra
#
# cronjob entry to run every 5 minutes:
# */5 * * * * /path/to/cloudflare_dyn_dns.sh -key 404613183ab3971a2118ae5bf03d63e032f9e -email [email protected] -zone example.com -name extra >> /path/to/cloudflare_dyn_dns.log
#
# will both set the type A DNS record for extra.example.com to the current public IP address for user [email protected] with the provided API key
key=
email=
zone=
zone_id=
type=A
rec_id=
name=
content=
ttl=1
proxied=false
while [ "$1" != "" ]; do
case $1 in
-key ) shift
key=$1
;;
-email ) shift
email=$1
;;
-zone ) shift
zone=$1
;;
-zone_id ) shift
zone_id=$1
;;
-type ) shift
type=$1
;;
-rec_id ) shift
rec_id=$1
;;
-name ) shift
name=$1
;;
-content ) shift
content=$1
;;
-ttl ) shift
ttl=$1
;;
-proxied ) shift
proxied=$1
;;
* ) echo "unknown parameter $1"
exit 1
esac
shift
done
if [ "$content" = "" ]
then
content=`curl -s http://myexternalip.com/raw`
if [ "$content" = "" ]
then
date
echo "No IP address to set record value with."
exit 1
fi
fi
if [ "$name" = "" ]
then
echo "You must provide the name of the record you wish to change."
exit 1
fi
if [ "$zone" = "" ]
then
echo "You must provide the domain you wish to change."
exit 1
fi
if [ "$name" = "$zone" ]
then
hostname="$name"
else
hostname="$name.$zone"
fi
command -v host > /dev/null 2>&1
if [ "$?" = "1" ]
then
command -v nslookup > /dev/null 2>&1
if [ "$?" = "1" ]
then
echo "Cannot find a way to check existing $type record for $hostname"
exit 1
fi
existing_content=`nslookup -type=$type $hostname | awk -F 'Address: ' 'NR==6 { print $2 }'`
else
existing_content=`host -t $type $hostname | sed -E 's/.+?\s+([^\s]+)$/\1/'`
fi
if [ "$content" = "$existing_content" ]
then
echo "Existing record value $existing_content is the same as provided content $content. Exiting."
exit
fi
if [ "$key" = "" ]
then
echo "You must provide your user API token."
exit 1
fi
if [ "$email" = "" ]
then
echo "You must provide your user email."
exit 1
fi
# Get the zone id for the entry we're trying to change if it's not provided
if [ "$zone_id" = "" ]
then
zone_response_json=`curl -X GET "https://api.cloudflare.com/client/v4/zones?name=$zone" -H "X-Auth-Email: $email" -H "X-Auth-Key: $key" -H "Content-Type: application/json"`
zone_id=`echo $zone_response_json | sed -E "s/.+\"result\":\[\{\"id\":\"([a-f0-9]+)\"[^\}]+$zone.+/\1/g"`
if [ "$zone_id" = "" ]
then
echo "Cloudflare DNS Zone id could not be found, please make sure it exists"
exit 1
fi
fi
# Get the record id for the entry we're trying to change if it's not provided
if [ "$rec_id" = "" ]
then
rec_response_json=`curl -X GET "https://api.cloudflare.com/client/v4/zones/$zone_id/dns_records?name=$hostname" -H "X-Auth-Email: $email" -H "X-Auth-Key: $key" -H "Content-Type: application/json"`
rec_id=`echo $rec_response_json | sed -E "s/.+\"result\":\[\{\"id\":\"([a-f0-9]+)\"[^\}]+\"type\":\"$type\"[^\}]+$hostname.+/\1/g"`
if [ "$rec_id" = "" ]
then
echo "Cloudflare DNS Record id could not be found, please make sure it exists"
exit 1
fi
fi
# Update the DNS record
update_response=`curl -X PUT "https://api.cloudflare.com/client/v4/zones/$zone_id/dns_records/$rec_id" -H "X-Auth-Email: $email" -H "X-Auth-Key: $key" -H "Content-Type: application/json" --data "{\"id\":\"$rec_id\",\"type\":\"$type\",\"name\":\"$hostname\",\"content\":\"$content\",\"ttl\":$ttl,\"proxied\":$proxied}"`
success_val=`echo $update_response | sed -E "s/.+\"success\":(true|false).+/\1/g"`
if [ "$success_val" = "true" ]
then
echo "Record Updated."
else
echo "Record update failed."
exit 1
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment