- update-all-dns-to-public-ip.sh: --dry-run (no CF API), --zone-only=ZONE, help before .env, env CLOUDFLARE_DNS_DRY_RUN/DNS_ZONE_ONLY - update-sankofa-npmplus-proxy-hosts.sh: the-order + www.the-order by ID (env SANKOFA_NPM_ID_THE_ORDER, SANKOFA_NPM_ID_WWW_THE_ORDER, THE_ORDER_UPSTREAM_*) - update-npmplus-proxy-hosts-api.sh: the-order.sankofa.nexus uses block_exploits false like sankofa portal - verify-end-to-end-routing.sh: E2E_WWW_CANONICAL_BASE + Location validation (fail on wrong apex); keep local redirect vars - docs: ALL_VMIDS www 301 lines, E2E_ENDPOINTS_LIST verifier/DNS notes; AGENTS.md Cloudflare script pointer Made-with: Cursor
161 lines
6.5 KiB
Bash
Executable File
161 lines
6.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
# Update Sankofa NPMplus proxy hosts (portal + Phoenix API + the-order) via API by numeric host ID.
|
||
# Prefer for production: scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh (domain-based, full fleet).
|
||
# NPM proxy host IDs below match backup backup-20260325_183932 (3–6, 7, 59); override with SANKOFA_NPM_ID_* if your DB differs.
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||
# shellcheck source=/dev/null
|
||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||
|
||
# Load environment variables
|
||
if [ -f "$PROJECT_ROOT/.env" ]; then
|
||
set -a
|
||
# shellcheck source=/dev/null
|
||
source "$PROJECT_ROOT/.env"
|
||
set +a
|
||
fi
|
||
|
||
NPM_URL="${NPM_URL:-https://${IP_NPMPLUS}:81}"
|
||
NPM_EMAIL="${NPM_EMAIL:-nsatoshi2007@hotmail.com}"
|
||
NPM_PASSWORD="${NPM_PASSWORD:-}"
|
||
NPM_CURL_MAX_TIME="${NPM_CURL_MAX_TIME:-180}"
|
||
|
||
IP_SANKOFA_PORTAL="${IP_SANKOFA_PORTAL:-${IP_SERVICE_51:-192.168.11.51}}"
|
||
IP_SANKOFA_PHOENIX_API="${IP_SANKOFA_PHOENIX_API:-${IP_SERVICE_50:-192.168.11.50}}"
|
||
SANKOFA_PORTAL_PORT="${SANKOFA_PORTAL_PORT:-3000}"
|
||
SANKOFA_PHOENIX_API_PORT="${SANKOFA_PHOENIX_API_PORT:-4000}"
|
||
THE_ORDER_UPSTREAM_IP="${THE_ORDER_UPSTREAM_IP:-${IP_SANKOFA_PORTAL}}"
|
||
THE_ORDER_UPSTREAM_PORT="${THE_ORDER_UPSTREAM_PORT:-${SANKOFA_PORTAL_PORT}}"
|
||
|
||
# NPM proxy host IDs: sankofa=3, www.sankofa=4, phoenix=5, www.phoenix=6; the-order=7, www.the-order=59 (typical; verify in NPM UI)
|
||
SANKOFA_NPM_ID_ROOT="${SANKOFA_NPM_ID_ROOT:-3}"
|
||
SANKOFA_NPM_ID_WWW="${SANKOFA_NPM_ID_WWW:-4}"
|
||
SANKOFA_NPM_ID_PHOENIX="${SANKOFA_NPM_ID_PHOENIX:-5}"
|
||
SANKOFA_NPM_ID_WWW_PHOENIX="${SANKOFA_NPM_ID_WWW_PHOENIX:-6}"
|
||
SANKOFA_NPM_ID_THE_ORDER="${SANKOFA_NPM_ID_THE_ORDER:-7}"
|
||
SANKOFA_NPM_ID_WWW_THE_ORDER="${SANKOFA_NPM_ID_WWW_THE_ORDER:-59}"
|
||
|
||
# Optional 4th field: canonical HTTPS apex — NPM advanced_config 301 (www → apex). Matches update-npmplus-proxy-hosts-api.sh.
|
||
declare -A PROXY_HOSTS=(
|
||
["$SANKOFA_NPM_ID_ROOT"]="sankofa.nexus|${IP_SANKOFA_PORTAL}|${SANKOFA_PORTAL_PORT}|"
|
||
["$SANKOFA_NPM_ID_WWW"]="www.sankofa.nexus|${IP_SANKOFA_PORTAL}|${SANKOFA_PORTAL_PORT}|https://sankofa.nexus"
|
||
["$SANKOFA_NPM_ID_PHOENIX"]="phoenix.sankofa.nexus|${IP_SANKOFA_PHOENIX_API}|${SANKOFA_PHOENIX_API_PORT}|"
|
||
["$SANKOFA_NPM_ID_WWW_PHOENIX"]="www.phoenix.sankofa.nexus|${IP_SANKOFA_PHOENIX_API}|${SANKOFA_PHOENIX_API_PORT}|https://phoenix.sankofa.nexus"
|
||
["$SANKOFA_NPM_ID_THE_ORDER"]="the-order.sankofa.nexus|${THE_ORDER_UPSTREAM_IP}|${THE_ORDER_UPSTREAM_PORT}|"
|
||
["$SANKOFA_NPM_ID_WWW_THE_ORDER"]="www.the-order.sankofa.nexus|${THE_ORDER_UPSTREAM_IP}|${THE_ORDER_UPSTREAM_PORT}|https://the-order.sankofa.nexus"
|
||
)
|
||
|
||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
echo "🔄 Updating Sankofa NPMplus Proxy Hosts"
|
||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
echo ""
|
||
|
||
# Authenticate
|
||
echo "🔐 Authenticating to NPMplus..."
|
||
TOKEN_RESPONSE=$(curl -s -k --connect-timeout 15 --max-time "$NPM_CURL_MAX_TIME" -X POST "$NPM_URL/api/tokens" \
|
||
-H "Content-Type: application/json" \
|
||
-d "{\"identity\":\"$NPM_EMAIL\",\"secret\":\"$NPM_PASSWORD\"}")
|
||
|
||
TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.token // empty' 2>/dev/null || echo "")
|
||
|
||
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
|
||
echo "❌ Authentication failed"
|
||
exit 1
|
||
fi
|
||
|
||
echo "✅ Authentication successful"
|
||
echo ""
|
||
|
||
# Function to update proxy host
|
||
update_proxy_host() {
|
||
local host_id=$1
|
||
local domain=$2
|
||
local target_ip=$3
|
||
local target_port=$4
|
||
local canonical_https="${5:-}"
|
||
|
||
echo "📝 Updating Proxy Host $host_id: $domain → $target_ip:$target_port"
|
||
|
||
# Get current proxy host
|
||
CURRENT_HOST=$(curl -s -k --connect-timeout 15 --max-time "$NPM_CURL_MAX_TIME" -X GET "$NPM_URL/api/nginx/proxy-hosts/$host_id" \
|
||
-H "Authorization: Bearer $TOKEN" 2>/dev/null || echo "{}")
|
||
|
||
if [ "$(echo "$CURRENT_HOST" | jq -r '.id // empty')" = "" ]; then
|
||
echo "❌ Proxy host $host_id not found"
|
||
return 1
|
||
fi
|
||
|
||
# NPMplus rejects full-document PUT (e.g. locations: null) — send only allowed forward fields.
|
||
local scheme="http"
|
||
local adv_line=""
|
||
if [ -n "$canonical_https" ]; then
|
||
adv_line="return 301 ${canonical_https}\$request_uri;"
|
||
fi
|
||
UPDATE_PAYLOAD=$(jq -n \
|
||
--arg scheme "$scheme" \
|
||
--arg hostname "$target_ip" \
|
||
--argjson port "$(echo "$target_port" | sed 's/[^0-9]//g')" \
|
||
--argjson websocket false \
|
||
--argjson block_exploits false \
|
||
--arg adv "$adv_line" \
|
||
'{
|
||
forward_scheme: $scheme,
|
||
forward_host: $hostname,
|
||
forward_port: $port,
|
||
allow_websocket_upgrade: $websocket,
|
||
block_exploits: $block_exploits
|
||
} + (if $adv != "" then {advanced_config: $adv} else {} end)')
|
||
|
||
RESPONSE=$(curl -s -k --connect-timeout 15 --max-time "${NPM_CURL_MAX_TIME:-120}" -X PUT "$NPM_URL/api/nginx/proxy-hosts/$host_id" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d "$UPDATE_PAYLOAD")
|
||
|
||
UPDATED_ID=$(echo "$RESPONSE" | jq -r '.id // empty' 2>/dev/null || echo "")
|
||
|
||
if [ -n "$UPDATED_ID" ] && [ "$UPDATED_ID" != "null" ]; then
|
||
echo "✅ Successfully updated proxy host $host_id"
|
||
return 0
|
||
else
|
||
echo "❌ Failed to update proxy host $host_id"
|
||
echo "$RESPONSE" | jq '.' 2>/dev/null || echo "$RESPONSE"
|
||
if echo "$RESPONSE" | jq -e '.error.code == 403' >/dev/null 2>&1; then
|
||
echo " (403 often means NPM user lacks permission to mutate proxy hosts; check UI role or use an admin identity.)"
|
||
fi
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# Update all proxy hosts
|
||
SUCCESS=0
|
||
FAILED=0
|
||
|
||
for host_id in "${!PROXY_HOSTS[@]}"; do
|
||
IFS='|' read -r domain target_ip target_port canonical_https _ <<< "${PROXY_HOSTS[$host_id]}"
|
||
|
||
if update_proxy_host "$host_id" "$domain" "$target_ip" "$target_port" "$canonical_https"; then
|
||
((SUCCESS++))
|
||
else
|
||
((FAILED++))
|
||
fi
|
||
echo ""
|
||
done
|
||
|
||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
echo "📊 Update Summary"
|
||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
echo "✅ Successfully updated: $SUCCESS"
|
||
echo "❌ Failed: $FAILED"
|
||
echo ""
|
||
|
||
if [ $FAILED -eq 0 ]; then
|
||
echo "🎉 All proxy hosts updated successfully!"
|
||
exit 0
|
||
else
|
||
echo "⚠️ Some proxy hosts failed to update"
|
||
exit 1
|
||
fi
|