diff --git a/Dynamic_DNS/Cloudflare/README.md b/Dynamic_DNS/Cloudflare/README.md new file mode 100644 index 0000000..9743a91 --- /dev/null +++ b/Dynamic_DNS/Cloudflare/README.md @@ -0,0 +1,126 @@ +# ๐Ÿ” Dynamic DNS Updater for Cloudflare with Mullvad IP + +This script updates A records in Cloudflare with your current public IP as reported by [Mullvad](https://mullvad.net)'s IP check service. It supports: + +- Multiple domains/zones via `.env` files +- Secure API access using **Cloudflare API Tokens** +- Smart updates: only changes DNS if your IP has changed +- Daily logging to `./logs/` + +--- + +## ๐Ÿš€ Features + +- โœ… Fetches current public IP from Mullvad API (`https://ipv4.am.i.mullvad.net/json`) +- โœ… Uses `.env` files to manage multiple Cloudflare DNS records +- โœ… Supports **API Tokens** (safer than global keys) +- โœ… Skips unnecessary updates if IP hasn't changed +- โœ… Logs every run to `logs/update_YYYY-MM-DD.log` + +--- + +## ๐Ÿ“ Project Structure + +. +โ”œโ”€โ”€ update_cloudflare_ip.sh # Main script +โ”œโ”€โ”€ zones/ # Folder for per-domain config files +โ”‚ โ”œโ”€โ”€ example_com.env +โ”‚ โ””โ”€โ”€ another_domain.env +โ””โ”€โ”€ logs/ # Auto-created daily log files + โ””โ”€โ”€ update_2025-10-05.log + + + +--- + +## โš™๏ธ Configuration + +1. Create a `zones/` folder (already included in repo). +2. Add one `.env` file per domain/zone, named descriptively. Example: + +### `zones/subdomain.domain.com.env` + +``` +ZONE_ID="your_cloudflare_zone_id" +DNS_RECORD_ID="your_dns_record_id" +CLOUDFLARE_API_TOKEN="your_cloudflare_api_token" +DNS_NAME="subdomain.domain.com" +``` + +## โœ… Use Cloudflare API Tokens with permission: +Zone โ†’ DNS โ†’ Edit for the required zone. + +๐Ÿงช Usage + +Make the script executable: +``` +chmod +x update_cloudflare_ip.sh +``` + +Run it manually: +``` +./update_cloudflare_ip.sh +``` + +Check logs: +``` +cat logs/update_$(date +%F).log +``` + +## ๐Ÿ•’ Automation (Cron Example) + +To run the script every 10 minutes, edit your crontab: +``` +crontab -e +``` + +Add this line: +``` +*/10 * * * * /path/to/update_cloudflare_ip.sh >> /dev/null 2>&1 + +``` + +Or, if you want to keep logs automatically: +``` +*/10 * * * * /path/to/update_cloudflare_ip.sh >> /path/to/logs/cron.log 2>&1 +``` + + +## โœ… Requirements + +* bash (scripted for Linux/macOS) +* curl +* jq (lightweight and flexible command-line JSON processor): https://github.com/jqlang/jq + +Install jq if missing: +``` +# Debian/Ubuntu +sudo apt install jq + +# macOS (Homebrew) +brew install jq +``` + +## ๐Ÿ” Security Tip + +Never share your .env files or commit them to public repositories. They contain sensitive credentials. + +Use .gitignore to ignore your secrets: + +.gitignore +``` +zones/*.env +logs/ +``` + + +## ๐Ÿ™‹ FAQ + +Q: What happens if the IP hasn't changed? +A: The script detects it and skips the update. + +Q: What if one domain fails? +A: The script continues to process the remaining .env files. + +Q: Can I use IPv6? +A: Not currently. This script uses Mullvad's IPv4 API. IPv6 support can be added if needed. diff --git a/Dynamic_DNS/Cloudflare/logs/Here_Be_Logs b/Dynamic_DNS/Cloudflare/logs/Here_Be_Logs new file mode 100644 index 0000000..e69de29 diff --git a/Dynamic_DNS/Cloudflare/update_cloudflare_ip.sh b/Dynamic_DNS/Cloudflare/update_cloudflare_ip.sh new file mode 100644 index 0000000..d06502f --- /dev/null +++ b/Dynamic_DNS/Cloudflare/update_cloudflare_ip.sh @@ -0,0 +1,93 @@ +#!/bin/bash + +# Exit on error +set -e + +# --- Configuration --- +ENV_DIR="./zones" +LOG_DIR="./logs" +DATE=$(date +%F) +LOG_FILE="$LOG_DIR/update_${DATE}.log" + +# --- Ensure log directory exists --- +mkdir -p "$LOG_DIR" + +# --- Logging function --- +log() { + local message="$1" + echo "$message" | tee -a "$LOG_FILE" +} + +# --- Step 1: Get current IP from Mullvad --- +log "[*] Fetching IP from Mullvad..." +IP_INFO=$(curl -s https://ipv4.am.i.mullvad.net/json) +CURRENT_IP=$(echo "$IP_INFO" | jq -r '.ip') + +if [[ -z "$CURRENT_IP" ]]; then + log "[!] Failed to extract IP address." + exit 1 +fi + +log "[*] Current public IP is: $CURRENT_IP" +log "" + +# --- Step 2: Loop through all .env files --- +for ENV_FILE in "$ENV_DIR"/*.env; do + log "[*] Processing config: $ENV_FILE" + + # Load environment variables + set -a + source "$ENV_FILE" + set +a + + # Check for required variables + if [[ -z "$ZONE_ID" || -z "$DNS_RECORD_ID" || -z "$CLOUDFLARE_API_TOKEN" || -z "$DNS_NAME" ]]; then + log "[!] Missing required variables in $ENV_FILE" + log "" + continue + fi + + # --- Step 3: Get existing DNS record from Cloudflare --- + log "[*] Fetching current DNS record for $DNS_NAME..." + + DNS_RECORD=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$DNS_RECORD_ID" \ + -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ + -H "Content-Type: application/json") + + EXISTING_IP=$(echo "$DNS_RECORD" | jq -r '.result.content') + + if [[ "$EXISTING_IP" == "$CURRENT_IP" ]]; then + log "[=] No update needed. $DNS_NAME already points to $CURRENT_IP" + log "" + continue + fi + + # --- Step 4: Update DNS record --- + log "[*] IP has changed: $EXISTING_IP โ†’ $CURRENT_IP" + log "[*] Updating Cloudflare DNS record..." + + UPDATE_RESPONSE=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$DNS_RECORD_ID" \ + -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ + -H "Content-Type: application/json" \ + -d "{ + \"type\": \"A\", + \"name\": \"$DNS_NAME\", + \"content\": \"$CURRENT_IP\", + \"ttl\": 3600, + \"proxied\": true, + \"comment\": \"Auto-updated via script\" + }") + + SUCCESS=$(echo "$UPDATE_RESPONSE" | jq -r '.success') + + if [[ "$SUCCESS" == "true" ]]; then + log "[+] Successfully updated $DNS_NAME to $CURRENT_IP" + else + log "[!] Failed to update $DNS_NAME" + log "Cloudflare response:" + echo "$UPDATE_RESPONSE" | tee -a "$LOG_FILE" + fi + + log "" +done + diff --git a/Dynamic_DNS/Cloudflare/zones/subdomain.domain.com.env b/Dynamic_DNS/Cloudflare/zones/subdomain.domain.com.env new file mode 100644 index 0000000..aa6e0b2 --- /dev/null +++ b/Dynamic_DNS/Cloudflare/zones/subdomain.domain.com.env @@ -0,0 +1,5 @@ +ZONE_ID="your_zone_id" +DNS_RECORD_ID="your_dns_record_id" +CLOUDFLARE_API_TOKEN="your_cloudflare_api_token" +DNS_NAME="subdomain.example.com" +