51 lines
1.6 KiB
Bash
Executable File
51 lines
1.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# DDNS updater — keeps jongsma.me A record current in Cloudflare
|
|
# Runs every 5 min via cron; only calls CF API when IP has changed
|
|
|
|
ZONE_ID="60b98ddacd2a61df9ac36b39acfe8b2c"
|
|
RECORD_NAME="jongsma.me"
|
|
STATE_FILE="/tmp/ddns-last-ip"
|
|
|
|
source /home/johan/.config/cloudflare.env
|
|
|
|
# Get current public IP
|
|
CURRENT_IP=$(curl -sf --max-time 5 https://api.ipify.org || curl -sf --max-time 5 https://ifconfig.me)
|
|
if [ -z "$CURRENT_IP" ]; then
|
|
echo "$(date -u): Failed to get public IP" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Compare to last known
|
|
LAST_IP=$(cat "$STATE_FILE" 2>/dev/null)
|
|
if [ "$CURRENT_IP" = "$LAST_IP" ]; then
|
|
exit 0
|
|
fi
|
|
|
|
echo "$(date -u): IP changed: $LAST_IP -> $CURRENT_IP"
|
|
|
|
# Get record ID
|
|
RECORD_ID=$(curl -sf \
|
|
"https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?type=A&name=$RECORD_NAME" \
|
|
-H "Authorization: Bearer $CF_API_TOKEN" | \
|
|
python3 -c "import sys,json; r=json.load(sys.stdin)['result']; print(r[0]['id'] if r else '')")
|
|
|
|
if [ -z "$RECORD_ID" ]; then
|
|
echo "$(date -u): Record not found for $RECORD_NAME" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Update record
|
|
RESULT=$(curl -sf -X PUT \
|
|
"https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" \
|
|
-H "Authorization: Bearer $CF_API_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"type\":\"A\",\"name\":\"$RECORD_NAME\",\"content\":\"$CURRENT_IP\",\"ttl\":1,\"proxied\":false}")
|
|
|
|
if echo "$RESULT" | python3 -c "import sys,json; sys.exit(0 if json.load(sys.stdin).get('success') else 1)"; then
|
|
echo "$(date -u): Updated $RECORD_NAME -> $CURRENT_IP"
|
|
echo "$CURRENT_IP" > "$STATE_FILE"
|
|
else
|
|
echo "$(date -u): CF API error: $RESULT" >&2
|
|
exit 1
|
|
fi
|