NPM: canonical 301 for www sankofa/phoenix/the-order; E2E pass on 301/308
- update-npmplus-proxy-hosts-api.sh: optional advanced_config 301 via 5th/6th args; wire www.the-order → https://the-order.sankofa.nexus; document OSJ portal and the_order repo path - update-sankofa-npmplus-proxy-hosts.sh: same 301 for www rows via 4th pipe field - verify-end-to-end-routing.sh: www.the-order in inventory; treat 301/308 as HTTPS pass for www.sankofa, www.phoenix, www.the-order - configure-npmplus-domains.js: comment — avoid duplicate redirection UI rows for Sankofa www - AGENTS.md, ALL_VMIDS_ENDPOINTS.md, E2E_ENDPOINTS_LIST.md: Order portal and www redirect notes Made-with: Cursor
This commit is contained in:
@@ -69,9 +69,8 @@ const DOMAINS = [
|
||||
|
||||
// www.* domains that redirect to parent domains
|
||||
const REDIRECT_DOMAINS = [
|
||||
// REMOVED: Sankofa redirects - services not deployed
|
||||
// { domain: 'www.sankofa.nexus', redirectTo: 'sankofa.nexus' },
|
||||
// { domain: 'www.phoenix.sankofa.nexus', redirectTo: 'phoenix.sankofa.nexus' },
|
||||
// Sankofa www → apex: use scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh (301 via proxy host advanced_config).
|
||||
// Do not add duplicate NPM "Redirection Host" rows for www.sankofa / www.phoenix here while those names are proxy hosts with LE certs.
|
||||
{ domain: 'www.mim4u.org', redirectTo: 'mim4u.org' },
|
||||
];
|
||||
|
||||
|
||||
@@ -3,21 +3,17 @@
|
||||
# Auth failures: only a short error message is printed by default. For a redacted JSON snippet set NPM_DEBUG_AUTH=1.
|
||||
set -euo pipefail
|
||||
|
||||
# Load IP configuration
|
||||
# Repo root (…/proxmox) — same as second block below; load IPs once from the right path
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
|
||||
# Update existing NPMplus proxy hosts via API with correct VMIDs and IPs
|
||||
# This script updates existing proxy hosts, not creates new ones.
|
||||
# PUT payload includes only forward_* / websocket / block_exploits — existing certificate_id and ssl_forced are preserved by NPMplus.
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
# Preserve NPM credentials from environment so "export NPM_PASSWORD=...; ./script" works
|
||||
_orig_npm_url="${NPM_URL:-}"
|
||||
_orig_npm_email="${NPM_EMAIL:-}"
|
||||
@@ -58,11 +54,12 @@ echo ""
|
||||
|
||||
# NPMplus API can stall indefinitely without --max-time (override e.g. NPM_CURL_MAX_TIME=300)
|
||||
NPM_CURL_MAX_TIME="${NPM_CURL_MAX_TIME:-120}"
|
||||
curl_npm() { curl -s -k --connect-timeout 10 --max-time "$NPM_CURL_MAX_TIME" "$@"; }
|
||||
# -L: port 81 often 301s HTTP→HTTPS; POST /api/tokens without -L returns 400 "Payload is undefined"
|
||||
curl_npm() { curl -s -k -L --connect-timeout 10 --max-time "$NPM_CURL_MAX_TIME" "$@"; }
|
||||
|
||||
# Connection check (NPMplus is on LAN 192.168.11.x). Try HTTP if HTTPS fails; try alternate IP .166/.167 if unreachable.
|
||||
echo "🔐 Authenticating to NPMplus..."
|
||||
try_connect() { curl -s -k -o /dev/null --connect-timeout 5 --max-time 15 "$1" 2>/dev/null; }
|
||||
try_connect() { curl -s -k -L -o /dev/null --connect-timeout 5 --max-time 15 "$1" 2>/dev/null; }
|
||||
if ! try_connect "$NPM_URL/"; then
|
||||
# Try HTTP instead of HTTPS (NPM admin often listens on HTTP only on port 81)
|
||||
http_url="${NPM_URL/https:/http:}"
|
||||
@@ -73,7 +70,7 @@ if ! try_connect "$NPM_URL/"; then
|
||||
alt_url=""
|
||||
if [[ "$NPM_URL" == *"${IP_NPMPLUS_ETH0}"* ]]; then
|
||||
alt_url="https://${IP_NPMPLUS}:81"
|
||||
elif [[ "$NPM_URL" == *"${IP_NPMPLUS}"* ]] || [[ "$NPM_URL" == *"${IP_NPMPLUS_ETH1}"* ]]; then
|
||||
elif [[ "$NPM_URL" == *"${IP_NPMPLUS}"* ]] || [[ -n "${IP_NPMPLUS_ETH1:-}" && "$NPM_URL" == *"${IP_NPMPLUS_ETH1}"* ]]; then
|
||||
alt_url="https://${IP_NPMPLUS_ETH0}:81"
|
||||
fi
|
||||
connected=""
|
||||
@@ -135,12 +132,18 @@ resolve_proxy_host_id() {
|
||||
}
|
||||
|
||||
# Function to add proxy host (POST) when domain does not exist
|
||||
# Optional 6th arg: canonical HTTPS apex for www-style hosts (sets advanced_config 301 → apex$request_uri)
|
||||
add_proxy_host() {
|
||||
local domain=$1
|
||||
local forward_host=$2
|
||||
local forward_port=$3
|
||||
local websocket=$4
|
||||
local block_exploits=${5:-false}
|
||||
local canonical_https="${6:-}"
|
||||
local adv_line=""
|
||||
if [ -n "$canonical_https" ]; then
|
||||
adv_line="return 301 ${canonical_https}\$request_uri;"
|
||||
fi
|
||||
local payload
|
||||
payload=$(jq -n \
|
||||
--arg domain "$domain" \
|
||||
@@ -148,6 +151,7 @@ add_proxy_host() {
|
||||
--argjson port "$forward_port" \
|
||||
--argjson ws "$websocket" \
|
||||
--argjson block_exploits "$([ "$block_exploits" = "true" ] && echo true || echo false)" \
|
||||
--arg adv "$adv_line" \
|
||||
'{
|
||||
domain_names: [$domain],
|
||||
forward_scheme: "http",
|
||||
@@ -157,7 +161,7 @@ add_proxy_host() {
|
||||
block_exploits: $block_exploits,
|
||||
certificate_id: null,
|
||||
ssl_forced: false
|
||||
}' 2>/dev/null)
|
||||
} + (if $adv != "" then {advanced_config: $adv} else {} end)' 2>/dev/null)
|
||||
if [ -z "$payload" ]; then
|
||||
echo " ❌ Failed to build payload for $domain"
|
||||
return 1
|
||||
@@ -180,7 +184,7 @@ add_proxy_host() {
|
||||
echo " ↪ Host likely exists; refreshing list and attempting PUT update..."
|
||||
PROXY_HOSTS_JSON=$(curl_npm -X GET "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
if update_proxy_host "$domain" "http://${forward_host}:${forward_port}" "$websocket" "$block_exploits"; then
|
||||
if update_proxy_host "$domain" "http://${forward_host}:${forward_port}" "$websocket" "$block_exploits" "$canonical_https"; then
|
||||
echo " ✅ Updated after duplicate-create error: $domain"
|
||||
return 0
|
||||
fi
|
||||
@@ -191,11 +195,13 @@ add_proxy_host() {
|
||||
|
||||
# Function to update proxy host
|
||||
# block_exploits: set false for RPC hosts (JSON-RPC uses POST to /; block_exploits can cause 405)
|
||||
# Optional 5th arg: canonical HTTPS URL (no path) — sets advanced_config to 301 redirect (www → apex)
|
||||
update_proxy_host() {
|
||||
local domain=$1
|
||||
local target=$2
|
||||
local websocket=$3
|
||||
local block_exploits=${4:-true}
|
||||
local canonical_https="${5:-}"
|
||||
|
||||
# Parse target URL
|
||||
local scheme=$(echo "$target" | sed -E 's|^([^:]+):.*|\1|')
|
||||
@@ -208,6 +214,17 @@ update_proxy_host() {
|
||||
hostname=$(echo "$target" | sed -E 's|^https://([^:]+):.*|\1|')
|
||||
port=$(echo "$target" | sed -E 's|^https://[^:]+:([0-9]+).*|\1|' || echo "443")
|
||||
fi
|
||||
|
||||
# Reject bad parses (e.g. https://:443 when forward IP env is empty) — NPM returns errors without .id and jq message is empty.
|
||||
if [[ -z "$hostname" || "$hostname" == *"://"* || "$hostname" == *"/"* ]]; then
|
||||
echo " ❌ Invalid forward target for $domain (check env / ip-addresses.conf): $target → host=[$hostname]"
|
||||
return 1
|
||||
fi
|
||||
port="${port//[^0-9]/}"
|
||||
if [[ -z "$port" || "$port" -lt 1 || "$port" -gt 65535 ]]; then
|
||||
echo " ❌ Invalid forward port for $domain: $target (parsed port=$port)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Get host ID (case-insensitive); refresh once if missing (stale list / race with other writers)
|
||||
HOST_ID=$(resolve_proxy_host_id "$domain" "$PROXY_HOSTS_JSON")
|
||||
@@ -228,19 +245,24 @@ update_proxy_host() {
|
||||
# block_exploits must be false for RPC so POST to / is allowed (JSON-RPC); explicit false fixes 405
|
||||
local be_json="false"
|
||||
[ "$block_exploits" = "true" ] && be_json="true"
|
||||
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 "$hostname" \
|
||||
--argjson port "$(echo "$port" | sed 's/[^0-9]//g' || echo "80")" \
|
||||
--argjson websocket "$websocket" \
|
||||
--argjson block_exploits "$be_json" \
|
||||
--arg adv "$adv_line" \
|
||||
'{
|
||||
forward_scheme: $scheme,
|
||||
forward_host: $hostname,
|
||||
forward_port: $port,
|
||||
allow_websocket_upgrade: $websocket,
|
||||
block_exploits: $block_exploits
|
||||
}' 2>/dev/null || echo "")
|
||||
} + (if $adv != "" then {advanced_config: $adv} else {} end)' 2>/dev/null || echo "")
|
||||
|
||||
UPDATE_RESPONSE=$(curl_npm -X PUT "$NPM_URL/api/nginx/proxy-hosts/$HOST_ID" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
@@ -250,10 +272,16 @@ update_proxy_host() {
|
||||
UPDATE_ID=$(echo "$UPDATE_RESPONSE" | jq -r '.id // empty' 2>/dev/null || echo "")
|
||||
|
||||
if [ -n "$UPDATE_ID" ] && [ "$UPDATE_ID" != "null" ]; then
|
||||
echo " ✅ Updated: $scheme://$hostname:$port (WebSocket: $websocket)"
|
||||
if [ -n "$canonical_https" ]; then
|
||||
echo " ✅ Updated: $scheme://$hostname:$port (WebSocket: $websocket) + 301 → ${canonical_https}\$request_uri"
|
||||
else
|
||||
echo " ✅ Updated: $scheme://$hostname:$port (WebSocket: $websocket)"
|
||||
fi
|
||||
return 0
|
||||
else
|
||||
ERROR=$(echo "$UPDATE_RESPONSE" | jq -r '.error.message // .error // "Unknown error"' 2>/dev/null || echo "$UPDATE_RESPONSE")
|
||||
ERROR=$(echo "$UPDATE_RESPONSE" | jq -r '.error.message // .message // .error // empty' 2>/dev/null || echo "")
|
||||
[ -z "$ERROR" ] && ERROR=$(echo "$UPDATE_RESPONSE" | head -c 400 | tr -d '\r\n')
|
||||
[ -z "$ERROR" ] && ERROR="(empty API response — timeout or connection error; try NPM_CURL_MAX_TIME=300)"
|
||||
echo " ❌ Failed: $ERROR"
|
||||
return 1
|
||||
fi
|
||||
@@ -280,7 +308,9 @@ update_proxy_host "wss.tw-core.d-bis.org" "http://${RPC_THIRDWEB_ADMIN_CORE}:854
|
||||
# Catch-all for foo.tw-core.d-bis.org → Besu HTTP JSON-RPC :8545 (exact rpc./wss. hosts above take precedence for nginx server_name)
|
||||
update_proxy_host '*.tw-core.d-bis.org' "http://${RPC_THIRDWEB_ADMIN_CORE}:8545" true false && updated_count=$((updated_count + 1)) || { add_proxy_host '*.tw-core.d-bis.org' "${RPC_THIRDWEB_ADMIN_CORE}" 8545 true false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
# RPC Core-2 (Nathan) is on the THIRD NPMplus (192.168.11.169) — use add-rpc-core-2-npmplus-proxy.sh and update-npmplus-alltra-hybx-proxy-hosts.sh
|
||||
update_proxy_host "rpc.public-0138.defi-oracle.io" "https://${RPC_THIRDWEB_PRIMARY}:443" true false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
# ThirdWeb / public-0138 edge (VMID 2400 nginx HTTPS) — default IP must match ALL_VMIDS_ENDPOINTS if env is unset
|
||||
RPC_THIRDWEB_PRIMARY="${RPC_THIRDWEB_PRIMARY:-192.168.11.240}"
|
||||
update_proxy_host "rpc.public-0138.defi-oracle.io" "https://${RPC_THIRDWEB_PRIMARY}:443" true false && updated_count=$((updated_count + 1)) || { sleep 2; echo " ↪ Retry rpc.public-0138.defi-oracle.io after transient NPM/API error..."; update_proxy_host "rpc.public-0138.defi-oracle.io" "https://${RPC_THIRDWEB_PRIMARY}:443" true false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1)); }
|
||||
# rpc.defi-oracle.io / wss.defi-oracle.io → same backend as rpc-http-pub / rpc-ws-pub (VMID 2201)
|
||||
update_proxy_host "rpc.defi-oracle.io" "http://${RPC_PUBLIC_1}:8545" true false && updated_count=$((updated_count + 1)) || { add_proxy_host "rpc.defi-oracle.io" "${RPC_PUBLIC_1}" 8545 true false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "wss.defi-oracle.io" "http://${RPC_PUBLIC_1}:8546" true false && updated_count=$((updated_count + 1)) || { add_proxy_host "wss.defi-oracle.io" "${RPC_PUBLIC_1}" 8546 true false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
@@ -309,6 +339,34 @@ update_proxy_host "dbis.xom-dev.phoenix.sankofa.nexus" "http://${IP_GOV_PORTALS_
|
||||
update_proxy_host "iccc.xom-dev.phoenix.sankofa.nexus" "http://${IP_GOV_PORTALS_DEV}:3002" false && updated_count=$((updated_count + 1)) || { add_proxy_host "iccc.xom-dev.phoenix.sankofa.nexus" "${IP_GOV_PORTALS_DEV}" 3002 false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "omnl.xom-dev.phoenix.sankofa.nexus" "http://${IP_GOV_PORTALS_DEV}:3003" false && updated_count=$((updated_count + 1)) || { add_proxy_host "omnl.xom-dev.phoenix.sankofa.nexus" "${IP_GOV_PORTALS_DEV}" 3003 false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "xom.xom-dev.phoenix.sankofa.nexus" "http://${IP_GOV_PORTALS_DEV}:3004" false && updated_count=$((updated_count + 1)) || { add_proxy_host "xom.xom-dev.phoenix.sankofa.nexus" "${IP_GOV_PORTALS_DEV}" 3004 false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
# Sankofa portal (Next.js CT 7801) and Phoenix API (Fastify CT 7800) — not Blockscout / SolaceScanScout (that is explorer.d-bis.org / IP_BLOCKSCOUT:80)
|
||||
# Public URL policy: https://sankofa.nexus = sovereign technology utility (portal); https://phoenix.sankofa.nexus = Phoenix division (API host; marketing site may share hostname later).
|
||||
# www.sankofa.nexus → 301 https://sankofa.nexus$request_uri; www.phoenix → phoenix; www.the-order → the-order (NPM advanced_config).
|
||||
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}"
|
||||
update_proxy_host "sankofa.nexus" "http://${IP_SANKOFA_PORTAL}:${SANKOFA_PORTAL_PORT}" false false && updated_count=$((updated_count + 1)) || { add_proxy_host "sankofa.nexus" "${IP_SANKOFA_PORTAL}" "${SANKOFA_PORTAL_PORT}" false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "www.sankofa.nexus" "http://${IP_SANKOFA_PORTAL}:${SANKOFA_PORTAL_PORT}" false false "https://sankofa.nexus" && updated_count=$((updated_count + 1)) || { add_proxy_host "www.sankofa.nexus" "${IP_SANKOFA_PORTAL}" "${SANKOFA_PORTAL_PORT}" false false "https://sankofa.nexus" && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "phoenix.sankofa.nexus" "http://${IP_SANKOFA_PHOENIX_API}:${SANKOFA_PHOENIX_API_PORT}" false false && updated_count=$((updated_count + 1)) || { add_proxy_host "phoenix.sankofa.nexus" "${IP_SANKOFA_PHOENIX_API}" "${SANKOFA_PHOENIX_API_PORT}" false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "www.phoenix.sankofa.nexus" "http://${IP_SANKOFA_PHOENIX_API}:${SANKOFA_PHOENIX_API_PORT}" false false "https://phoenix.sankofa.nexus" && updated_count=$((updated_count + 1)) || { add_proxy_host "www.phoenix.sankofa.nexus" "${IP_SANKOFA_PHOENIX_API}" "${SANKOFA_PHOENIX_API_PORT}" false false "https://phoenix.sankofa.nexus" && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
# Keycloak (CT 7802) — portal SSO; NPM must forward X-Forwarded-* (Keycloak KC_PROXY_HEADERS=xforwarded on upstream)
|
||||
IP_KEYCLOAK="${IP_KEYCLOAK:-192.168.11.52}"
|
||||
update_proxy_host "keycloak.sankofa.nexus" "http://${IP_KEYCLOAK}:8080" false false && updated_count=$((updated_count + 1)) || { add_proxy_host "keycloak.sankofa.nexus" "${IP_KEYCLOAK}" 8080 false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
# the-order.sankofa.nexus — public hostname for the Sovereign Military Order of Malta (OSJ) management portal (secure auth).
|
||||
# Application source (operator workstation): repo the_order at ~/projects/the_order (e.g. /home/intlc/projects/the_order).
|
||||
# Ideal upstream: VMID 10210 order-haproxy @ IP_ORDER_HAPROXY:80. When HAProxy/order edge is not serving, NPM may 502.
|
||||
# Interim default: same Next.js upstream as sankofa.nexus (7801). Switch: THE_ORDER_UPSTREAM_IP=192.168.11.39 THE_ORDER_UPSTREAM_PORT=80.
|
||||
# www.the-order.sankofa.nexus → 301 https://the-order.sankofa.nexus$request_uri (same pattern as www.sankofa / www.phoenix).
|
||||
IP_ORDER_HAPROXY="${IP_ORDER_HAPROXY:-192.168.11.39}"
|
||||
THE_ORDER_UPSTREAM_IP="${THE_ORDER_UPSTREAM_IP:-${IP_SANKOFA_PORTAL}}"
|
||||
THE_ORDER_UPSTREAM_PORT="${THE_ORDER_UPSTREAM_PORT:-${SANKOFA_PORTAL_PORT}}"
|
||||
update_proxy_host "the-order.sankofa.nexus" "http://${THE_ORDER_UPSTREAM_IP}:${THE_ORDER_UPSTREAM_PORT}" false && updated_count=$((updated_count + 1)) || { add_proxy_host "the-order.sankofa.nexus" "${THE_ORDER_UPSTREAM_IP}" "${THE_ORDER_UPSTREAM_PORT}" false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "www.the-order.sankofa.nexus" "http://${THE_ORDER_UPSTREAM_IP}:${THE_ORDER_UPSTREAM_PORT}" false false "https://the-order.sankofa.nexus" && updated_count=$((updated_count + 1)) || { add_proxy_host "www.the-order.sankofa.nexus" "${THE_ORDER_UPSTREAM_IP}" "${THE_ORDER_UPSTREAM_PORT}" false false "https://the-order.sankofa.nexus" && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
# Sankofa Studio (FusionAI) — VMID 7805; UI at /studio/ on same origin (port 8000). Prefer IP_SANKOFA_STUDIO from ip-addresses.conf / .env
|
||||
IP_SANKOFA_STUDIO="${IP_SANKOFA_STUDIO:-192.168.11.72}"
|
||||
SANKOFA_STUDIO_PORT="${SANKOFA_STUDIO_PORT:-8000}"
|
||||
update_proxy_host "studio.sankofa.nexus" "http://${IP_SANKOFA_STUDIO}:${SANKOFA_STUDIO_PORT}" false && updated_count=$((updated_count + 1)) || { add_proxy_host "studio.sankofa.nexus" "${IP_SANKOFA_STUDIO}" "${SANKOFA_STUDIO_PORT}" false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
|
||||
Reference in New Issue
Block a user