[Bash Script] Update a Cloudflare DNS Record with a Dynamic IPv4 Address
Nghia Phan
Table of Contents
This script checks your current public IP and quickly updates the corresponding Cloudflare DNS records.
cloudflare_dynamic_ip_update.bash
#!/usr/bin/env bash## Author: Hyecheol (Jerry) Jang## Shell Script that checks the current public (dynamic) IP address of a server## and updates the Cloudflare DNS record after comparing it with the registered address.## Basic shell scripting guide: https://blog.gaerae.com/2015/01/bash-hello-world.html## Use dig (https://en.wikipedia.org/wiki/Dig_(command)) to get the current public IP address.currentIP=$(dig -4 TXT +short o-o.myaddr.1.google.com @ns1.google.com)if [ $? == 0 ] && [ ${currentIP} ]; then ## when dig runs without an error, ## Keep only the IP address from the response. ## https://stackabuse.com/substrings-in-bash/ currentIP=$(echo $currentIP | cut -d'"' -f 2) echo "current public IP address is "$currentIPelse ## an error occurred, echo "Check your internet connection, or the Google DNS server may be interrupted." exitfi## Use the Cloudflare API to retrieve the existing record IP.## https://api.cloudflare.com/## Read configuration from a separate cloudflare_config file in the same directory.## https://stackoverflow.com/questions/10929453/read-a-file-line-by-line-assigning-the-value-to-a-variable## https://stackoverflow.com/questions/10586153/split-string-into-an-array-in-bashSCRIPT_PATH=$(dirname $(realpath $0))readResult="" ## Store configuration.while IFS= read -r line || [[ -n "$line" ]]; do readResult+=" " ## Delimiter: space. readResult+="$line"done < $SCRIPT_PATH"/cloudflare_config" ## Use cloudflare_config.unset IFSunset SCRIPT_PATH## Split the configuration string into its elements.key=$(echo $(echo $readResult | cut -d' ' -f 1) | cut -d'=' -f 2)email=$(echo $(echo $readResult | cut -d' ' -f 2) | cut -d'=' -f 2)zoneID=$(echo $(echo $readResult | cut -d' ' -f 3) | cut -d'=' -f 2)IFS=',' read -r -a updateTarget <<< "$(echo $(echo $readResult | cut -d' ' -f 4) | cut -d'=' -f 2)"unset readResultunset IFS## Allocate arrays for record IP addresses, types, and names.declare -a recordIPdeclare -a recordTypedeclare -a recordNamedeclare -a dnsIDdeclare -a recordProxiedfor string in ${updateTarget[@]}; do ## Retrieve each record's IP address. content=$( curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zoneID/dns_records?name=${string}" \ -H "X-Auth-Email: $email" \ -H "X-Auth-Key: $key" \ -H "Content-Type: application/json" ) ## Parse JSON with jq. ## https://stackoverflow.com/questions/42427371/cloudflare-api-cut-json-response ## https://stedolan.github.io/jq/ ip=$(echo $content | jq '.result | map(.content) | add' | cut -d'"' -f 2) rType=$(echo $content | jq '.result | map(.type) | add' | cut -d'"' -f 2) name=$(echo $content | jq '.result | map(.name) | add' | cut -d'"' -f 2) id=$(echo $content | jq '.result | map(.id) | add' | cut -d'"' -f 2) proxied=$(echo $content | jq '.result | map(.proxied) | add' | cut -d'"' -f 2) recordIP=(${recordIP[@]} $ip) recordType=(${recordType[@]} $rType) recordName=(${recordName[@]} $name) dnsID=(${dnsID[@]} $id) recordProxied=(${recordProxied[@]} $proxied) unset id unset rType unset name unset ip unset content unset string unset proxieddoneunset updateTarget## Compare currentIP with each recordIP.declare -a needUpdate ## Store whether each record needs updating.for string in ${recordIP[@]}; do if [ ${string} == ${currentIP} ]; then needUpdate=(${needUpdate[@]} 'False') else needUpdate=(${needUpdate[@]} 'True') fi unset stringdoneunset recordIP ## No longer needed.## Update records that need it.count=0while [ $count -lt ${#needUpdate[@]} ]; do if [ ${needUpdate[count]} == 'True' ]; then echo "record IP needs to be updated for "${recordName[count]} success=$( curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zoneID/dns_records/${dnsID[count]}" \ -H "X-Auth-Email: $email" \ -H "X-Auth-Key: $key" \ -H "Content-Type: application/json" \ --data '{"type":"'"${recordType[count]}"'","name":"'"${recordName[count]}"'","content":"'"$currentIP"'","proxied":'${recordProxied[count]}'}' | \ jq '.success' | cut -d'"' -f 2 ) if [ $success == true ]; then echo "Success: updated the record IP of "${recordName[count]} else echo "Failed to update the record IP of "${recordName[count]}"\n""Please check the result." fi else echo "record IP does not need to be updated for "${recordName[count]} fi count=$((${count}+1))doneunset countunset currentIPunset keyunset emailunset zoneIDunset recordTypeunset recordNameunset dnsIDunset recordProxiedunset needUpdate
cloudflare_config
Auth-Key=[Global API Key]Auth-Email=[Login Mail]Zone-ID=[Zone ID]Update-Target=subdomain.router.io.vn
Credit: Hyecheol (Jerry) Jang
📎 Attachments
2 files - 📄Downloadcloudflare_config104 B • 0 downloads
- 📄Downloadcloudflare_dynamic_ip_update.bash4.8 KB • 0 downloads
Comments & Discussion
Share your thoughts, ask questions and feedback