-
-
Save lyoshenka/6257440 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash | |
# Step 1: Fill in EMAIL, TOKEN, DOMAIN and SUBDOMAIN. Your API token is here: https://dash.cloudflare.com/profile/api-tokens | |
# Make sure the token is the Global token, or has these permissions: #zone:read, #dns_record:read, #dns_records:edit | |
# If you want to set the root domain instead of a subdomain, set SUBDOMAIN to "@" | |
# Step 2: Create an A record on Cloudflare with the subdomain you chose | |
# Step 3: Run "./ddns.sh -l" to get the zone_id and rec_id of the record you created. | |
# Fill in ZONE_ID and REC_ID below | |
# This step is optional, but will save you 2 requests every time you run this script | |
# Step 4: Run "./ddns.sh". It should tell you that record was updated or that it didn't need updating. | |
# Step 5: Run it every hour with cron. Use the '-s' flag to silence normal output | |
# 0 * * * * /path/to/ddns.sh -s | |
EMAIL='' | |
TOKEN='' | |
DOMAIN='' | |
SUBDOMAIN='' | |
ZONE_ID='' | |
REC_ID='' | |
set -euo pipefail | |
VERBOSE="true" | |
LOOKUP="false" | |
while getopts ":lsd" opt; do | |
case ${opt} in | |
l ) LOOKUP="true" ;; | |
s ) VERBOSE="false" ;; | |
d ) set -x ;; # for debugging | |
\? ) echo -e "Usage: $(basename "$0") [-l] [-s] [-d]\nRead the script source for detailed instructions" && exit 1 ;; | |
esac | |
done | |
[[ "$SUBDOMAIN" = "@" ]] && FULL_DOMAIN="$DOMAIN" || FULL_DOMAIN="$SUBDOMAIN.$DOMAIN" | |
API_URL="https://api.cloudflare.com/client/v4" | |
CURL="curl -s \ | |
-H Content-Type:application/json \ | |
-H X-Auth-Key:$TOKEN \ | |
-H X-Auth-Email:$EMAIL " | |
if [ -z "$ZONE_ID" ] || $LOOKUP; then | |
ZONE_ID="$($CURL "$API_URL/zones?name=$DOMAIN" | sed -e 's/[{}]/\n/g' | grep '"name":"'"$DOMAIN"'"' | sed -e 's/,/\n/g' | grep '"id":"' | cut -d'"' -f4)" | |
$VERBOSE && echo "ZONE_ID='$ZONE_ID'" | |
fi | |
if [ -z "$REC_ID" ] || $LOOKUP; then | |
#REC_ID="$($CURL "$API_URL/zones/$ZONE_ID/dns_records" | grep -C 5 '"name": "'"$FULL_DOMAIN"'"' | grep '"id": "' | cut -d'"' -f4)" | |
REC_ID="$($CURL "$API_URL/zones/$ZONE_ID/dns_records" | sed -e 's/[{}]/\n/g' | grep '"name":"'"$FULL_DOMAIN"'"' | sed -e 's/,/\n/g' | grep '"id":"' | cut -d'"' -f4)" | |
$VERBOSE && echo "REC_ID='$REC_ID'" | |
fi | |
$LOOKUP && exit 0 | |
set +e | |
for IP_URL in "http://ifconfig.me/ip" "http://ipv4.icanhazip.com"; do | |
IP="$(curl -s "$IP_URL")" | |
[ -n "$IP" ] && break | |
done | |
set -e | |
if [ -z "$IP" ]; then | |
echo "Could not get external IP" | |
exit 1 | |
fi | |
RECORD_IP="$($CURL "$API_URL/zones/$ZONE_ID/dns_records/$REC_ID" | grep -o '"content":"[^"]\+' | cut -d '"' -f4)" | |
if [ "$IP" == "$RECORD_IP" ]; then | |
$VERBOSE && echo "IP Unchanged" | |
exit 0 | |
fi | |
$VERBOSE && echo "Setting IP to $IP" | |
$CURL -X PUT "$API_URL/zones/$ZONE_ID/dns_records/$REC_ID" --data '{"type":"A","name":"'"$SUBDOMAIN"'","content":"'"$IP"'","proxied":false}' 1>/dev/null | |
exit 0 |
@davidcastellani just updated it. give it a try and let me know if you see any issues
How would you change a wildcard record or the root domain? What would you set in the subdomain variable for those records? I tried putting in * and (mydomain).net and it does not work. @lyoshenka
Have you found any solution? Still looking for a fix...
For anyone interested, I wrote a similar script in bash for use with multiple Cloudflare accounts, zones, records, and a proxy option: here
reaplace L42
REC_ID="$($CURL "$API_URL/zones/$ZONE_ID/dns_records?name=$SUBDOMAIN" | awk '{t=$0;gsub(/.*"id":"|".*/,"",t);print t}')"
replace l37
ZONE_ID="$($CURL "$API_URL/zones?name=$DOMAIN" | jq '.result[0].id'
@waiyanwh that works but i'd like to avoid dependence on extra things like jq
cloudflare has changed its response format, so this line
| sed -e 's/[{}]/\n/g' | grep '"name":"'"$SUBDOMAIN"'.'"$DOMAIN"'"' | sed -e 's/,/\n/g' | grep '"id": "' | cut -d'"' -f4
doesn't work now.
REC_ID needs to be manually set. (you can get your id by uncomment the -x in the ddns.sh script, then manually curl request the dns_records path
as given by the debug info )
Thanks @frankang. I updated the grep commands so it finds the correct record. Should work now
Wondering the same as Agazed did years ago. Is it at all possible to set the root domain using this script?
@ImmortalScientist @Agazed - I just updated the script to support root domains. Set SUBDOMAIN
to @
and give it a try. Let me know if that doesn't work for you.
Hi, i'm trying to get it working with monit but unfortunatelly looks like monit doesn't run the script btw when i run it myself everything works.
Do you have any idea ?
Perhaps there is my command on monit
check host xxxxxx with address xxxxxx
if failed ping4 then exec "/bin/bash -c /etc/monit/SecondaryIP.sh"
else if succeeded then exec "/bin/bash -c /etc/monit/NativeIP.sh"
@lyoshenka , Cloudflare is deprecating API v1 in favor of v4.
Email I received just this morning.
They then link to https://www.cloudflare.com/migrating-to-v4/
Any chance you would convert this script to API v4?