restore repo

This commit is contained in:
FranSisco 2024-11-18 22:38:28 +01:00
parent 729dcdeed3
commit ea0fb8af02
4 changed files with 327 additions and 2 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
cloudflare-dns-update_test.conf
cloudflare-dns-update.log

142
README.md
View file

@ -1,3 +1,141 @@
# Cloudflare-DDNS-Script
# cloudflare DDNS Script
Cloudflare-DDNS-script is a Bash script that automatically updates Cloudflare DNS records with your current external IP address. It supports both IPv4 and IPv6, and can update multiple domains simultaneously. This script is particularly useful for any user who has a dynamic IP address and wants to keep their Cloudflare DNS records up to date without having an additional DDNS provider.
cloudflare-DDNS-script is a Bash script that automatically updates Cloudflare DNS records with your current external IP address. It supports both IPv4 and IPv6, and can update multiple domains simultaneously. This script is particularly useful for any user who has a dynamic IP address and wants to keep their Cloudflare DNS records up to date without having an additional DDNS provider.
## Features
- Updates both A (IPv4) and AAAA (IPv6) records
- Supports multiple domains
- Uses multiple sources to reliably fetch public IP addresses
- Configurable Time To Live (TTL) and proxy settings
- Optional Telegram notifications for successful updates
- Detailed logging for easy troubleshooting (including API responses)
## Prerequisites
- Bash shell
- `curl` command-line tool
- A Cloudflare account with the domain(s) you want to update
- Cloudflare API token with the necessary permissions
## Installation
1. Clone this repository:
```bash
git clone https://github.com/Ate329/cloudflare-DDNS-script.git
cd cloudflare-DDNS-script
```
2. Make the script executable:
```bash
chmod +x cloudflare-dns-update.sh
```
3. Change the configurations in the configuration file named `cloudflare-dns-update.conf` in the same directory as the script based on your needs (see Configuration section below).
## Configuration
The configuration is in a file named `cloudflare-dns-update.conf` with the following content:
```bash
zoneid="your_cloudflare_zone_id"
cloudflare_zone_api_token="your_cloudflare_api_token"
# "DOMAIN,TTL,PROXY" ==> "google.com,3600,true"
dns_record=(
"example.com,3600,true"
"sub1.example.com,1,true"
"sub2.example.com,1,false"
"sub3.example.com,120,true"
"sub4.example.com,,"
) # Automatic TTL = 1 , TTL and Proxy dont set ==> TTL = 1 and PROXY=true
ttl=1 # Or any value between 120 and 7200 (1 for automatic)
proxied=false # Or true
notify_me_telegram="no" # Or "yes"
telegram_bot_API_Token="your_telegram_bot_token" # If using Telegram notifications
telegram_chat_id="your_telegram_chat_id" # If using Telegram notifications
```
Replace the placeholder values with your actual Cloudflare and Telegram (if used) credentials.
This is where you can get your API Tokens: https://dash.cloudflare.com/profile/api-tokens
***You should get the API Tokens by clicking the "Create Token" button instead of the API Keys.
(API Tokens and keys are DIFFERENT)***
## Usage
Run the script manually:
```bash
./cloudflare-dns-update.sh
```
For automatic updates, you can set up a cron job. For example, to run the script every 5 minutes:
Run the command:
```bash
crontab -e
```
And add the following (it means running the config once per 5 minutes):
```bash
*/5 * * * * /path/to/cloudflare-dns-update.sh
```
### For NixOS
It's a better idea to do this declaratively in NixOS.
In your configuration.nix (the default configuration file for NixOS):
```nix
services.cron = {
enable = true;
systemCronJobs = [
"* * * * * [username] /your/path/to/cloudflare-dns-update.sh"
];
};
```
Example:
```nix
services.cron = {
enable = true;
systemCronJobs = [
"* * * * * guest /home/guest/cloudflare-DDNS-script/cloudflare-dns-update.sh"
];
};
```
And you might need to install cron as well:
```nix
environment.systemPackages = [
pkgs.cron
];
```
Tested on my raspberrypi 4 with NixOS installed and it was working perfectly.
## Logging
The script creates a log file named `cloudflare-dns-update.log` in the same directory. This log file contains information about each run of the script, including any errors encountered.
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Disclaimer
This script is provided as-is, without any warranties. Always test thoroughly before using in a production environment.
## Acknowledgments
- Thanks to Cloudflare for providing a robust API.
- Thanks to various public IP services for enabling reliable IP address retrieval.
- Thanks to ChatGPT for generating this README as well.
- Motivated by [DDNS-Cloudflare-Bash](https://github.com/fire1ce/DDNS-Cloudflare-Bash)

View file

@ -0,0 +1,16 @@
zoneid="your_cloudflare_zone_id"
cloudflare_zone_api_token="your_cloudflare_api_token"
# "DOMAIN,TTL,PROXY" ==> "google.com,3600,true"
dns_record=(
"example.com,3600,true"
"sub1.example.com,1,true"
"sub2.example.com,1,false"
"sub3.example.com,120,true"
"sub4.example.com,,"
) # Automatic TTL = 1 , TTL and Proxy dont set ==> TTL = 1 and PROXY=true
ttl=1 # Or any value between 120 and 7200 (1 for automatic)
proxied=false # Or true
notify_me_telegram="no" # Or "yes"
telegram_bot_API_Token="your_telegram_bot_token" # If using Telegram notifications
telegram_chat_id="your_telegram_chat_id" # If using Telegram notifications

169
cloudflare-dns-update.sh Executable file
View file

@ -0,0 +1,169 @@
#!/usr/bin/env bash
set -euo pipefail
### Function to log messages
log() {
echo "$(date "+%Y-%m-%d %H:%M:%S") $1" | tee -a "$LOG_FILE" >&2
}
### Function to log messages only to the log file
log_to_file() {
echo "$(date "+%Y-%m-%d %H:%M:%S") $1" >> "$LOG_FILE"
}
### Create log file
parent_path="$(dirname "${BASH_SOURCE[0]}")"
LOG_FILE="${parent_path}/cloudflare-dns-update.log"
touch "$LOG_FILE"
log "==> Script started"
### Validate config file
config_file="${1:-${parent_path}/cloudflare-dns-update.conf}"
if ! source "$config_file"; then
log "Error! Missing configuration file $config_file or invalid syntax!"
exit 1
fi
### Check validity of parameters
if ! [[ "$ttl" =~ ^[0-9]+$ ]] || { [ "$ttl" -lt 120 ] || [ "$ttl" -gt 7200 ]; } && [ "$ttl" -ne 1 ]; then
log "Error! ttl must be 1 or between 120 and 7200"
exit 1
fi
### Valid IPv4 and IPv6 Regex
readonly IPV4_REGEX='^([0-9]{1,3}\.){3}[0-9]{1,3}$'
readonly IPV6_REGEX='^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$'
### Function to get external IP (IPv4 or IPv6)
get_external_ip() {
local ip_type=$1
local sources=()
local regex
case "$ip_type" in
ipv4)
sources=("https://api.ipify.org" "https://checkip.amazonaws.com" "https://ifconfig.me/ip")
regex="$IPV4_REGEX"
;;
ipv6)
sources=("https://api64.ipify.org" "https://ifconfig.co/ip")
regex="$IPV6_REGEX"
;;
*)
log "Error! Invalid IP type specified: $ip_type"
return 1
;;
esac
for source in "${sources[@]}"; do
if ip=$(curl -"${ip_type:3:1}" -s "$source" --max-time 10) && [[ "$ip" =~ $regex ]]; then
echo "$ip"
return 0
fi
done
log "Error! Unable to retrieve $ip_type address from any source."
return 1
}
### Get external IPs
ipv4=$(get_external_ip "ipv4") || ipv4=""
ipv6=$(get_external_ip "ipv6") || ipv6=""
[ -n "$ipv4" ] && log "==> External IPv4 is: $ipv4"
[ -n "$ipv6" ] && log "==> External IPv6 is: $ipv6"
### Function to extract value from JSON
json_extract() {
local key=$1
sed -n 's/.*"'"$key"'":"\?\([^,"]*\)"\?.*/\1/p'
}
### Function to update DNS record
update_dns_record() {
local record=$1
local ip=$2
local type=$3
local ttl=$4
local proxied=$5
# Get the DNS record information from Cloudflare API
local cloudflare_record_info
cloudflare_record_info=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records?type=$type&name=$record" \
-H "Authorization: Bearer $cloudflare_zone_api_token" \
-H "Content-Type: application/json")
log_to_file "Cloudflare API response: $cloudflare_record_info" # Log the API response to file for debugging
if [[ $cloudflare_record_info == *"\"success\":false"* ]]; then
log "Error! Can't get $record ($type) record information from Cloudflare API"
return 1
fi
# Get the current IP and proxy status from the API response
local current_ip
current_ip=$(echo "$cloudflare_record_info" | json_extract "content")
local current_proxied
current_proxied=$(echo "$cloudflare_record_info" | json_extract "proxied")
# Check if IP or proxy have changed
if [ "$current_ip" == "$ip" ] && [ "$current_proxied" == "$proxied" ]; then
log "==> DNS $type record of $record is $current_ip, no changes needed."
return 0
fi
log "==> DNS $type record of $record is: $current_ip. Trying to update..."
# Get the DNS record ID from response
local cloudflare_dns_record_id
cloudflare_dns_record_id=$(echo "$cloudflare_record_info" | json_extract "id")
# Push new DNS record information to Cloudflare API
if ! 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\":\"$type\",\"name\":\"$record\",\"content\":\"$ip\",\"ttl\":$ttl,\"proxied\":$proxied}" | grep -q '"success":true'; then
log "Error! Update failed for $record ($type)"
return 1
fi
log "==> Success!"
log "==> $record DNS $type Record updated to: $ip, ttl: $ttl, proxied: $proxied"
# Telegram notification
if [ "${notify_me_telegram:-no}" == "yes" ]; then
send_telegram_notification "$record" "$type" "$ip" "$ttl" "$proxied"
fi
}
### Function to send Telegram notification
send_telegram_notification() {
local record=$1
local type=$2
local ip=$3
local ttl=$4
local proxied=$5
if ! curl -s -X POST "https://api.telegram.org/bot${telegram_bot_API_Token}/sendMessage" \
-H "Content-Type: application/json" \
--data "{\"chat_id\":\"${telegram_chat_id}\",\"text\":\"DNS Record Update\nDomain: ${record}\nType: ${type}\nIP: ${ip}\nTTL: ${ttl}\nProxied: ${proxied}\"}" | grep -q '"ok":true'; then
log "Error! Telegram notification failed for $record ($type)"
fi
}
# Update DNS records
for dns_record in "${dns_record[@]}"; do
IFS=',' read -r record ttl proxied <<< "$dns_record"
ttl="${ttl:-1}" # if TTL is null, set to automatic 1
proxied="${proxied:-true}" # if proxied is null, set true
[ -n "$ipv4" ] && update_dns_record "$record" "$ipv4" "A" "$ttl" "$proxied"
[ -n "$ipv6" ] && update_dns_record "$record" "$ipv6" "AAAA" "$ttl" "$proxied"
done
log "==> Script finished"