Compare commits
	
		
			4 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 0a90e4c305 | |||
| ffeb767822 | |||
| cc1e47981e | |||
| 1eb4d13de9 | 
| @ -1,66 +1,167 @@ | ||||
| #!/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) || { | ||||
|   log "[!] Failed to fetch IP from Mullvad" | ||||
|   exit 1 | ||||
| } | ||||
| 
 | ||||
| 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 "" | ||||
| 
 | ||||
| # Loop through all .env files in ENV_DIR | ||||
| for ENV_FILE in "$ENV_DIR"/*.env; do | ||||
|   echo "[*] Processing config: $ENV_FILE" | ||||
| # --- 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" | ||||
| 
 | ||||
|   # 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_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..." | ||||
|   # --- Check if DNS record exists --- | ||||
|   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" \ | ||||
|     -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 | ||||
|         }') | ||||
|   DNS_LOOKUP=$(curl -sf -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?type=A&name=$DNS_NAME" \ | ||||
|     -H "Authorization: Bearer $CLOUDFLARE_API_KEY" \ | ||||
|     -H "Content-Type: application/json") | ||||
|   CURL_EXIT_CODE=$? | ||||
| 
 | ||||
| 
 | ||||
|   SUCCESS=$(echo "$UPDATE_RESPONSE" | jq -r '.success') | ||||
| 
 | ||||
|   if [[ "$SUCCESS" == "true" ]]; then | ||||
|     echo "[+] $DNS_NAME updated successfully!" | ||||
|   else | ||||
|     echo "[!] Failed to update $DNS_NAME." | ||||
|     echo "Cloudflare response:" | ||||
|     echo "$UPDATE_RESPONSE" | ||||
|   if [[ $CURL_EXIT_CODE -ne 0 ]]; then | ||||
|     log "[!] Failed to query DNS record for $DNS_NAME (curl exit code $CURL_EXIT_CODE)" | ||||
|     log "$DNS_LOOKUP" | ||||
|     log "" | ||||
|     continue | ||||
|   fi | ||||
| 
 | ||||
|   echo | ||||
|   RECORD_ID=$(echo "$DNS_LOOKUP" | jq -r '.result[0].id // empty') | ||||
|   EXISTING_IP=$(echo "$DNS_LOOKUP" | jq -r '.result[0].content // empty') | ||||
| 
 | ||||
|   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 "Content-Type: application/json" \ | ||||
|       -H "Authorization: Bearer $CLOUDFLARE_API_KEY" \ | ||||
|       -d "{ | ||||
|             \"name\": \"$DNS_NAME\", | ||||
|             \"ttl\": 3600, | ||||
|             \"type\": \"A\", | ||||
|             \"comment\": \"Domain verification record\", | ||||
|             \"content\": \"$CURRENT_IP\", | ||||
|             \"proxied\": true | ||||
|           }") | ||||
|     CURL_EXIT_CODE=$? | ||||
| 
 | ||||
|     if [[ $CURL_EXIT_CODE -ne 0 ]]; then | ||||
|       log "[!] curl failed creating DNS record (exit code $CURL_EXIT_CODE)" | ||||
|       log "$CREATE_RESPONSE" | ||||
|       log "" | ||||
|       continue | ||||
|     fi | ||||
| 
 | ||||
|     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 | ||||
| 
 | ||||
|   # --- 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 "Content-Type: application/json" \ | ||||
|     -H "Authorization: Bearer $CLOUDFLARE_API_KEY" \ | ||||
|     -d "{ | ||||
|           \"name\": \"$DNS_NAME\", | ||||
|           \"ttl\": 3600, | ||||
|           \"type\": \"A\", | ||||
|           \"comment\": \"Domain verification record\", | ||||
|           \"content\": \"$CURRENT_IP\", | ||||
|           \"proxied\": true | ||||
|         }") | ||||
|   CURL_EXIT_CODE=$? | ||||
| 
 | ||||
|   if [[ $CURL_EXIT_CODE -ne 0 ]]; then | ||||
|     log "[!] curl failed updating DNS record (exit code $CURL_EXIT_CODE)" | ||||
|     log "$UPDATE_RESPONSE" | ||||
|     log "" | ||||
|     continue | ||||
|   fi | ||||
| 
 | ||||
|   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 | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| ZONE_ID="abc123zoneid" | ||||
| DNS_RECORD_ID="def456recordid" | ||||
| CLOUDFLARE_EMAIL="you@example.com" | ||||
| CLOUDFLARE_API_KEY="your_api_key_here" | ||||
| DNS_NAME="subdomain.example.com" | ||||
| CLOUDFLARE_API_KEY="your_api_key_here" | ||||
| 
 | ||||
|  | ||||
| @ -1,2 +1,3 @@ | ||||
| # Cloudflare API Token (must have Zone:Read + DNS:Read permissions) | ||||
| # Example env file (envs/site1.env) | ||||
| CLOUDFLARE_API_TOKEN=your_api_token_here | ||||
| @ -1,38 +1,61 @@ | ||||
| #!/bin/bash | ||||
| set -euo pipefail | ||||
| 
 | ||||
| # Load config | ||||
| source config.conf | ||||
| 
 | ||||
| ENV_DIR="./envs" | ||||
| EXPORT_FOLDER="export" | ||||
| mkdir -p "$EXPORT_FOLDER" | ||||
| 
 | ||||
| # Step 1: Fetch all zones from Cloudflare | ||||
| echo "Fetching zone list from Cloudflare..." | ||||
| zones_json=$(curl -s https://api.cloudflare.com/client/v4/zones \ | ||||
|     -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ | ||||
|     -H "Content-Type: application/json") | ||||
| # Find all .env files in the ENV_DIR | ||||
| env_files=("$ENV_DIR"/*.env) | ||||
| 
 | ||||
| # Step 2: Parse zones (needs jq) | ||||
| zone_count=$(echo "$zones_json" | jq '.result | length') | ||||
| echo "Found $zone_count zones." | ||||
| if [ ${#env_files[@]} -eq 0 ]; then | ||||
|     echo "❌ No .env files found in $ENV_DIR" | ||||
|     exit 1 | ||||
| fi | ||||
| 
 | ||||
| # Step 3: Loop through zones | ||||
| for ((i=0; i<zone_count; i++)); do | ||||
|     ZONE_ID=$(echo "$zones_json" | jq -r ".result[$i].id") | ||||
|     SITE_NAME=$(echo "$zones_json" | jq -r ".result[$i].name") | ||||
| for env_file in "${env_files[@]}"; do | ||||
|     echo "🔄 Processing environment file: $env_file" | ||||
|      | ||||
|     TIMESTAMP=$(date +"%Y%m%d_%H%M%S") | ||||
|     OUTPUT_FILE="$EXPORT_FOLDER/${SITE_NAME}_$TIMESTAMP.txt" | ||||
|     # Load environment variables from .env file | ||||
|     set -o allexport | ||||
|     source "$env_file" | ||||
|     set +o allexport | ||||
| 
 | ||||
|     echo "Exporting DNS records for $SITE_NAME..." | ||||
|     if [[ -z "${CLOUDFLARE_API_TOKEN:-}" ]]; then | ||||
|         echo "⚠️  CLOUDFLARE_API_TOKEN not set in $env_file. Skipping." | ||||
|         continue | ||||
|     fi | ||||
| 
 | ||||
|     curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/export" \ | ||||
|     # Step 1: Fetch all zones from Cloudflare | ||||
|     echo "Fetching zone list from Cloudflare..." | ||||
|     zones_json=$(curl -s https://api.cloudflare.com/client/v4/zones \ | ||||
|         -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ | ||||
|         -H "Content-Type: application/json" | tee "$OUTPUT_FILE" | ||||
|         -H "Content-Type: application/json") | ||||
| 
 | ||||
|     echo " -> Saved to $OUTPUT_FILE" | ||||
|     # Step 2: Parse zones (needs jq) | ||||
|     zone_count=$(echo "$zones_json" | jq '.result | length') | ||||
|     echo "Found $zone_count zones." | ||||
| 
 | ||||
|     # Step 3: Loop through zones | ||||
|     for ((i=0; i<zone_count; i++)); do | ||||
|         ZONE_ID=$(echo "$zones_json" | jq -r ".result[$i].id") | ||||
|         SITE_NAME=$(echo "$zones_json" | jq -r ".result[$i].name") | ||||
| 
 | ||||
|         TIMESTAMP=$(date +"%Y%m%d_%H%M%S") | ||||
|         OUTPUT_FILE="$EXPORT_FOLDER/${SITE_NAME}_$TIMESTAMP.txt" | ||||
| 
 | ||||
|         echo "Exporting DNS records for $SITE_NAME..." | ||||
| 
 | ||||
|         curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/export" \ | ||||
|             -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ | ||||
|             -H "Content-Type: application/json" | tee "$OUTPUT_FILE" | ||||
| 
 | ||||
|         echo " -> Saved to $OUTPUT_FILE" | ||||
|     done | ||||
| 
 | ||||
|     echo "✅ Export complete for $env_file" | ||||
|     echo "" | ||||
| done | ||||
| 
 | ||||
| echo "✅ All exports complete. Files are in the '$EXPORT_FOLDER' folder." | ||||
| echo "🎉 All exports finished. Files are in the '$EXPORT_FOLDER' folder." | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user