-
-
Save benkulbertis/fff10759c2391b6618dd to your computer and use it in GitHub Desktop.
#!/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 |
mod for openwrt, grep of busybox doesn't support -P option
https://gist.github.com/4ft35t/510897486bc6986d19cac45b3b9ca1d0
I have my version of updating IPv6 address for AAAA record:
https://gist.github.com/pentie/4827058990343db9a5eede346d76ba0f
Line 27, will report an error on some platforms,like
[: too many arguments
change to:
if [ "$ip" == "$old_ip" ]; then
fix that.
THANKS MAN! Was looking for this! 😃
If you want to use the script from crontab without problems add this:
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
cd "$(dirname "$0")"
the PATH with use the system bash's environment variables
the CD commands with change the directory to the script's. so all the commands will be executed with that folder.
This will solve the problem when executing the script with crontab so it will be able to write and read the files like:
"ip.txt"
"cloudflare.ids"
"cloudflare.log"
if you want to use the script to update local ip, change ip variable to:
ip=$(ifconfig | grep -Eo 'inet (addr:)?([0-9].){3}[0-9]' | grep -Eo '([0-9].){3}[0-9]' | grep -v '127.0.0.1')
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.
another clue was make sure the record_name already exits in your zone, when this script purpose was update.
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.
Thanks this gist.
I also add more feature such as
- env file
- debug mode.
- replace grep to sed that it also work on MacOS.
if someone interested, check out my version
https://github.com/HillLiu/cloudflare-bash-util
I'm also getting the same error as @Kiendeleo and @danieluramg namely:
{ "success":false, "errors":[ { "code":7003, "message":"Could not route to \/zones\/dns_records, perhaps your object identifier is invalid?" }, { "code":7000, "message":"No route for that URI" } ], "messages":[ ], "result":null }
These are the files and permissions:
drwxr-xr-x 2 ptts ptts 4096 Dec 2 16:17 . drwxr-xr-x 5 ptts ptts 4096 Dec 2 16:11 .. -rw-r--r-- 1 ptts ptts 2 Dec 2 16:13 cloudflare.ids -rw-r--r-- 1 ptts ptts 666 Dec 2 16:15 cloudflare.log -rw-rw-rw- 1 ptts ptts 1928 Dec 2 16:15 cloudflare-update-record.sh
I ran the script with
bash cloudflare-update-record.sh
andsudo bash cloudflare-update-record.sh
, both yield the same result.
Any suggestions? Thanks!
@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?
If you are using this on a Raspberry Pi make sure to use bash
not sh
and to remove the spacing at line 36 before the "fi"
Thank you worked! perfectly. Make sure run under bash.
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
I had to change the "update" line to remove the quotes around "$proxied". Cloudflare expects that json value to be a boolean:
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\"}")
I am getting the following result when I run the script:
{"success":false,"errors":[{"code":7003,"message":"Could not route to \/zones\/dns_records, perhaps your object identifier is invalid?"},{"code":7000,"message":"No route for that URI"}],"messages":[],"result":null}
I am attempting to update and A record of a subdomain on an account with multiple domains. Is anyone else getting this error?
I have the same issue, also in an account with multiple domains. No solution on this thread worked so far.
Thank you for the script saved me lots of time. Tweaked to add DNS Record instead of updating. I did not add a check to see if the record already exist.
...
if [ -f
zone_identifier=$(head -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 )
echo "$zone_identifier" > $id_file
fi
addDns=$(curl -X POST "https://api.cloudflare.com/client/v4/zones/${zone_identifier}/dns_records" -H "X-Auth-Email: ${auth_email}" -H "X-Auth-Key: ${auth_key}" -H "Content-Type: application/json" --data '{"type":"A","name":"'${record_name}'","content":"'${ip}'","ttl":120,"priority":10,"proxied":true}')
if [[ $addDns == ""success":false" ]]; then
message="API UPDATE FAILED. DUMPING RESULTS:\n$addDns"
log "$message"
echo -e "$message"
exit 1
else
message="IP changed to: $ip"
echo "$ip" > $ip_file
log "$message"
echo "$message"
fi
just a heads up everyone, apparently Cloudflare made a few changes to their API and I found out the hards way today (bit of a downtime). All you need to do is to add a space character (
) in every regex when parsing a field.
specifically:
if [[ $record == *"\"count\":0"* ]]; then
needs to become
if [[ $record == *"\"count\": 0"* ]]; then
old_ip=$(echo "$record" | grep -Po '(?<="content":")[^"]*' | head -1)
to
old_ip=$(echo "$record" | grep -Po '(?<="content": ")[^"]*' | head -1)
*"\"success\":false"*)
has to become
*"\"success\": false"*)
Thanks @mrwhizzy
I also update my sed sample here.
HillLiu/cloudflare-bash-util@304d58e
just a heads up everyone, apparently Cloudflare made a few changes to their API and I found out the hards way today (bit of a downtime). All you need to do is to add a space character (
) in every regex when parsing a field.
specifically:
if [[ $record == *"\"count\":0"* ]]; then
needs to become
if [[ $record == *"\"count\": 0"* ]]; then
old_ip=$(echo "$record" | grep -Po '(?<="content":")[^"]*' | head -1)
to
old_ip=$(echo "$record" | grep -Po '(?<="content": ")[^"]*' | head -1)
*"\"success\":false"*)
has to become
*"\"success\": false"*)
just a heads up everyone, apparently Cloudflare made a few changes to their API and I found out the hards way today (bit of a downtime). All you need to do is to add a space character (
) in every regex when parsing a field.
specifically:
if [[ $record == *"\"count\":0"* ]]; then
needs to become
if [[ $record == *"\"count\": 0"* ]]; then
old_ip=$(echo "$record" | grep -Po '(?<="content":")[^"]*' | head -1)
to
old_ip=$(echo "$record" | grep -Po '(?<="content": ")[^"]*' | head -1)
*"\"success\":false"*)
has to become
*"\"success\": false"*)
Updated my scripts but still doesn't seem to work.
Anyone got it working again?
grep -Po '(?<="id":")[^"]*')
change to
grep -Po '(?<="id": ")[^"]*')
Why Cloudflare why do you do these things.
Thanks for the update
tx guys for the update, was wondering what was going on !
Did they change something again? Scripts no longer seem to work..
@niklasmato, yes they did, I've uploaded an up-to-date version of the script on GitHub which will work a bit more reliably no matter if they have spaces after semicolons or not, plus it will also update multiple records.
@niklasmato, yes they did, I've uploaded an up-to-date version of the script on GitHub which will work a bit more reliably no matter if they have spaces after semicolons or not, plus it will also update multiple records.
Thank you for this!
#!/bin/sh
#modify by: John Chen
# CHANGE THESE
zone_identifier="your_zone_id"
record_identifier="Your_record_iid"
auth_key="Your_auth_keys" # 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
else if [$ip == ""]; then
echo "Timeout! "
fi
fi
update=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records/$record_identifier" -H "Authorization: Bearer $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
change -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key"
to -H "Authorization: Bearer $auth_key"
and
change use sed to instead of grep to parse json data
like
sed -E "s/.+\{\"id\":\"([a-f0-9]+)\".+\"type\":\"A\".+/\1/g"
and
if [ -f $id_file ] && [ -n $(sed -n '1p' $id_file) ] && [ -n $(sed -n '2p' $id_file) ]; then
and
success=$( echo $update | sed -E "s/.+\"success\":[ ]*([a-z]+).+/\1/g")
if [[ $success == "false" ]]; then
message="API UPDATE FAILED. DUMPING RESULTS:\n$update"
log "$message"
echo -e "$message"
exit 1
else
check here
Hi all,
Previously I have posted a bash/systemd version fork of this script in another gist, I have moved and updated the script to an actual repository, please kindly visit it instead at: https://github.com/lifehome/systemd-cfddns
Regards,
Ivan
Good Idea! 👍