#!/bin/bash | |
# CHANGE THESE | |
auth_email="user@example.com" | |
auth_key="c2547eb745079dac9320b638f5e225cf483cc5cfdda41" # found in cloudflare account settings | |
zone_name="example.com" | |
record_name="www.example.com" | |
# MAYBE CHANGE THESE | |
ip=$(curl -s http://ipv4.icanhazip.com) | |
ip_file="ip.txt" | |
id_file="cloudflare.ids" | |
log_file="cloudflare.log" | |
# LOGGER | |
log() { | |
if [ "$1" ]; then | |
echo -e "[$(date)] - $1" >> $log_file | |
fi | |
} | |
# SCRIPT START | |
log "Check Initiated" | |
if [ -f $ip_file ]; then | |
old_ip=$(cat $ip_file) | |
if [ $ip == $old_ip ]; then | |
echo "IP has not changed." | |
exit 0 | |
fi | |
fi | |
if [ -f $id_file ] && [ $(wc -l $id_file | cut -d " " -f 1) == 2 ]; then | |
zone_identifier=$(head -1 $id_file) | |
record_identifier=$(tail -1 $id_file) | |
else | |
zone_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$zone_name" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*' | head -1 ) | |
record_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records?name=$record_name" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*') | |
echo "$zone_identifier" > $id_file | |
echo "$record_identifier" >> $id_file | |
fi | |
update=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records/$record_identifier" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" --data "{\"id\":\"$zone_identifier\",\"type\":\"A\",\"name\":\"$record_name\",\"content\":\"$ip\"}") | |
if [[ $update == *"\"success\":false"* ]]; then | |
message="API UPDATE FAILED. DUMPING RESULTS:\n$update" | |
log "$message" | |
echo -e "$message" | |
exit 1 | |
else | |
message="IP changed to: $ip" | |
echo "$ip" > $ip_file | |
log "$message" | |
echo "$message" | |
fi |
This comment has been minimized.
This comment has been minimized.
tomdavidson
commented
Jul 19, 2015
If one is tired of the OSX exceptions (such as not pcre with grep), then one could fix their grep and other cmd tools: |
This comment has been minimized.
This comment has been minimized.
b0bcarlson
commented
Jan 11, 2016
It still appears to work but I am getting |
This comment has been minimized.
This comment has been minimized.
nekoyokoshima
commented
Feb 9, 2016
for anyone(@123isme1) getting
A dirty workaround, but hey, it works! If you want to change to root record of the domain you'll need to set |
This comment has been minimized.
This comment has been minimized.
Gurkengewuerz
commented
Mar 8, 2016
Thank's for sharing! |
This comment has been minimized.
This comment has been minimized.
gstuartj
commented
May 7, 2016
I started modifying this script for my own purposes, then ended up rewriting it. I did, however, use @benkulbertis's grep patterns for parsing the responses, so thanks for the inspiration. My script is POSIX compliant, so it can be used on embedded systems like consumer routers without BASH. I also added more error checking and some other useful actions & ease-of-use stuff. Repo: https://github.com/gstuartj/cf-ddns.sh/ |
This comment has been minimized.
This comment has been minimized.
Noino
commented
Aug 10, 2016
•
Felt like i had to add this starting line 25 if ! [[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
message="Fetched IP does not look valid! Quitting"
log "$message"
echo -e "$message"
exit 1
fi |
This comment has been minimized.
This comment has been minimized.
thordin9
commented
Dec 24, 2016
very useful, thanks for sharing. |
This comment has been minimized.
This comment has been minimized.
Wohlraj
commented
Dec 24, 2016
How about handling IPv6 as well? I can give it a try if not already done |
This comment has been minimized.
This comment has been minimized.
emily-curry
commented
Jan 17, 2017
Thanks for this! |
This comment has been minimized.
This comment has been minimized.
mitchins
commented
Feb 19, 2017
This worked for me, thanks a lot! |
This comment has been minimized.
This comment has been minimized.
PsychoTea
commented
Feb 24, 2017
•
Script is working great for me, bar one small issue. Say I have the domain s.tech. I'm able to update both a.s.tech, www.s.tech, but simply setting s.tech as the record name in hopes of updating s.tech doesn't work. Any ideas? Edit: nevermind, it appears to be working now. Not sure how that happened since I have edited anything though O.o |
This comment has been minimized.
This comment has been minimized.
tmkasun
commented
Apr 8, 2017
Thanks it's working Try deleting |
This comment has been minimized.
This comment has been minimized.
bogdanstoica35
commented
Apr 8, 2017
Thanks for sharing. The script works just fine (I do not need it for DDNS but to change the ip address in the DNS zone with an IP address of my choice). One question though. When the script updates the A record in CF, the cloudflare CF CDN is disabled by default. I need that to be enabled all the time. Any ideea how to do that? |
This comment has been minimized.
This comment has been minimized.
jsarenik
commented
May 8, 2017
Thank you! |
This comment has been minimized.
This comment has been minimized.
Kiendeleo
commented
Jun 15, 2017
I am getting the following result when I run the script: I am attempting to update and A record of a subdomain on an account with multiple domains. Is anyone else getting this error? |
This comment has been minimized.
This comment has been minimized.
ghost
commented
Sep 1, 2017
Bug what if i like to change more records than 1? For example: www smtp irc ftp and more |
This comment has been minimized.
This comment has been minimized.
sandroshu
commented
Sep 17, 2017
@maratmkhitaryan Then why don't you update one and use CNAME for the rest? |
This comment has been minimized.
This comment has been minimized.
danieluramg
commented
Sep 18, 2017
I'm having the same error as @Kiendeleo user above, but only when the script runs on Cron, if I run manually it updates properly. Run on Cron: Manually executing: |
This comment has been minimized.
This comment has been minimized.
beykansen
commented
Nov 28, 2017
•
Added #!/bin/bash
# Created by benkulbertis/cloudflare-update-record.sh
# CHANGE THESE
auth_email="user@example.com"
auth_key="c2547eb745079dac9320b638f5e225cf483cc5cfdda41" # found in cloudflare account settings
zone_name="example.com"
record_name="www.example.com"
# MAYBE CHANGE THESE
ip=$(curl -s http://ipv4.icanhazip.com)
ip_file="ip.txt"
id_file="cloudflare.ids"
log_file="cloudflare.log"
# LOGGER
log() {
if [ "$1" ]; then
echo -e "[$(date)] - $1" >> $log_file
fi
}
# SCRIPT START
log "Check Initiated"
if [ -f $ip_file ]; then
old_ip=$(cat $ip_file)
if [ $ip == $old_ip ]; then
echo "IP has not changed."
exit 0
fi
fi
if [ -f $id_file ] && [ $(wc -l $id_file | cut -d " " -f 1) == 2 ]; then
zone_identifier=$(head -1 $id_file)
record_identifier=$(tail -1 $id_file)
else
zone_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$zone_name" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*' | head -1 )
record_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records?name=$record_name" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*')
echo "$zone_identifier" > $id_file
echo "$record_identifier" >> $id_file
fi
update=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records/$record_identifier" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" --data "{\"id\":\"$zone_identifier\",\"type\":\"A\",\"proxied\":true,\"name\":\"$record_name\",\"content\":\"$ip\"}")
case "$update" in
*"\"success\":false"*)
message="API UPDATE FAILED. DUMPING RESULTS:\n$update"
log "$message"
echo -e "$message"
exit 1;;
*)
message="IP changed to: $ip"
echo "$ip" > $ip_file
log "$message"
echo "$message";;
esac |
This comment has been minimized.
This comment has been minimized.
ptts
commented
Dec 2, 2017
I'm also getting the same error as @Kiendeleo and @danieluramg namely:
These are the files and permissions:
I ran the script with |
This comment has been minimized.
This comment has been minimized.
MachineITSvcs
commented
Jan 1, 2018
Hey, guys. Just published a script I wrote and used in my company to manage my clients' domains on Cloudflare. You can find it here Contact info is availabe on the page as well for those needing assistance with use. |
This comment has been minimized.
This comment has been minimized.
clouddav
commented
Jul 1, 2018
your script is working fine but only for **www.**my-domain.com and it is not updating my-domain.com IP address. |
This comment has been minimized.
This comment has been minimized.
telunc
commented
Jul 3, 2018
•
Any idea how to schedule this script? I'm trying to use crontab, but data isn't logging in cloudflare.log.
|
This comment has been minimized.
This comment has been minimized.
lifehome
commented
Jul 6, 2018
•
I have tuned the script a bit so no files will be created, also created some systemd unit for automation. See my version at: https://gist.github.com/lifehome/eb3f7d798f9bc6720cdc7d2be1238d4f |
This comment has been minimized.
This comment has been minimized.
channprj
commented
Aug 13, 2018
Good Idea! |
This comment has been minimized.
This comment has been minimized.
4ft35t
commented
Sep 20, 2018
mod for openwrt, grep of busybox doesn't support -P option |
This comment has been minimized.
This comment has been minimized.
boypt
commented
Dec 5, 2018
I have my version of updating IPv6 address for AAAA record: |
This comment has been minimized.
This comment has been minimized.
vircloud
commented
Dec 20, 2018
Line 27, will report an error on some platforms,like
change to:
fix that. |
This comment has been minimized.
This comment has been minimized.
minhazulOO7
commented
Jan 4, 2019
THANKS MAN! Was looking for this! |
This comment has been minimized.
This comment has been minimized.
fire1ce
commented
Jan 15, 2019
If you want to use the script from crontab without problems add this: the PATH with use the system bash's environment variables |
This comment has been minimized.
This comment has been minimized.
fire1ce
commented
Jan 15, 2019
if you want to use the script to update local ip, change ip variable to: |
This comment has been minimized.
This comment has been minimized.
minhazulOO7
commented
May 6, 2019
•
Thanks @benkulbertis! I edited and made this gist. Hope it helps somebody. |
This comment has been minimized.
This comment has been minimized.
nunesgh
commented
May 31, 2019
For those having the same issue as @ptts, @Kiendeleo, and @danieluramg, consider checking if the auth_key parameter you have set is indeed your Cloudflare API Key. You can find your Cloudflare API Key going to My Profile, which is located under the menu at the top right of the Cloudflare Dashboard. Once there, scroll down to API Keys and locate Global API Key. Click View, enter your password, and you will have access to your API Key. |
This comment has been minimized.
This comment has been minimized.
HillLiu
commented
Jun 19, 2019
another clue was make sure the record_name already exits in your zone, when this script purpose was update.
|
This comment has been minimized.
This comment has been minimized.
HillLiu
commented
Jun 19, 2019
Thanks this gist. I also add more feature such as
if someone interested, check out my version |
This comment has been minimized.
This comment has been minimized.
danfraser007
commented
Jun 29, 2019
•
@ptts, @Kiendeleo, and @danieluramg If you are getting the error "Could not route to /zones/dns_records, perhaps your object identifier is invalid?" .....try deleting the log file filecloudflare.ids . For some reason when I first ran the script it didnt populate the file. This may of been because I had an invalid API key. However it still created the file, but it was just empty. So the script would not run when I re-ran it. Anyway, I deleted the empty file. Re-ran the script and now it works. To the dev, maybe its worth deleting the file once it has been used? or checking to see if the file is empty? |
This comment has been minimized.
This comment has been minimized.
DTM450
commented
Jul 24, 2019
•
If you are using this on a Raspberry Pi make sure to use |
This comment has been minimized.
This comment has been minimized.
samywee
commented
Sep 2, 2019
Thank you worked! perfectly. Make sure run under bash. |
This comment has been minimized.
This comment has been minimized.
issess
commented
Oct 7, 2019
•
I updated API_TOKEN version like this : #!/bin/bash
# Created by benkulbertis/cloudflare-update-record.sh
# CHANGE THESE
api_token="c2547eb745079dac9320b638f5e225cf483cc5cfdda41" # found in cloudflare account my profile - API Tokens - (Permission Zone.Zone, Zone.DNS)
zone_name="example.com"
record_name="www.example.com"
proxied="true"
# MAYBE CHANGE THESE
ip=$(curl -s http://ipv4.icanhazip.com)
ip_file="ip.txt"
id_file="cloudflare.ids"
log_file="cloudflare.log"
# LOGGER
log() {
if [ "$1" ]; then
echo -e "[$(date)] - $1" >> $log_file
fi
}
# SCRIPT START
log "Check Initiated"
if ! [[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
message="Fetched IP does not look valid! Quitting"
log "$message"
echo -e "$message"
exit 1
fi
if [ -f $ip_file ]; then
old_ip=$(cat $ip_file)
if [ $ip == $old_ip ]; then
echo "IP has not changed."
exit 0
fi
fi
if [ -f $id_file ] && [ $(wc -l $id_file | cut -d " " -f 1) == 2 ]; then
zone_identifier=$(head -1 $id_file)
record_identifier=$(tail -1 $id_file)
else
zone_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$zone_name" -H "Authorization: Bearer $api_token" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*' | head -1 )
record_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records?name=$record_name" -H "Authorization: Bearer $api_token" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*')
echo "$zone_identifier" > $id_file
echo "$record_identifier" >> $id_file
fi
echo "zone : $zone_identifier"
echo "record : $record_identifier"
update=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records/$record_identifier" -H "Authorization: Bearer $api_token" -H "Content-Type: application/json" --data "{\"id\":\"$zone_identifier\",\"type\":\"A\",\"proxied\":\"$proxied\",\"name\":\"$record_name\",\"content\":\"$ip\"}")
case "$update" in
*"\"success\":false"*)
message="API UPDATE FAILED. DUMPING RESULTS:\n$update"
log "$message"
echo -e "$message"
exit 1;;
*)
message="IP changed to: $ip"
echo "$ip" > $ip_file
log "$message"
echo "$message";;
esac |
This comment has been minimized.
This comment has been minimized.
DaveSanders
commented
Nov 8, 2019
I had to change the "update" line to remove the quotes around "$proxied". Cloudflare expects that json value to be a boolean:
|
This comment has been minimized.
rasmusbe commentedMay 12, 2015
Thanks for your code!
Since grep -P isn't available on mac I made an alternative version for mac (will probably work for linux as well)
https://gist.github.com/rasmusbe/fc2e270095f1a3b41348