From 1eb4d13de955e567c8ff898e53be2efb7b0285f2 Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 5 Oct 2025 21:06:48 +0100 Subject: [PATCH] Updated script so if the record doesn't exist, it will create it. Updated env file --- .../update_cloudflare_ip.sh | 154 +++++++++++++----- .../zones/subdomain.domain.com.env | 4 +- 2 files changed, 117 insertions(+), 41 deletions(-) diff --git a/Dynamic_DNS/Dynamic_DNS_Cloudflare/update_cloudflare_ip.sh b/Dynamic_DNS/Dynamic_DNS_Cloudflare/update_cloudflare_ip.sh index e6702a8..54bfad9 100644 --- a/Dynamic_DNS/Dynamic_DNS_Cloudflare/update_cloudflare_ip.sh +++ b/Dynamic_DNS/Dynamic_DNS_Cloudflare/update_cloudflare_ip.sh @@ -1,66 +1,142 @@ #!/bin/bash -# Exit if any command fails -set -e +set -euo pipefail -# Directory containing all .env config files -ENV_DIR="./zones" +# --- Configuration --- +: "${ENV_DIR:="./zones"}" +: "${LOG_DIR:="./logs"}" +DATE=$(date +%F) +LOG_FILE="$LOG_DIR/update_${DATE}.log" -# Fetch current IP from Mullvad -echo "[*] Fetching IP info from Mullvad..." -IP_INFO=$(curl -s https://ipv4.am.i.mullvad.net/json) -IP=$(echo "$IP_INFO" | jq -r '.ip') +# --- Ensure log directory exists --- +mkdir -p "$LOG_DIR" -if [[ -z "$IP" ]]; then - echo "[!] Failed to extract IP address." +# --- Logging function --- +log() { + local message="$1" + echo "$message" | tee -a "$LOG_FILE" +} + +# --- Check required tools --- +for cmd in curl jq; do + if ! command -v "$cmd" >/dev/null 2>&1; then + echo "[!] Required tool '$cmd' not found. Please install it." >&2 + exit 1 + fi +done + +# --- Fetch current IP from Mullvad --- +log "[*] Fetching IP from Mullvad..." +IP_INFO=$(curl -sf https://ipv4.am.i.mullvad.net/json) + +if ! echo "$IP_INFO" | jq -e '.ip' >/dev/null; then + log "[!] Invalid Mullvad response or missing IP." + log "$IP_INFO" exit 1 fi -echo "[*] Current public IP is: $IP" -echo +CURRENT_IP=$(echo "$IP_INFO" | jq -r '.ip') +log "[*] Current public IP is: $CURRENT_IP" +log "" + +# --- Get list of .env files --- +shopt -s nullglob +ENV_FILES=("$ENV_DIR"/*.env) + +if [[ ${#ENV_FILES[@]} -eq 0 ]]; then + log "[!] No .env files found in $ENV_DIR" + exit 0 +fi + +# --- Process each env file --- +for ENV_FILE in "${ENV_FILES[@]}"; do + log "[*] Processing config: $ENV_FILE" -# Loop through all .env files in ENV_DIR -for ENV_FILE in "$ENV_DIR"/*.env; do - echo "[*] Processing config: $ENV_FILE" - # Load environment variables set -a source "$ENV_FILE" set +a - # Check required variables - if [[ -z "$ZONE_ID" || -z "$DNS_RECORD_ID" || -z "$CLOUDFLARE_EMAIL" || -z "$CLOUDFLARE_API_KEY" || -z "$DNS_NAME" ]]; then - echo "[!] Missing required variables in $ENV_FILE" + # Validate required vars + missing_vars=() + [[ -z "${ZONE_ID:-}" ]] && missing_vars+=("ZONE_ID") + [[ -z "${DNS_NAME:-}" ]] && missing_vars+=("DNS_NAME") + [[ -z "${CLOUDFLARE_EMAIL:-}" ]] && missing_vars+=("CLOUDFLARE_EMAIL") + [[ -z "${CLOUDFLARE_API_KEY:-}" ]] && missing_vars+=("CLOUDFLARE_API_KEY") + + if (( ${#missing_vars[@]} )); then + log "[!] Missing variables in $ENV_FILE: ${missing_vars[*]}" + log "" continue fi - # Make the API request - echo "[*] Updating Cloudflare record for $DNS_NAME..." + # --- Fetch DNS records for the zone --- + log "[*] Checking DNS record for $DNS_NAME..." - UPDATE_RESPONSE=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$DNS_RECORD_ID" \ - -H "Content-Type: application/json" \ + DNS_LOOKUP=$(curl -sf -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?type=A&name=$DNS_NAME" \ -H "X-Auth-Email: $CLOUDFLARE_EMAIL" \ -H "X-Auth-Key: $CLOUDFLARE_API_KEY" \ - -d '{ - "name": "'$DNS_NAME'", - "ttl": 3600, - "type": "A", - "comment": "Domain verification record", - "content": "'$IP'", - "proxied": true - }') + -H "Content-Type: application/json") + RECORD_ID=$(echo "$DNS_LOOKUP" | jq -r '.result[0].id // empty') + EXISTING_IP=$(echo "$DNS_LOOKUP" | jq -r '.result[0].content // empty') - SUCCESS=$(echo "$UPDATE_RESPONSE" | jq -r '.success') + if [[ -z "$RECORD_ID" ]]; then + log "[!] No existing record found. Creating new A record for $DNS_NAME..." + CREATE_RESPONSE=$(curl -sf -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \ + -H "X-Auth-Email: $CLOUDFLARE_EMAIL" \ + -H "X-Auth-Key: $CLOUDFLARE_API_KEY" \ + -H "Content-Type: application/json" \ + -d "{ + \"type\": \"A\", + \"name\": \"$DNS_NAME\", + \"content\": \"$CURRENT_IP\", + \"ttl\": 3600, + \"proxied\": true, + \"comment\": \"Created via script\" + }") - if [[ "$SUCCESS" == "true" ]]; then - echo "[+] $DNS_NAME updated successfully!" - else - echo "[!] Failed to update $DNS_NAME." - echo "Cloudflare response:" - echo "$UPDATE_RESPONSE" + if [[ $(echo "$CREATE_RESPONSE" | jq -r '.success') == "true" ]]; then + log "[+] Successfully created DNS record for $DNS_NAME → $CURRENT_IP" + else + log "[!] Failed to create DNS record for $DNS_NAME" + echo "$CREATE_RESPONSE" | tee -a "$LOG_FILE" + fi + log "" + continue fi - echo + # --- If record exists, check if update is needed --- + if [[ "$EXISTING_IP" == "$CURRENT_IP" ]]; then + log "[=] No update needed. $DNS_NAME already points to $CURRENT_IP" + log "" + continue + fi + + # --- Patch the existing record --- + log "[*] IP has changed: $EXISTING_IP → $CURRENT_IP" + log "[*] Updating existing DNS record via PATCH..." + + UPDATE_RESPONSE=$(curl -sf -X PATCH "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" \ + -H "X-Auth-Email: $CLOUDFLARE_EMAIL" \ + -H "X-Auth-Key: $CLOUDFLARE_API_KEY" \ + -H "Content-Type: application/json" \ + -d "{ + \"type\": \"A\", + \"name\": \"$DNS_NAME\", + \"content\": \"$CURRENT_IP\", + \"ttl\": 3600, + \"proxied\": true, + \"comment\": \"Updated via script\" + }") + + if [[ $(echo "$UPDATE_RESPONSE" | jq -r '.success') == "true" ]]; then + log "[+] Successfully updated $DNS_NAME to $CURRENT_IP" + else + log "[!] Failed to update $DNS_NAME" + echo "$UPDATE_RESPONSE" | tee -a "$LOG_FILE" + fi + + log "" done diff --git a/Dynamic_DNS/Dynamic_DNS_Cloudflare/zones/subdomain.domain.com.env b/Dynamic_DNS/Dynamic_DNS_Cloudflare/zones/subdomain.domain.com.env index bdb6aee..50cc3f0 100644 --- a/Dynamic_DNS/Dynamic_DNS_Cloudflare/zones/subdomain.domain.com.env +++ b/Dynamic_DNS/Dynamic_DNS_Cloudflare/zones/subdomain.domain.com.env @@ -1,5 +1,5 @@ ZONE_ID="abc123zoneid" -DNS_RECORD_ID="def456recordid" +DNS_NAME="subdomain.example.com" CLOUDFLARE_EMAIL="you@example.com" CLOUDFLARE_API_KEY="your_api_key_here" -DNS_NAME="subdomain.example.com" +