feat: start-voip.sh — update DNS locally + start Docker stack

- Removed dns-updater Docker sidecar (curl not available in alpine)
- scripts/start-voip.sh: updates DNS then docker compose up
- update-dns.sh: supports --once flag, runs locally with curl
- All CF API calls forced to IPv4 (-4 flag)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Siavash Sameni
2026-03-30 11:39:23 +04:00
parent 74af18463e
commit 02471b28ba
3 changed files with 65 additions and 41 deletions

View File

@@ -82,17 +82,6 @@ services:
networks: networks:
- backend - backend
# ─── Dynamic DNS updater (keeps A + AAAA current) ───
dns-updater:
image: python:3-alpine
restart: unless-stopped
volumes:
- ./update-dns.sh:/update-dns.sh:ro
secrets:
- cf_api_token
entrypoint: ["/bin/sh", "-c", "apk add --no-cache curl > /dev/null 2>&1 && /bin/sh /update-dns.sh"]
environment:
DNS_UPDATE_INTERVAL: "300" # 5 minutes
secrets: secrets:
cf_api_token: cf_api_token:

View File

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

35
warzone/scripts/start-voip.sh Executable file
View File

@@ -0,0 +1,35 @@
#!/bin/bash
set -euo pipefail
# Start featherChat Docker stack + update DNS.
# Usage: ./scripts/start-voip.sh
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
DOCKER_DIR="$PROJECT_DIR/deploy/docker"
DNS_SCRIPT="$DOCKER_DIR/update-dns.sh"
CF_TOKEN_FILE="$DOCKER_DIR/cf_api_token.txt"
# Check CF token
if [ ! -f "$CF_TOKEN_FILE" ]; then
echo "ERROR: $CF_TOKEN_FILE not found"
echo " echo 'YOUR_CF_TOKEN' > $CF_TOKEN_FILE"
exit 1
fi
export CF_API_TOKEN=$(cat "$CF_TOKEN_FILE" | tr -d '\n')
# Update DNS first
echo "=== Updating DNS ==="
bash "$DNS_SCRIPT" --once
# Start Docker stack
echo ""
echo "=== Starting Docker stack ==="
cd "$DOCKER_DIR"
docker compose up -d
echo ""
echo "=== Running ==="
echo "URL: https://voip.manko.yoga"
echo "Logs: docker compose -f $DOCKER_DIR/docker-compose.yml logs -f"