#!/bin/bash # Cloudflare DNS upsert — create or update a DNS record. # Usage: CLOUDFLARE_API_TOKEN=xxx ./scripts/cloudflare-dns.sh [ttl] # # Examples: # cloudflare-dns.sh jimmygan.com A code 161.33.182.109 # cloudflare-dns.sh jimmygan.com CNAME www jimmygan.com 120 set -euo pipefail ZONE="${1:?Usage: $0 [ttl]}" TYPE="${2:?}" NAME="${3:?}" CONTENT="${4:?}" TTL="${5:-120}" if [ -z "${CLOUDFLARE_API_TOKEN:-}" ]; then echo "❌ CLOUDFLARE_API_TOKEN not set" >&2 exit 1 fi API="https://api.cloudflare.com/client/v4" AUTH_HEADER="Authorization: Bearer $CLOUDFLARE_API_TOKEN" CONTENT_TYPE="Content-Type: application/json" echo "🔍 Looking up zone: $ZONE" ZONE_RESP=$(curl -s -H "$AUTH_HEADER" -H "$CONTENT_TYPE" \ "$API/zones?name=$ZONE&status=active") ZONE_ID=$(echo "$ZONE_RESP" | python3 -c " import sys, json d = json.load(sys.stdin) if not d.get('success'): print('API error:', d.get('errors'), file=sys.stderr) sys.exit(1) result = d.get('result', []) if not result: print('Zone not found:', '$ZONE', file=sys.stderr) sys.exit(1) print(result[0]['id']) ") echo "✅ Zone ID: $ZONE_ID" echo "🔍 Checking existing record: $NAME.$ZONE ($TYPE)" RECORD_RESP=$(curl -s -H "$AUTH_HEADER" -H "$CONTENT_TYPE" \ "$API/zones/$ZONE_ID/dns_records?type=$TYPE&name=$NAME.$ZONE") RECORD_ID=$(echo "$RECORD_RESP" | python3 -c " import sys, json d = json.load(sys.stdin) if not d.get('success'): sys.exit(0) # skip, will create result = d.get('result', []) if result: # Prefer exact content match for r in result: if r['content'] == '$CONTENT': print(r['id']) sys.exit(0) # Fall back to first match print(result[0]['id']) ") FULL_NAME="$NAME.$ZONE" if [ -n "$RECORD_ID" ]; then echo "🔄 Updating existing record ($RECORD_ID): $FULL_NAME → $CONTENT" RESP=$(curl -s -X PUT \ -H "$AUTH_HEADER" -H "$CONTENT_TYPE" \ -d "{\"type\":\"$TYPE\",\"name\":\"$FULL_NAME\",\"content\":\"$CONTENT\",\"ttl\":$TTL,\"proxied\":false}" \ "$API/zones/$ZONE_ID/dns_records/$RECORD_ID") SUCCESS=$(echo "$RESP" | python3 -c "import sys,json; d=json.load(sys.stdin); print('true' if d.get('success') else 'false')") if [ "$SUCCESS" = "true" ]; then echo "✅ Updated: $FULL_NAME → $CONTENT" else echo "❌ Failed to update:" >&2 echo "$RESP" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('errors'))" >&2 exit 1 fi else echo "🆕 Creating new record: $FULL_NAME → $CONTENT" RESP=$(curl -s -X POST \ -H "$AUTH_HEADER" -H "$CONTENT_TYPE" \ -d "{\"type\":\"$TYPE\",\"name\":\"$FULL_NAME\",\"content\":\"$CONTENT\",\"ttl\":$TTL,\"proxied\":false}" \ "$API/zones/$ZONE_ID/dns_records") SUCCESS=$(echo "$RESP" | python3 -c "import sys,json; d=json.load(sys.stdin); print('true' if d.get('success') else 'false')") if [ "$SUCCESS" = "true" ]; then echo "✅ Created: $FULL_NAME → $CONTENT" else echo "❌ Failed to create:" >&2 echo "$RESP" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('errors'))" >&2 exit 1 fi fi