-
-
Save Firsh/c9f72970eaae3aec04beb1106cc304bc to your computer and use it in GitHub Desktop.
#!/bin/bash | |
# Cloudflare as Dynamic DNS | |
# From: https://letswp.io/cloudflare-as-dynamic-dns-raspberry-pi/ | |
# Based on: https://gist.github.com/benkulbertis/fff10759c2391b6618dd/ | |
# Original non-RPi article: https://phillymesh.net/2016/02/23/setting-up-dynamic-dns-for-your-registered-domain-through-cloudflare/ | |
# Update these with real values | |
auth_email="[email protected]" | |
auth_key="global_api_key_goes_here" | |
zone_name="example.com" | |
record_name="home.example.com" | |
# Don't touch these | |
ip=$(curl -s http://ipv4.icanhazip.com) | |
ip_file="ip.txt" | |
id_file="cloudflare.ids" | |
log_file="cloudflare.log" | |
# Keep files in the same folder when run from cron | |
current="$(pwd)" | |
cd "$(dirname "$(readlink -f "$0")")" | |
log() { | |
if [ "$1" ]; then | |
echo -e "[$(date)] - $1" >> $log_file | |
fi | |
} | |
log "Check Initiated" | |
if [ -f $ip_file ]; then | |
old_ip=$(cat $ip_file) | |
if [ $ip == $old_ip ]; then | |
log "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 happens
lwp-cloudflare-dyndns.sh: 33: [: ipaddress: unexpected operator
lwp-cloudflare-dyndns.sh: 39: [: 2: unexpected operator
lwp-cloudflare-dyndns.sh: 51: lwp-cloudflare-dyndns.sh: [[: not found
IP changed to: ipaddressI changed my real ip for ipaddress
This is most likely due to running as an SH vs BASH command. Try running like so: "bash lwp-cloudflare-dyndns.sh".
Works great on RPi with buster. Thanks!
FWIW, getting the same error
{"success":false,"errors":[{"code":7001,"message":"Method PUT not available for that URI."}],"messages":[],"result":null}
No idea how to fix it yet. Would appreciate it if someone could point out how to do so...
Getting:
API UPDATE FAILED. DUMPING RESULTS:
{"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}
Any idea? It is an account with multiple domains.
Managed to get it to work:
https://gist.github.com/heygambo/6a6180d62469002297b2ec63406b7d37
- Updated it to work with Cloudflare API tokens that can be limited.
- Fixed id parsing for the identifiers
For whoever's interested in using API Tokens instead of API Keys (which makes it possible to fine-tune the access rights of a given API Token) the headers of the GET and PUT requests sent using curl
can be changed as follows:
delete X-Auth-Email:
and X-Auth-Key:
add Authorization: Bearer <your API Token>
Only permission necessary for the API Token is Zone.DNS in my experience
I am really confused. I am trying to get this script running on a raspberry pi4 running raspbian buster. And when I try to execute lwp-cloudflare-dyndns.sh with the bash command I get:
lwp-cloudflare-dyndns.sh: line 6: $'\r': command not found
lwp-cloudflare-dyndns.sh: line 20: $'\r': command not found
lwp-cloudflare-dyndns.sh: line 25: $'\r': command not found
lwp-cloudflare-dyndns.sh: line 31: $'\r': command not found
lwp-cloudflare-dyndns.sh: line 34: cd: $'/home/pi\r': No such file or directory
lwp-cloudflare-dyndns.sh: line 35: $'\r': command not found
lwp-cloudflare-dyndns.sh: line 36: syntax error near unexpected token $'{\r'' 'wp-cloudflare-dyndns.sh: line 36:
log() {
What is going on? Where is it reading the \r into the tokens?
I did not change anything except of changing the domain and login data..
Seems to be the way newlines were handled on your system, that may or may not be because of how you copied or downloaded the source. \r is a carriage return or new line character.
Thank you @Firsh, works great!
As @giovanniferretti suggested, I changed out the email/key for the token. I'm getting a "sh: not: unknown operand" error followed by "IP changed to: [my ip]"
Any suggestions?
`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
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","name":"$record_name","content":"$ip"}")`
I've now switched to using this docker container:
version: "3"
services:
cloudflare-ddns:
image: oznu/cloudflare-ddns:latest
restart: unless-stopped
environment:
- API_KEY=<cloudflare-api-key>
- ZONE=example.com
- SUBDOMAIN=subdomain
- PROXIED=true
is it possible to use it without a subdomain?
I don't see why not.
If anyone is experiencing issues when trying to use this to update the primary A record for a domain, which may have other records associated with the same record_name, for example MX records, I suggest making the following modification:
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":")[^"]*')
Change to
record_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records?name=$record_name&page=1&per_page=1" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*')
I discovered the issue by checking the .ids file and found 5 rows, when there should have only been 2 rows. By limiting to page=1 and per_page=1 it only returns the primary A record, and not MX records.
Nice, yeah that makes sense to receive a paged list of records if someone has a busy domain and the missing the one you wanted.
No working for me from a Raspberry Pi.
First attempts kept getting a URI error.
~/cf $ sudo ./lwp-cloudflare-dyndns.sh API UPDATE FAILED. DUMPING RESULTS: {"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}
After self populating zone_identifier and record_identifier I get this error:
API UPDATE FAILED. DUMPING RESULTS: {"success":false,"errors":[{"code":7001,"message":"Method PUT not available for that URI."}],"messages":[],"result":null}
Same result when I used a custom API token just for this script:
./lwp-cloudflare-dyndns.sh API UPDATE FAILED. DUMPING RESULTS: {"success":false,"errors":[{"code":7001,"message":"Method PUT not available for that URI."}],"messages":[],"result":null}
Not sure what old me had issues with, but just did this again and it worked. I don't even remember posting that comment. Blimey.
So thanks! (that docker version looks nice too)
Not sure what old me had issues with, but just did this again and it worked. I don't even remember posting that comment. Blimey.
I still use the script to this day, still on RPI, and it works fine. The only thing that will break it is when Cloudflare changes their API, to which we could react.
@tarasis I wish i could talk to 'old you' because i am getting that same error. as you.
Getting: API UPDATE FAILED. DUMPING RESULTS: {"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}
Any idea? It is an account with multiple domains.
Hiya... did you ever get this to work?
Hi, it still works fine for me. From the docs: https://api.cloudflare.com/#accounts-update-account It tells us to use PUT, and these permissions are required: #organization:edit not sure where those are set though.