#!/bin/bash # Updates voip.manko.yoga DNS records with current public IPs. # Usage: # ./update-dns.sh Loop every 5 minutes # ./update-dns.sh --once Run once and exit # # Reads CF_API_TOKEN env var or deploy/docker/cf_api_token.txt DOMAIN="voip.manko.yoga" ZONE="manko.yoga" INTERVAL="${DNS_UPDATE_INTERVAL:-300}" get_token() { if [ -n "${CF_API_TOKEN:-}" ]; then echo "$CF_API_TOKEN" elif [ -f /run/secrets/cf_api_token ]; then cat /run/secrets/cf_api_token | tr -d '\n' else echo "ERROR: no CF token" >&2 exit 1 fi } get_zone_id() { curl -4 -s "https://api.cloudflare.com/client/v4/zones?name=$ZONE" \ -H "Authorization: Bearer $(get_token)" | \ python3 -c "import sys,json; print(json.load(sys.stdin)['result'][0]['id'])" 2>/dev/null } get_public_ipv4() { curl -4 -s --connect-timeout 5 https://api.ipify.org 2>/dev/null || \ curl -4 -s --connect-timeout 5 https://ifconfig.me 2>/dev/null || echo "" } get_public_ipv6() { curl -6 -s --connect-timeout 5 https://api6.ipify.org 2>/dev/null || \ curl -6 -s --connect-timeout 5 https://ifconfig.co 2>/dev/null || echo "" } upsert_record() { local zone_id="$1" type="$2" content="$3" token token=$(get_token) local existing existing=$(curl -4 -s "https://api.cloudflare.com/client/v4/zones/$zone_id/dns_records?name=$DOMAIN&type=$type" \ -H "Authorization: Bearer $token") local rec_id current rec_id=$(echo "$existing" | python3 -c "import sys,json; r=json.load(sys.stdin)['result']; print(r[0]['id'] if r else '')" 2>/dev/null) current=$(echo "$existing" | python3 -c "import sys,json; r=json.load(sys.stdin)['result']; print(r[0]['content'] if r else '')" 2>/dev/null) if [ "$current" = "$content" ]; then echo " $type: $content (unchanged)" return fi if [ -n "$rec_id" ]; then curl -4 -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zone_id/dns_records/$rec_id" \ -H "Authorization: Bearer $token" \ -H "Content-Type: application/json" \ --data "{\"type\":\"$type\",\"name\":\"$DOMAIN\",\"content\":\"$content\",\"ttl\":120,\"proxied\":false}" > /dev/null echo " $type: $current -> $content (updated)" else curl -4 -s -X POST "https://api.cloudflare.com/client/v4/zones/$zone_id/dns_records" \ -H "Authorization: Bearer $token" \ -H "Content-Type: application/json" \ --data "{\"type\":\"$type\",\"name\":\"$DOMAIN\",\"content\":\"$content\",\"ttl\":120,\"proxied\":false}" > /dev/null echo " $type: $content (created)" fi } update() { echo "[$(date -u +%H:%M:%S)] Updating DNS for $DOMAIN..." local zone_id zone_id=$(get_zone_id) if [ -z "$zone_id" ]; then echo " ERROR: cannot get zone ID" return 1 fi local ipv4 ipv6 ipv4=$(get_public_ipv4) ipv6=$(get_public_ipv6) [ -n "$ipv4" ] && upsert_record "$zone_id" "A" "$ipv4" || echo " A: no IPv4" [ -n "$ipv6" ] && upsert_record "$zone_id" "AAAA" "$ipv6" || echo " AAAA: no IPv6" } # Main if [ "${1:-}" = "--once" ]; then update else update while true; do sleep "$INTERVAL" update done fi