T-HUB/infra/occupymedia/edge/edge-firewall.sh
glass beadian 9365b561b2 Add edge stack: second ingress path + dual-path DNS failover
Cloudflare's tunnel edge-pool assignment can blackhole the site for whole
regions (2026-10-10: tunnel hostnames served from an unreachable anycast
range for hours). This adds an independent path and the automation that
keeps occupymedia.cc reachable when either path is sick:

- nginx edge mirroring the tunnel ingress (app/api/tube/chat/ping), LE
  wildcard via dns-01, twice-daily renewal
- DOCKER-USER firewall: 80/443 restricted to Cloudflare ranges (CF mode)
  or OPEN for grey-cloud mode via firewall.mode
- edge-watcher (60s systemd timer): dynamic public-IP sync, dual-path
  health checks, DNS failover TUNNEL<->ORIGIN/GREY with hysteresis,
  gated by EDGE_ENABLED
- ping.occupymedia.cc sacrificial probe host for activation
- deployment runbook in README.md; credential files shipped as .example
2026-10-10 21:22:15 +00:00

40 lines
1.4 KiB
Bash
Executable file

#!/bin/bash
# edge-firewall.sh — restrict the edge ports to Cloudflare's ranges only.
# Mode file ./firewall.mode: "CF" (default, CF ranges only) or "OPEN" (anyone —
# grey mode: visitors connect directly, nginx rejects unknown SNI).
# Idempotent; safe to re-run (rebuilds the DOCKER-USER rules from scratch).
set -euo pipefail
cd "$(dirname "$0")"
MODE="CF"
[[ -f firewall.mode ]] && MODE=$(cat firewall.mode)
CF4_URL="https://www.cloudflare.com/ips-v4"
CF6_URL="https://www.cloudflare.com/ips-v6"
# Reset our rules, keep anything else in DOCKER-USER.
iptables -F DOCKER-USER
ip6tables -F DOCKER-USER 2>/dev/null || true
if [[ $MODE == OPEN ]]; then
echo "edge firewall: OPEN (any source allowed on 80/443; nginx SNI gate applies)"
exit 0
fi
mapfile -t CF4 < <(curl -s -m 15 "$CF4_URL" | grep -v '^$')
mapfile -t CF6 < <(curl -s -m 15 "$CF6_URL" | grep -v '^$')
((${#CF4[@]} > 5)) || { echo "cf ips-v4 fetch failed" >&2; exit 1; }
for net in "${CF4[@]}"; do
iptables -A DOCKER-USER -p tcp -m multiport --dports 80,443 -s "$net" -j RETURN
done
iptables -A DOCKER-USER -p tcp -m multiport --dports 80,443 -j DROP
if ((${#CF6[@]} > 0)); then
for net in "${CF6[@]}"; do
ip6tables -A DOCKER-USER -p tcp -m multiport --dports 80,443 -s "$net" -j RETURN 2>/dev/null || true
done
ip6tables -A DOCKER-USER -p tcp -m multiport --dports 80,443 -j DROP 2>/dev/null || true
fi
echo "edge firewall: ${#CF4[@]} v4 + ${#CF6[@]} v6 CF ranges allowed on 80/443"