Skip to content

Instantly share code, notes, and snippets.

@zoonderkins
Last active June 14, 2022 06:00
Show Gist options
  • Save zoonderkins/321a02aba98c5863b3f95ae3beeb0c45 to your computer and use it in GitHub Desktop.
Save zoonderkins/321a02aba98c5863b3f95ae3beeb0c45 to your computer and use it in GitHub Desktop.
Ddns with Cloudflare DNS #linux

Use case

  1. VPS has dynamic IP which changed few times a week or month.
  2. Self-hosted NAS or homelab which use dynamic IP from ISP.

Setup and config

  1. Download script below and assign excuatable permission
wget https://gist.githubusercontent.com/ookangzheng/321a02aba98c5863b3f95ae3beeb0c45/raw/update-cloudflare.sh && chmod +x update-cloudflare.sh
  1. Config your Cloudflare API Token, Zone ID, DNS A record name
  2. Test it
  3. Final, setup cron job every 5 minitues

Cron tab

*/5 * * * * root /root/update-cloudflare.sh

Origin source

Credit from: https://3os.org/automation/ddns-cloudflare-bash
License: MIT Copyright@ 3os.org
## Which IP should be used for the record: internal/external
## Internal interface will be chosen automaticly as a primary default interface
what_ip="external"
## DNS A record to be updated
dns_record="hello.world.mom"
## Cloudflare's Zone ID
zoneid="asdfasdfasdf"
## Api token can be generated from here
## https://dash.cloudflare.com/profile/api-tokens
## Cloudflare Zone API Token
cloudflare_zone_api_token="asdf1234567890"
## Use Cloudflare proxy on dns record true/false
proxied="false"
## 60-300 in seconds or 1 for Aut
ttl=60
## Telegram Notifications yes/no (only sent if DNS is updated)
notify_me_telegram="no"
## Telegram Chat ID
telegram_chat_id="ChangeMe"
## Telegram Bot API Key
telegram_bot_API_Token="ChangeMe"
#!/usr/bin/env bash
### Last update: 2022-06-14
### Credit from: https://3os.org/automation/ddns-cloudflare-bash
### License: MIT Copyright@ 3os.org
### Create .update-cloudflare-dns.log file of the last run for debug
parent_path="$(dirname "${BASH_SOURCE[0]}")"
FILE=${parent_path}/update-cloudflare-dns.log
if ! [ -x "$FILE" ]; then
touch "$FILE"
fi
LOG_FILE=${parent_path}'/update-cloudflare-dns.log'
### Write last run of STDOUT & STDERR as log file and prints to screen
exec > >(tee $LOG_FILE) 2>&1
echo "==> $(date "+%Y-%m-%d %H:%M:%S")"
### Validate if config file exists
if ! source ${parent_path}/update-cloudflare-dns.conf; then
echo 'Error! Missing "update-cloudflare-dns.conf or invalid syntax"!'
exit 0
fi
### Check validity of "ttl" parameter
if [ "${ttl}" -lt 60 ] || [ "${ttl}" -gt 300 ] && [ "${ttl}" -ne 1 ]; then
echo "Error! ttl out of range (60-300) or not set to 1"
exit
fi
## Get external IP
if [ "${what_ip}" == "external" ]; then
ip=$(curl -s -X GET https://ipinfo.tw/ip --max-time 10)
if [ -z "$ip" ]; then
echo "Error! Can't get external ip from https://ipinfo.tw/ip"
exit 0
fi
echo "==> External IP is: $ip"
fi
echo "==> DNS record of ${dns_record} is: ${dns_record_ip}. Trying to update..."
### Get the dns record information from cloudflare's api
cloudflare_record_info=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records?name=$dns_record" \
-H "Authorization: Bearer $cloudflare_zone_api_token" \
-H "Content-Type: application/json")
if [[ ${cloudflare_record_info} == *"\"success\":false"* ]]; then
echo ${cloudflare_record_info}
echo "Error! Can't get ${dns_record} record inforamiton from cloudflare API"
exit 0
fi
### Get the dns record id from response
cloudflare_dns_record_id=$(echo ${cloudflare_record_info} | grep -o '"id":"[^"]*' | cut -d'"' -f4)
### Push new dns record information to cloudflare's api
update_dns_record=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records/$cloudflare_dns_record_id" \
-H "Authorization: Bearer $cloudflare_zone_api_token" \
-H "Content-Type: application/json" \
--data "{\"type\":\"A\",\"name\":\"$dns_record\",\"content\":\"$ip\",\"ttl\":$ttl,\"proxied\":$proxied}")
if [[ ${update_dns_record} == *"\"success\":false"* ]]; then
echo ${update_dns_record}
echo "Error! Update Failed"
exit 0
fi
echo "==> Success!"
echo "==> $dns_record DNS Record Updated To: $ip, ttl: $ttl, proxied: $proxied"
### Telegram notification
if [ ${notify_me_telegram} == "no" ]; then
exit 0
fi
if [ ${notify_me_telegram} == "yes" ]; then
telegram_notification=$(
curl -s -X GET "https://api.telegram.org/bot${telegram_bot_API_Token}/sendMessage?chat_id=${telegram_chat_id}" --data-urlencode "text=${>
)
if [[ ${telegram_notification=} == *"\"ok\":false"* ]]; then
echo ${telegram_notification=}
echo "Error! Telegram notification failed"
exit 0
fi
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment