-
-
Save d0zingcat/8cd76dc49d28c99af010c67a4a94d30b to your computer and use it in GitHub Desktop.
CloudFlare Dynamic DNS Shell Script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
##!/usr/bin/env sh | |
# Gist: https://gist.github.com/D0zingcat/8cd76dc49d28c99af010c67a4a94d30b | |
# forked from: https://gist.github.com/chappy84/9606755 | |
# use environment variables instead of flags (as in docker pass parameters is not very convenient) | |
# a docker image is derived from this script: d0zingcat/ddns-reporter (:latest tag for amd x86-64 arch and :armv8 tag for arm x64 v8 arch, e.g. raspberry pi 4B | |
# you could use this image to report your dynamic public ip to cloudflare(to update your A DNS record) | |
# command: docker run -e KEY=${KEY} -e NAME=${subdomain} -e EMAIL=${cloudflare_email} -e ZONE={base_domain} d0zingcat/ddns-reporter:latest | |
# Dockerfile: https://github.com/D0zingcat/all-in-docker/blob/main/ddns-reporter/Dockerfile | |
# 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 theprovided API key | |
#set -x | |
key=${KEY} | |
email=${EMAIL} | |
zone=${ZONE} | |
zone_id=${ZONE_ID} | |
type=A | |
rec_id=${REC_ID} | |
name=${NAME} | |
content=${CONTENT} | |
ttl=1 | |
proxied=false | |
report_interval=${REPORT_INTERVAL:-60} | |
function report() { | |
if [ "$content" = "" ] | |
then | |
content=`curl -s -4 http://icanhazip.com/` | |
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. Skip." | |
continue | |
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 -s -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 -s -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]+)\"[^\}]+\$hostname\",\"type\":\"$type\"[^\}]+.+/\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 -s -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 | |
} | |
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 | |
while true; | |
do | |
echo "sleep for $report_interval s" | |
sleep $report_interval | |
report | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment