Sync workspace: config, docs, scripts, CI, operator rules, and submodule pointers.
- Update dbis_core, cross-chain-pmm-lps, explorer-monorepo, metamask-integration, pr-workspace/chains - Omit embedded publish git dirs and empty placeholders from index Made-with: Cursor
This commit is contained in:
@@ -18,19 +18,75 @@ NPM_URL="${NPM_URL:-https://192.168.11.167:81}"
|
||||
|
||||
[ -z "$NPM_PASSWORD" ] && echo "Set NPM_PASSWORD (e.g. source .env)" && exit 1
|
||||
|
||||
# Remote script: no jq required (Proxmox host may not have it)
|
||||
# Remote script: use Python's JSON parser so reruns are idempotent and preserve cert / Force SSL state.
|
||||
REMOTE_SCRIPT='
|
||||
set -euo pipefail
|
||||
[ -z "${NPM_PASSWORD:-}" ] && echo "NPM_PASSWORD not set on remote" && exit 1
|
||||
AUTH_JSON="{\"identity\":\"$NPM_EMAIL\",\"secret\":\"$NPM_PASSWORD\"}"
|
||||
TOKEN_RESP=$(curl -sk -X POST "$NPM_URL/api/tokens" -H "Content-Type: application/json" -d "$AUTH_JSON")
|
||||
TOKEN=$(echo "$TOKEN_RESP" | sed -n "s/.*\"token\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" | head -1)
|
||||
[ -z "$TOKEN" ] && TOKEN=$(echo "$TOKEN_RESP" | sed -n "s/.*\"accessToken\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" | head -1)
|
||||
[ -z "$TOKEN" ] && echo "Auth failed. Response: $TOKEN_RESP" && exit 1
|
||||
BODY="{\"domain_names\":[\"dapp.d-bis.org\"],\"forward_scheme\":\"http\",\"forward_host\":\"$DAPP_IP\",\"forward_port\":80,\"allow_websocket_upgrade\":true,\"certificate_id\":null,\"ssl_forced\":false}"
|
||||
resp=$(curl -sk -X POST "$NPM_URL/api/nginx/proxy-hosts" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$BODY")
|
||||
if echo "$resp" | grep -q "\"id\""; then echo "Added: dapp.d-bis.org -> $DAPP_IP:80"; else echo "Create failed: $resp"; exit 1; fi
|
||||
echo "Request SSL in NPMplus UI for dapp.d-bis.org and enable Force SSL."
|
||||
python3 - <<'"'"'PY'"'"'
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
def curl(*args):
|
||||
return subprocess.check_output(["curl", "-skS", *args], text=True)
|
||||
|
||||
npm_password = os.environ.get("NPM_PASSWORD", "")
|
||||
if not npm_password:
|
||||
print("NPM_PASSWORD not set on remote")
|
||||
sys.exit(1)
|
||||
|
||||
auth_payload = json.dumps({
|
||||
"identity": os.environ.get("NPM_EMAIL", "admin@example.org"),
|
||||
"secret": npm_password,
|
||||
})
|
||||
token_resp = json.loads(curl("-X", "POST", f"{os.environ['NPM_URL']}/api/tokens", "-H", "Content-Type: application/json", "-d", auth_payload))
|
||||
token = token_resp.get("token") or token_resp.get("accessToken") or (token_resp.get("data") or {}).get("token")
|
||||
if not token:
|
||||
print(f"Auth failed. Response: {json.dumps(token_resp)}")
|
||||
sys.exit(1)
|
||||
|
||||
auth_header = ["-H", f"Authorization: Bearer {token}"]
|
||||
hosts_resp = json.loads(curl("-X", "GET", f"{os.environ['NPM_URL']}/api/nginx/proxy-hosts", *auth_header))
|
||||
if isinstance(hosts_resp, dict):
|
||||
hosts = hosts_resp.get("data") or hosts_resp.get("proxy_hosts") or []
|
||||
else:
|
||||
hosts = hosts_resp
|
||||
|
||||
existing = None
|
||||
for host in hosts:
|
||||
if "dapp.d-bis.org" in (host.get("domain_names") or []):
|
||||
existing = host
|
||||
break
|
||||
|
||||
payload = {
|
||||
"domain_names": ["dapp.d-bis.org"],
|
||||
"forward_scheme": "http",
|
||||
"forward_host": os.environ["DAPP_IP"],
|
||||
"forward_port": 80,
|
||||
"allow_websocket_upgrade": True,
|
||||
"block_exploits": False,
|
||||
}
|
||||
|
||||
if existing:
|
||||
payload["certificate_id"] = existing.get("certificate_id")
|
||||
payload["ssl_forced"] = existing.get("ssl_forced", False)
|
||||
resp = json.loads(curl("-X", "PUT", f"{os.environ['NPM_URL']}/api/nginx/proxy-hosts/{existing['id']}", *auth_header, "-H", "Content-Type: application/json", "-d", json.dumps(payload)))
|
||||
if resp.get("id"):
|
||||
print(f"Updated: dapp.d-bis.org -> {os.environ['DAPP_IP']}:80")
|
||||
sys.exit(0)
|
||||
print(f"Update failed: {json.dumps(resp)}")
|
||||
sys.exit(1)
|
||||
|
||||
payload["certificate_id"] = None
|
||||
payload["ssl_forced"] = False
|
||||
resp = json.loads(curl("-X", "POST", f"{os.environ['NPM_URL']}/api/nginx/proxy-hosts", *auth_header, "-H", "Content-Type: application/json", "-d", json.dumps(payload)))
|
||||
if resp.get("id"):
|
||||
print(f"Added: dapp.d-bis.org -> {os.environ['DAPP_IP']}:80")
|
||||
print("Request SSL in NPMplus UI for dapp.d-bis.org and enable Force SSL if this is a new host.")
|
||||
sys.exit(0)
|
||||
print(f"Create failed: {json.dumps(resp)}")
|
||||
sys.exit(1)
|
||||
PY
|
||||
'
|
||||
|
||||
echo "Running NPM add proxy host from Proxmox host $PROXMOX_HOST (must be on same LAN as NPMplus 192.168.11.167)..."
|
||||
@@ -39,7 +95,7 @@ PASS_ESC="${NPM_PASSWORD//\'/\'\\\'\'}"
|
||||
OUTPUT=$(ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new root@"$PROXMOX_HOST" \
|
||||
"export NPM_EMAIL='${NPM_EMAIL//\'/\'\\\'\'}' NPM_PASSWORD='$PASS_ESC' NPM_URL='$NPM_URL' DAPP_IP='$DAPP_IP'; bash -s" <<< "$REMOTE_SCRIPT" 2>&1) || true
|
||||
echo "$OUTPUT"
|
||||
if ! echo "$OUTPUT" | grep -q "Added: dapp.d-bis.org"; then
|
||||
if ! echo "$OUTPUT" | grep -qE "Added: dapp.d-bis.org|Updated: dapp.d-bis.org"; then
|
||||
echo "Failed. Ensure this machine can SSH to $PROXMOX_HOST and that host can reach $NPM_URL (same LAN)." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -17,9 +17,27 @@ AUTH_JSON=$(jq -n --arg identity "$NPM_EMAIL" --arg secret "$NPM_PASSWORD" '{ide
|
||||
TOKEN_RESP=$(curl -sk -X POST "$NPM_URL/api/tokens" -H "Content-Type: application/json" -d "$AUTH_JSON" -c "$COOKIE_JAR")
|
||||
TOKEN=$(echo "$TOKEN_RESP" | jq -r '.token // .accessToken // .data.token // empty')
|
||||
if [ -z "$TOKEN" ]; then echo "Auth failed"; echo "$TOKEN_RESP" | jq . 2>/dev/null; exit 1; fi
|
||||
PROXY_HOSTS_JSON=$(curl -sk -X GET "$NPM_URL/api/nginx/proxy-hosts" -H "Authorization: Bearer $TOKEN")
|
||||
HOSTS_ARRAY=$(echo "$PROXY_HOSTS_JSON" | jq -c 'if type == "array" then . elif .data != null then .data elif .proxy_hosts != null then .proxy_hosts else [] end' 2>/dev/null)
|
||||
EXISTING_ID=$(echo "$HOSTS_ARRAY" | jq -r '.[] | select(.domain_names[]? == "dapp.d-bis.org") | .id' 2>/dev/null | head -1)
|
||||
EXISTING_HOST_JSON=$(echo "$HOSTS_ARRAY" | jq -c '.[] | select(.domain_names[]? == "dapp.d-bis.org")' 2>/dev/null | head -1)
|
||||
if [ -n "$EXISTING_ID" ] && [ "$EXISTING_ID" != "null" ]; then
|
||||
PRESERVED_CERTIFICATE_ID=$(printf '%s' "$EXISTING_HOST_JSON" | jq -c '.certificate_id // null' 2>/dev/null || echo "null")
|
||||
PRESERVED_SSL_FORCED=$(printf '%s' "$EXISTING_HOST_JSON" | jq -c '.ssl_forced // false' 2>/dev/null || echo "false")
|
||||
BODY=$(jq -n --arg domain "dapp.d-bis.org" --arg host "$DAPP_IP" --argjson port 80 --argjson certificate_id "$PRESERVED_CERTIFICATE_ID" --argjson ssl_forced "$PRESERVED_SSL_FORCED" \
|
||||
'{domain_names:[$domain],forward_scheme:"http",forward_host:$host,forward_port:$port,allow_websocket_upgrade:true,block_exploits:false,certificate_id:$certificate_id,ssl_forced:$ssl_forced}')
|
||||
resp=$(curl -sk -X PUT "$NPM_URL/api/nginx/proxy-hosts/$EXISTING_ID" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$BODY")
|
||||
id=$(echo "$resp" | jq -r '.id // empty')
|
||||
if [ -n "$id" ] && [ "$id" != "null" ]; then
|
||||
echo "Updated: dapp.d-bis.org -> $DAPP_IP:80"
|
||||
exit 0
|
||||
fi
|
||||
echo "$resp" | jq . 2>/dev/null
|
||||
exit 1
|
||||
fi
|
||||
BODY=$(jq -n --arg domain "dapp.d-bis.org" --arg host "$DAPP_IP" --argjson port 80 \
|
||||
'{domain_names:[$domain],forward_scheme:"http",forward_host:$host,forward_port:$port,allow_websocket_upgrade:true,certificate_id:null,ssl_forced:false}')
|
||||
'{domain_names:[$domain],forward_scheme:"http",forward_host:$host,forward_port:$port,allow_websocket_upgrade:true,block_exploits:false,certificate_id:null,ssl_forced:false}')
|
||||
resp=$(curl -sk -X POST "$NPM_URL/api/nginx/proxy-hosts" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$BODY")
|
||||
id=$(echo "$resp" | jq -r '.id // empty')
|
||||
if [ -n "$id" ]; then echo "Added: dapp.d-bis.org -> $DAPP_IP:80"; else echo "$resp" | jq . 2>/dev/null; exit 1; fi
|
||||
echo "Request SSL in NPMplus UI for dapp.d-bis.org and enable Force SSL."
|
||||
echo "Request SSL in NPMplus UI for dapp.d-bis.org and enable Force SSL if this is a new host."
|
||||
|
||||
@@ -57,6 +57,27 @@ curl_auth() {
|
||||
fi
|
||||
}
|
||||
|
||||
fetch_proxy_hosts_json() {
|
||||
curl_auth -X GET "$NPM_URL/api/nginx/proxy-hosts"
|
||||
}
|
||||
|
||||
resolve_proxy_host_id() {
|
||||
local domain=$1
|
||||
local hosts_json=${2:-}
|
||||
[ -z "$hosts_json" ] && hosts_json=$(fetch_proxy_hosts_json)
|
||||
echo "$hosts_json" | jq -r --arg dom "$domain" '
|
||||
if type == "array" then .
|
||||
elif .data != null then .data
|
||||
elif .proxy_hosts != null then .proxy_hosts
|
||||
else []
|
||||
end
|
||||
| .[]
|
||||
| select(.domain_names | type == "array")
|
||||
| select(.domain_names[] == $dom)
|
||||
| .id
|
||||
' 2>/dev/null | head -n1
|
||||
}
|
||||
|
||||
add_proxy_host() {
|
||||
local domain=$1
|
||||
local fwd_port=$2
|
||||
@@ -90,11 +111,96 @@ add_proxy_host() {
|
||||
fi
|
||||
}
|
||||
|
||||
update_proxy_host() {
|
||||
local domain=$1
|
||||
local fwd_port=$2
|
||||
local hosts_json
|
||||
hosts_json=$(fetch_proxy_hosts_json)
|
||||
local arr
|
||||
arr=$(echo "$hosts_json" | jq -c '
|
||||
if type == "array" then .
|
||||
elif .data != null then .data
|
||||
elif .proxy_hosts != null then .proxy_hosts
|
||||
else []
|
||||
end
|
||||
' 2>/dev/null)
|
||||
[ -z "$arr" ] && return 1
|
||||
local id
|
||||
id=$(echo "$arr" | jq -r --arg dom "$domain" '
|
||||
.[]
|
||||
| select(.domain_names | type == "array")
|
||||
| select(.domain_names[] == $dom)
|
||||
| .id
|
||||
' 2>/dev/null | head -n1)
|
||||
if [ -z "$id" ] || [ "$id" = "null" ]; then
|
||||
return 1
|
||||
fi
|
||||
local payload
|
||||
payload=$(jq -n \
|
||||
--arg host "$IP_GOV_PORTALS_DEV" \
|
||||
--argjson port "$fwd_port" \
|
||||
'{ forward_scheme: "http", forward_host: $host, forward_port: $port, allow_websocket_upgrade: false, block_exploits: false }')
|
||||
local resp
|
||||
resp=$(curl_auth -X PUT "$NPM_URL/api/nginx/proxy-hosts/$id" -H "Content-Type: application/json" -d "$payload")
|
||||
local out_id
|
||||
out_id=$(echo "$resp" | jq -r '.id // empty' 2>/dev/null)
|
||||
if [ -n "$out_id" ] && [ "$out_id" != "null" ]; then
|
||||
echo " Updated: $domain -> $IP_GOV_PORTALS_DEV:$fwd_port"
|
||||
return 0
|
||||
fi
|
||||
local host_obj
|
||||
host_obj=$(echo "$arr" | jq -c --arg dom "$domain" '
|
||||
.[]
|
||||
| select(.domain_names | type == "array")
|
||||
| select(.domain_names[] == $dom)
|
||||
' 2>/dev/null | head -n1)
|
||||
if [ -n "$host_obj" ]; then
|
||||
payload=$(echo "$host_obj" | jq -c --arg host "$IP_GOV_PORTALS_DEV" --argjson port "$fwd_port" '
|
||||
{
|
||||
domain_names,
|
||||
forward_scheme,
|
||||
forward_host: $host,
|
||||
forward_port: $port,
|
||||
allow_websocket_upgrade,
|
||||
block_exploits,
|
||||
certificate_id,
|
||||
ssl_forced,
|
||||
caching_enabled,
|
||||
advanced_config,
|
||||
access_list_id,
|
||||
enabled,
|
||||
http2_support,
|
||||
hsts_enabled,
|
||||
hsts_subdomains
|
||||
}
|
||||
' 2>/dev/null)
|
||||
if [ -n "$payload" ]; then
|
||||
resp=$(curl_auth -X PUT "$NPM_URL/api/nginx/proxy-hosts/$id" -H "Content-Type: application/json" -d "$payload")
|
||||
out_id=$(echo "$resp" | jq -r '.id // empty' 2>/dev/null)
|
||||
if [ -n "$out_id" ] && [ "$out_id" != "null" ]; then
|
||||
echo " Updated: $domain -> $IP_GOV_PORTALS_DEV:$fwd_port"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
echo " Warning: could not update $domain via API."
|
||||
return 1
|
||||
}
|
||||
|
||||
add_or_update_proxy_host() {
|
||||
local domain=$1
|
||||
local fwd_port=$2
|
||||
if add_proxy_host "$domain" "$fwd_port"; then
|
||||
return 0
|
||||
fi
|
||||
update_proxy_host "$domain" "$fwd_port"
|
||||
}
|
||||
|
||||
# Four portals on xom-dev.phoenix.sankofa.nexus
|
||||
add_proxy_host "dbis.xom-dev.phoenix.sankofa.nexus" 3001 || true
|
||||
add_proxy_host "iccc.xom-dev.phoenix.sankofa.nexus" 3002 || true
|
||||
add_proxy_host "omnl.xom-dev.phoenix.sankofa.nexus" 3003 || true
|
||||
add_proxy_host "xom.xom-dev.phoenix.sankofa.nexus" 3004 || true
|
||||
add_or_update_proxy_host "dbis.xom-dev.phoenix.sankofa.nexus" 3001 || true
|
||||
add_or_update_proxy_host "iccc.xom-dev.phoenix.sankofa.nexus" 3002 || true
|
||||
add_or_update_proxy_host "omnl.xom-dev.phoenix.sankofa.nexus" 3003 || true
|
||||
add_or_update_proxy_host "xom.xom-dev.phoenix.sankofa.nexus" 3004 || true
|
||||
|
||||
echo ""
|
||||
echo "Done. Request Let's Encrypt certs in NPMplus UI for: dbis/iccc/omnl/xom.xom-dev.phoenix.sankofa.nexus"
|
||||
|
||||
@@ -40,13 +40,18 @@ fi
|
||||
|
||||
PROXY_HOSTS_JSON=$(curl -s -k -X GET "$NPM_URL/api/nginx/proxy-hosts" -H "Authorization: Bearer $TOKEN")
|
||||
EXISTING_ID=$(echo "$PROXY_HOSTS_JSON" | jq -r ".[] | select(.domain_names[]? == \"$DOMAIN\") | .id" 2>/dev/null | head -1)
|
||||
EXISTING_HOST_JSON=$(echo "$PROXY_HOSTS_JSON" | jq -c ".[] | select(.domain_names[]? == \"$DOMAIN\")" 2>/dev/null | head -1)
|
||||
|
||||
if [ -n "$EXISTING_ID" ] && [ "$EXISTING_ID" != "null" ]; then
|
||||
echo "✓ Proxy host for $DOMAIN already exists (ID: $EXISTING_ID). Updating target to ${IP_SANKOFA_STUDIO}:${PORT}..."
|
||||
PRESERVED_CERTIFICATE_ID=$(printf '%s' "$EXISTING_HOST_JSON" | jq -c '.certificate_id // null' 2>/dev/null || echo "null")
|
||||
PRESERVED_SSL_FORCED=$(printf '%s' "$EXISTING_HOST_JSON" | jq -c '.ssl_forced // false' 2>/dev/null || echo "false")
|
||||
PAYLOAD=$(jq -n \
|
||||
--arg domain "$DOMAIN" \
|
||||
--arg host "$IP_SANKOFA_STUDIO" \
|
||||
--argjson port "$PORT" \
|
||||
--argjson certificate_id "$PRESERVED_CERTIFICATE_ID" \
|
||||
--argjson ssl_forced "$PRESERVED_SSL_FORCED" \
|
||||
'{
|
||||
domain_names: [$domain],
|
||||
forward_scheme: "http",
|
||||
@@ -54,15 +59,16 @@ if [ -n "$EXISTING_ID" ] && [ "$EXISTING_ID" != "null" ]; then
|
||||
forward_port: $port,
|
||||
allow_websocket_upgrade: false,
|
||||
block_exploits: false,
|
||||
certificate_id: null,
|
||||
ssl_forced: false
|
||||
certificate_id: $certificate_id,
|
||||
ssl_forced: $ssl_forced,
|
||||
advanced_config: ""
|
||||
}')
|
||||
RESP=$(curl -s -k -X PUT "$NPM_URL/api/nginx/proxy-hosts/$EXISTING_ID" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$PAYLOAD")
|
||||
if echo "$RESP" | jq -e '.id' >/dev/null 2>&1; then
|
||||
echo "✓ Updated $DOMAIN → http://${IP_SANKOFA_STUDIO}:${PORT}"
|
||||
echo "✓ Updated $DOMAIN → http://${IP_SANKOFA_STUDIO}:${PORT} (preserved certificate_id=${PRESERVED_CERTIFICATE_ID}, ssl_forced=${PRESERVED_SSL_FORCED})"
|
||||
else
|
||||
echo "❌ Update failed: $(echo "$RESP" | jq -r '.message // .error // "unknown"' 2>/dev/null)"
|
||||
exit 1
|
||||
@@ -80,7 +86,8 @@ else
|
||||
allow_websocket_upgrade: false,
|
||||
block_exploits: false,
|
||||
certificate_id: null,
|
||||
ssl_forced: false
|
||||
ssl_forced: false,
|
||||
advanced_config: ""
|
||||
}')
|
||||
RESP=$(curl -s -k -X POST "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
@@ -95,5 +102,5 @@ else
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
echo "Next: Request SSL in NPMplus UI for $DOMAIN and enable Force SSL."
|
||||
echo "Next: Request SSL in NPMplus UI for $DOMAIN and enable Force SSL if this is a new host."
|
||||
echo "DNS: Ensure studio.sankofa.nexus resolves (e.g. run scripts/cloudflare/add-studio-sankofa-dns.sh)."
|
||||
|
||||
@@ -36,10 +36,10 @@ const DOMAINS = [
|
||||
|
||||
// d-bis.org zone
|
||||
{ domain: 'explorer.d-bis.org', target: 'http://192.168.11.140:4000', description: 'Blockscout Explorer (Direct Route)' },
|
||||
{ domain: 'rpc-http-pub.d-bis.org', target: 'https://192.168.11.252:443', description: 'RPC HTTP Public' },
|
||||
{ domain: 'rpc-ws-pub.d-bis.org', target: 'https://192.168.11.252:443', description: 'RPC WebSocket Public' },
|
||||
{ domain: 'rpc-http-prv.d-bis.org', target: 'https://192.168.11.251:443', description: 'RPC HTTP Private' },
|
||||
{ domain: 'rpc-ws-prv.d-bis.org', target: 'https://192.168.11.251:443', description: 'RPC WebSocket Private' },
|
||||
{ domain: 'rpc-http-pub.d-bis.org', target: 'http://192.168.11.221:8545', description: 'RPC HTTP Public' },
|
||||
{ domain: 'rpc-ws-pub.d-bis.org', target: 'http://192.168.11.221:8546', description: 'RPC WebSocket Public' },
|
||||
{ domain: 'rpc-http-prv.d-bis.org', target: 'http://192.168.11.211:8545', description: 'RPC HTTP Private' },
|
||||
{ domain: 'rpc-ws-prv.d-bis.org', target: 'http://192.168.11.211:8546', description: 'RPC WebSocket Private' },
|
||||
{ domain: 'dbis-admin.d-bis.org', target: 'http://192.168.11.130:80', description: 'DBIS Admin' },
|
||||
{ domain: 'dbis-api.d-bis.org', target: 'http://192.168.11.155:3000', description: 'DBIS API' },
|
||||
{ domain: 'dbis-api-2.d-bis.org', target: 'http://192.168.11.156:3000', description: 'DBIS API 2' },
|
||||
@@ -53,7 +53,7 @@ const DOMAINS = [
|
||||
{ domain: 'training.mim4u.org', target: 'http://192.168.11.37:80', description: 'MIM4U Training' },
|
||||
|
||||
// defi-oracle.io zone
|
||||
{ domain: 'rpc.public-0138.defi-oracle.io', target: 'https://192.168.11.252:443', description: 'ThirdWeb RPC' },
|
||||
{ domain: 'rpc.public-0138.defi-oracle.io', target: 'https://192.168.11.240:443', description: 'ThirdWeb RPC' },
|
||||
];
|
||||
|
||||
// Helper functions
|
||||
|
||||
@@ -32,10 +32,10 @@ const DOMAINS = [
|
||||
|
||||
// d-bis.org zone
|
||||
{ domain: 'explorer.d-bis.org', target: 'http://192.168.11.140:4000', websocket: false },
|
||||
{ domain: 'rpc-http-pub.d-bis.org', target: 'https://192.168.11.252:443', websocket: true },
|
||||
{ domain: 'rpc-ws-pub.d-bis.org', target: 'https://192.168.11.252:443', websocket: true },
|
||||
{ domain: 'rpc-http-prv.d-bis.org', target: 'https://192.168.11.251:443', websocket: true },
|
||||
{ domain: 'rpc-ws-prv.d-bis.org', target: 'https://192.168.11.251:443', websocket: true },
|
||||
{ domain: 'rpc-http-pub.d-bis.org', target: 'http://192.168.11.221:8545', websocket: true },
|
||||
{ domain: 'rpc-ws-pub.d-bis.org', target: 'http://192.168.11.221:8546', websocket: true },
|
||||
{ domain: 'rpc-http-prv.d-bis.org', target: 'http://192.168.11.211:8545', websocket: true },
|
||||
{ domain: 'rpc-ws-prv.d-bis.org', target: 'http://192.168.11.211:8546', websocket: true },
|
||||
{ domain: 'dbis-admin.d-bis.org', target: 'http://192.168.11.130:80', websocket: false },
|
||||
{ domain: 'dbis-api.d-bis.org', target: 'http://192.168.11.155:3000', websocket: false },
|
||||
{ domain: 'dbis-api-2.d-bis.org', target: 'http://192.168.11.156:3000', websocket: false },
|
||||
@@ -49,7 +49,7 @@ const DOMAINS = [
|
||||
{ domain: 'training.mim4u.org', target: 'http://192.168.11.37:80', websocket: false },
|
||||
|
||||
// defi-oracle.io zone
|
||||
{ domain: 'rpc.public-0138.defi-oracle.io', target: 'https://192.168.11.252:443', websocket: true },
|
||||
{ domain: 'rpc.public-0138.defi-oracle.io', target: 'https://192.168.11.240:443', websocket: true },
|
||||
];
|
||||
|
||||
// Helper functions
|
||||
|
||||
428
scripts/nginx-proxy-manager/fix-npmplus-ssl-issues.sh
Executable file
428
scripts/nginx-proxy-manager/fix-npmplus-ssl-issues.sh
Executable file
@@ -0,0 +1,428 @@
|
||||
#!/usr/bin/env bash
|
||||
# Fix NPMplus SSL gaps reported by audit-npmplus-ssl-all-instances.sh (primary instance by default).
|
||||
# - Hosts with a cert but ssl_forced=false: enable Force SSL + HSTS only for non-RPC endpoints (see should_force_ssl).
|
||||
# - Hosts with no cert: request Let's Encrypt cert via NPM API, assign to host (ssl_forced per same rule).
|
||||
# - Hosts with expired certs: request a fresh cert (or reuse an already-valid one) and reassign it.
|
||||
# - Hosts bound to the wrong certificate: request/reuse a matching cert and reassign it.
|
||||
# Supports both JSON bearer-token auth and cookie-session auth returned by some
|
||||
# NPMplus UIs.
|
||||
# Skips: disabled hosts; domain names containing * (wildcard — request certs in UI); dry-run.
|
||||
#
|
||||
# Usage: bash scripts/nginx-proxy-manager/fix-npmplus-ssl-issues.sh [--dry-run]
|
||||
# Env: NPM_URL (default https://IP_NPMPLUS:81), NPM_EMAIL, NPM_PASSWORD, NPM_CURL_MAX_TIME
|
||||
# NPM_SSL_FIX_SLEEP_LE=5 seconds between LE certificate requests (default 5)
|
||||
set -euo pipefail
|
||||
|
||||
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
|
||||
|
||||
DRY_RUN=0
|
||||
for _a in "$@"; do [[ "$_a" == "--dry-run" ]] && DRY_RUN=1; done
|
||||
|
||||
_orig_npm_url="${NPM_URL:-}"
|
||||
_orig_npm_email="${NPM_EMAIL:-}"
|
||||
_orig_npm_password="${NPM_PASSWORD:-}"
|
||||
_orig_npm_instance_label="${NPM_INSTANCE_LABEL:-}"
|
||||
if [ -f "$PROJECT_ROOT/.env" ]; then
|
||||
set +u
|
||||
# shellcheck source=/dev/null
|
||||
source "$PROJECT_ROOT/.env"
|
||||
set -u
|
||||
fi
|
||||
[ -n "$_orig_npm_url" ] && NPM_URL="$_orig_npm_url"
|
||||
[ -n "$_orig_npm_email" ] && NPM_EMAIL="$_orig_npm_email"
|
||||
[ -n "$_orig_npm_password" ] && NPM_PASSWORD="$_orig_npm_password"
|
||||
[ -n "$_orig_npm_instance_label" ] && NPM_INSTANCE_LABEL="$_orig_npm_instance_label"
|
||||
# shellcheck source=/dev/null
|
||||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
NPM_URL="${NPM_URL:-https://${IP_NPMPLUS:-192.168.11.167}:81}"
|
||||
NPM_EMAIL="${NPM_EMAIL:-}"
|
||||
NPM_CURL_MAX_TIME="${NPM_CURL_MAX_TIME:-300}"
|
||||
NPM_SSL_FIX_SLEEP_LE="${NPM_SSL_FIX_SLEEP_LE:-5}"
|
||||
|
||||
password_for_label() {
|
||||
case "$1" in
|
||||
primary) echo "${NPM_PASSWORD_PRIMARY:-${NPM_PASSWORD:-}}" ;;
|
||||
secondary) echo "${NPM_PASSWORD_SECONDARY:-${NPM_PASSWORD:-}}" ;;
|
||||
alltra-hybx) echo "${NPM_PASSWORD_ALLTRA_HYBX:-${NPM_PASSWORD:-}}" ;;
|
||||
fourth-dev) echo "${NPM_PASSWORD_FOURTH:-${NPM_PASSWORD:-}}" ;;
|
||||
mifos) echo "${NPM_PASSWORD_MIFOS:-${NPM_PASSWORD:-}}" ;;
|
||||
*) echo "${NPM_PASSWORD:-}" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
instance_label_from_url() {
|
||||
local url="${1:-}"
|
||||
local label="${NPM_INSTANCE_LABEL:-}"
|
||||
if [ -n "$label" ]; then
|
||||
echo "$label"
|
||||
return 0
|
||||
fi
|
||||
case "$url" in
|
||||
*"${IP_NPMPLUS_SECONDARY:-192.168.11.168}"*) echo "secondary" ;;
|
||||
*"${IP_NPMPLUS_ALLTRA_HYBX:-192.168.11.169}"*) echo "alltra-hybx" ;;
|
||||
*"${IP_NPMPLUS_FOURTH:-192.168.11.170}"*) echo "fourth-dev" ;;
|
||||
*"${IP_NPMPLUS_MIFOS:-192.168.11.171}"*) echo "mifos" ;;
|
||||
*) echo "primary" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
NPM_INSTANCE_LABEL="$(instance_label_from_url "$NPM_URL")"
|
||||
NPM_PASSWORD="$(password_for_label "$NPM_INSTANCE_LABEL")"
|
||||
|
||||
if [ -z "$NPM_PASSWORD" ]; then
|
||||
echo "NPM_PASSWORD required (.env or export)." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
curl_npm() { curl -s -k -L --connect-timeout 10 --max-time "$NPM_CURL_MAX_TIME" "$@"; }
|
||||
|
||||
AUTH_TOKEN=""
|
||||
AUTH_COOKIE_JAR=""
|
||||
|
||||
cleanup_auth() {
|
||||
[ -n "${AUTH_COOKIE_JAR:-}" ] && [ -f "$AUTH_COOKIE_JAR" ] && rm -f "$AUTH_COOKIE_JAR"
|
||||
}
|
||||
trap cleanup_auth EXIT
|
||||
|
||||
extract_json_token() {
|
||||
local body="${1:-}"
|
||||
echo "$body" | jq -r '.token // empty' 2>/dev/null || true
|
||||
}
|
||||
|
||||
cookie_has_session() {
|
||||
local jar="$1"
|
||||
[ -f "$jar" ] && grep -q $'\ttoken\t' "$jar"
|
||||
}
|
||||
|
||||
npm_api() {
|
||||
if [ -n "$AUTH_TOKEN" ]; then
|
||||
curl_npm -H "Authorization: Bearer $AUTH_TOKEN" "$@"
|
||||
else
|
||||
curl_npm -b "$AUTH_COOKIE_JAR" -c "$AUTH_COOKIE_JAR" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
# 0 = force SSL OK for this host; 1 = keep ssl_forced false (JSON-RPC / WS edge)
|
||||
should_force_ssl() {
|
||||
local domain="${1,,}"
|
||||
local port="${2:-0}"
|
||||
case "$port" in 8545|8546) return 1 ;; esac
|
||||
[[ "$domain" == *"*"* ]] && return 1
|
||||
if [[ "$domain" =~ ^(rpc\.|ws\.|wss\.) ]]; then return 1; fi
|
||||
if [[ "$domain" =~ rpc-http- ]]; then return 1; fi
|
||||
if [[ "$domain" =~ rpc-ws- ]]; then return 1; fi
|
||||
if [[ "$domain" =~ rpc-core ]]; then return 1; fi
|
||||
if [[ "$domain" =~ rpc-fireblocks ]]; then return 1; fi
|
||||
if [[ "$domain" =~ rpc\.public-0138 ]]; then return 1; fi
|
||||
if [[ "$domain" == "rpc.d-bis.org" || "$domain" == "rpc2.d-bis.org" ]]; then return 1; fi
|
||||
if [[ "$domain" =~ \.tw-core\. ]]; then return 1; fi
|
||||
if [[ "$domain" =~ ^rpc\.defi-oracle ]]; then return 1; fi
|
||||
if [[ "$domain" =~ ^wss\.defi-oracle ]]; then return 1; fi
|
||||
return 0
|
||||
}
|
||||
|
||||
log() { echo "[fix-npmplus-ssl] $*"; }
|
||||
|
||||
try_connect() {
|
||||
curl_npm -o /dev/null -w "%{http_code}" "$1/" 2>/dev/null | grep -qE '^(200|301|302|401)$'
|
||||
}
|
||||
if ! try_connect "$NPM_URL"; then
|
||||
http_url="${NPM_URL/https:/http:}"
|
||||
try_connect "$http_url" && NPM_URL="$http_url" || { echo "Cannot reach NPM at $NPM_URL"; exit 1; }
|
||||
fi
|
||||
|
||||
AUTH_JSON=$(jq -n --arg identity "$NPM_EMAIL" --arg secret "$NPM_PASSWORD" '{identity:$identity,secret:$secret}')
|
||||
AUTH_COOKIE_JAR="$(mktemp)"
|
||||
AUTH_RESPONSE=$(curl_npm -c "$AUTH_COOKIE_JAR" -X POST "$NPM_URL/api/tokens" -H "Content-Type: application/json" -d "$AUTH_JSON")
|
||||
AUTH_TOKEN=$(extract_json_token "$AUTH_RESPONSE")
|
||||
if [ -z "$AUTH_TOKEN" ] || [ "$AUTH_TOKEN" = "null" ]; then
|
||||
AUTH_TOKEN=""
|
||||
fi
|
||||
if [ -z "$AUTH_TOKEN" ] && ! cookie_has_session "$AUTH_COOKIE_JAR"; then
|
||||
echo "NPM auth failed for $NPM_URL" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
HOSTS_JSON=$(npm_api -X GET "$NPM_URL/api/nginx/proxy-hosts")
|
||||
CERTS_JSON=$(npm_api -X GET "$NPM_URL/api/nginx/certificates")
|
||||
if ! echo "$HOSTS_JSON" | jq -e 'type == "array"' >/dev/null 2>&1 || \
|
||||
! echo "$CERTS_JSON" | jq -e 'type == "array"' >/dev/null 2>&1; then
|
||||
echo "NPM auth succeeded but proxy-host or certificate API payload was not usable for $NPM_URL" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# NPM PUT rejects full GET payloads ("additional properties"); use minimal SSL update for cert assignment.
|
||||
cert_id_for_domain() {
|
||||
local domain="$1"
|
||||
echo "$CERTS_JSON" | jq -r --arg d "$domain" '
|
||||
def parse_exp($c):
|
||||
($c.expires_on // $c.meta.letsencrypt_expiry // $c.meta.expires_on // "") | tostring;
|
||||
def epoch_if($s):
|
||||
if $s == "" or $s == "null" then null
|
||||
else
|
||||
($s | gsub(" "; "T") | . + "Z" | fromdateiso8601? // null)
|
||||
end;
|
||||
[ .[] | select(.domain_names | type == "array" and any(.[]; . == $d)) |
|
||||
{id, expires_at:(epoch_if(parse_exp(.)))} ] |
|
||||
map(select(.expires_at == null or .expires_at > now)) |
|
||||
.[0].id // empty
|
||||
'
|
||||
}
|
||||
|
||||
cert_is_expired() {
|
||||
local cert_id="$1"
|
||||
echo "$CERTS_JSON" | jq -e --argjson cid "$cert_id" '
|
||||
def parse_exp($c):
|
||||
($c.expires_on // $c.meta.letsencrypt_expiry // $c.meta.expires_on // "") | tostring;
|
||||
def epoch_if($s):
|
||||
if $s == "" or $s == "null" then null
|
||||
else
|
||||
($s | gsub(" "; "T") | . + "Z" | fromdateiso8601? // null)
|
||||
end;
|
||||
[ .[] | select(.id == $cid) ][0] as $c |
|
||||
if $c == null then false
|
||||
else
|
||||
(epoch_if(parse_exp($c)) as $ep | ($ep != null and $ep < now))
|
||||
end
|
||||
' >/dev/null 2>&1
|
||||
}
|
||||
|
||||
cert_matches_domain() {
|
||||
local cert_id="$1"
|
||||
local domain="$2"
|
||||
echo "$CERTS_JSON" | jq -e --argjson cid "$cert_id" --arg d "$domain" '
|
||||
def host_covered_by_cert($host; $names):
|
||||
any(($names // [])[]; . == $host or (startswith("*.") and ($host | endswith("." + .[2:])) and ($host != .[2:])));
|
||||
[ .[] | select(.id == $cid) ][0] as $c |
|
||||
if $c == null then false
|
||||
else host_covered_by_cert($d; ($c.domain_names // []))
|
||||
end
|
||||
' >/dev/null 2>&1
|
||||
}
|
||||
|
||||
put_host_ssl() {
|
||||
local hid="$1"
|
||||
local force="$2"
|
||||
local body resp upd cid
|
||||
body=$(echo "$HOSTS_JSON" | jq --argjson id "$hid" --argjson force "$force" '
|
||||
[.[] | select(.id == $id)][0] |
|
||||
if . == null then empty
|
||||
else
|
||||
.ssl_forced = $force |
|
||||
.http2_support = true |
|
||||
.hsts_enabled = $force |
|
||||
.hsts_subdomains = $force
|
||||
end
|
||||
')
|
||||
if [ -z "$body" ] || [ "$body" = "null" ]; then
|
||||
log "host id $hid not found in snapshot"
|
||||
return 1
|
||||
fi
|
||||
if [ "$DRY_RUN" = 1 ]; then
|
||||
log "dry-run: PUT proxy-hosts/$hid ssl_forced=$force"
|
||||
return 0
|
||||
fi
|
||||
resp=$(npm_api -X PUT "$NPM_URL/api/nginx/proxy-hosts/$hid" \
|
||||
-H "Content-Type: application/json" -d "$body")
|
||||
if echo "$resp" | jq -e '.id' >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
cid=$(echo "$HOSTS_JSON" | jq -r --argjson id "$hid" '.[] | select(.id == $id) | .certificate_id // empty')
|
||||
if [ -z "$cid" ] || [ "$cid" = "null" ]; then
|
||||
log "PUT failed and no certificate_id for host $hid: $(echo "$resp" | head -c 250)"
|
||||
return 1
|
||||
fi
|
||||
upd=$(jq -n --argjson cid "$cid" --argjson force "$force" \
|
||||
'{certificate_id:$cid, ssl_forced:$force, http2_support:true, hsts_enabled:$force, hsts_subdomains:$force}')
|
||||
resp=$(npm_api -X PUT "$NPM_URL/api/nginx/proxy-hosts/$hid" \
|
||||
-H "Content-Type: application/json" -d "$upd")
|
||||
if echo "$resp" | jq -e '.id' >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
log "PUT fallback failed: $(echo "$resp" | head -c 250)"
|
||||
return 1
|
||||
}
|
||||
|
||||
assign_minimal_ssl() {
|
||||
local hid="$1"
|
||||
local cid="$2"
|
||||
local force="$3"
|
||||
local upd uresp
|
||||
upd=$(jq -n --argjson cid "$cid" --argjson f "$force" \
|
||||
'{certificate_id:$cid, ssl_forced:$f, http2_support:true, hsts_enabled:$f, hsts_subdomains:$f}')
|
||||
uresp=$(npm_api -X PUT "$NPM_URL/api/nginx/proxy-hosts/$hid" \
|
||||
-H "Content-Type: application/json" -d "$upd")
|
||||
if echo "$uresp" | jq -e '.id' >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
log "minimal PUT failed for host $hid: $(echo "$uresp" | head -c 280)"
|
||||
return 1
|
||||
}
|
||||
|
||||
prepare_host_for_certificate_request() {
|
||||
local hid="$1"
|
||||
local sf="$2"
|
||||
local want_force="$3"
|
||||
local domain="$4"
|
||||
if [[ "$sf" == "$want_force" ]]; then
|
||||
return 0
|
||||
fi
|
||||
log "pre-align SSL mode: $domain (host $hid, ssl_forced=$want_force)"
|
||||
if put_host_ssl "$hid" "$want_force"; then
|
||||
HOSTS_JSON=$(npm_api -X GET "$NPM_URL/api/nginx/proxy-hosts")
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
request_cert_and_assign() {
|
||||
local hid="$1"
|
||||
local domain="$2"
|
||||
local force="$3"
|
||||
local cert_resp new_id existing_id
|
||||
if [ "$DRY_RUN" = 1 ]; then
|
||||
log "dry-run: POST certificates + assign host $hid domain=$domain force=$force"
|
||||
return 0
|
||||
fi
|
||||
existing_id=$(cert_id_for_domain "$domain")
|
||||
new_id=""
|
||||
if [ -n "$existing_id" ] && [ "$existing_id" != "null" ]; then
|
||||
log "reuse existing cert id=$existing_id for $domain"
|
||||
new_id="$existing_id"
|
||||
else
|
||||
cert_resp=$(npm_api -X POST "$NPM_URL/api/nginx/certificates" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$(jq -n --arg domain "$domain" '{domain_names:[$domain], provider:"letsencrypt"}')")
|
||||
new_id=$(echo "$cert_resp" | jq -r '.id // empty')
|
||||
if [ -z "$new_id" ] || [ "$new_id" = "null" ]; then
|
||||
log "cert request failed for $domain: $(echo "$cert_resp" | jq -c '.' 2>/dev/null | head -c 350)"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
if assign_minimal_ssl "$hid" "$new_id" "$force"; then
|
||||
CERTS_JSON=$(npm_api -X GET "$NPM_URL/api/nginx/certificates")
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
n_force=0
|
||||
n_force_fail=0
|
||||
n_cert=0
|
||||
n_cert_fail=0
|
||||
n_skip=0
|
||||
|
||||
while IFS= read -r row; do
|
||||
[ -z "$row" ] && continue
|
||||
hid=$(echo "$row" | jq -r '.id')
|
||||
domain=$(echo "$row" | jq -r '.domain_names[0] // empty')
|
||||
cid=$(echo "$row" | jq -r '.certificate_id // 0')
|
||||
sf=$(echo "$row" | jq -r '.ssl_forced // false')
|
||||
en=$(echo "$row" | jq -r '.enabled // true')
|
||||
port=$(echo "$row" | jq -r '.forward_port // 0')
|
||||
[[ "$en" == "false" ]] && continue
|
||||
[ -z "$domain" ] || [ "$domain" = "null" ] && continue
|
||||
|
||||
if should_force_ssl "$domain" "$port"; then
|
||||
want_force=true
|
||||
else
|
||||
want_force=false
|
||||
fi
|
||||
|
||||
if [[ "$cid" == "null" ]] || [[ -z "$cid" ]] || [[ "$cid" == "0" ]]; then
|
||||
if [[ "$domain" == *"*"* ]]; then
|
||||
log "skip wildcard (request cert in UI): $domain"
|
||||
n_skip=$((n_skip + 1))
|
||||
continue
|
||||
fi
|
||||
log "request cert: $domain (host $hid, ssl_forced=$want_force)"
|
||||
if request_cert_and_assign "$hid" "$domain" "$want_force" "$row"; then
|
||||
n_cert=$((n_cert + 1))
|
||||
log "ok cert+assign: $domain"
|
||||
else
|
||||
n_cert_fail=$((n_cert_fail + 1))
|
||||
fi
|
||||
if [ "$DRY_RUN" = 0 ]; then
|
||||
sleep "$NPM_SSL_FIX_SLEEP_LE"
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
|
||||
if cert_is_expired "$cid"; then
|
||||
if [[ "$domain" == *"*"* ]]; then
|
||||
log "skip expired wildcard (renew in UI): $domain"
|
||||
n_skip=$((n_skip + 1))
|
||||
continue
|
||||
fi
|
||||
if ! prepare_host_for_certificate_request "$hid" "$sf" "$want_force" "$domain"; then
|
||||
n_cert_fail=$((n_cert_fail + 1))
|
||||
log "FAIL pre-align SSL mode before renew: $domain"
|
||||
continue
|
||||
fi
|
||||
log "renew expired cert: $domain (host $hid, cert $cid, ssl_forced=$want_force)"
|
||||
if request_cert_and_assign "$hid" "$domain" "$want_force"; then
|
||||
n_cert=$((n_cert + 1))
|
||||
log "ok renewed cert: $domain"
|
||||
else
|
||||
n_cert_fail=$((n_cert_fail + 1))
|
||||
log "FAIL renew: $domain"
|
||||
fi
|
||||
if [ "$DRY_RUN" = 0 ]; then
|
||||
sleep "$NPM_SSL_FIX_SLEEP_LE"
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
|
||||
if ! cert_matches_domain "$cid" "$domain"; then
|
||||
if [[ "$domain" == *"*"* ]]; then
|
||||
log "skip mismatched wildcard cert (fix in UI): $domain"
|
||||
n_skip=$((n_skip + 1))
|
||||
continue
|
||||
fi
|
||||
if ! prepare_host_for_certificate_request "$hid" "$sf" "$want_force" "$domain"; then
|
||||
n_cert_fail=$((n_cert_fail + 1))
|
||||
log "FAIL pre-align SSL mode before mismatched-cert fix: $domain"
|
||||
continue
|
||||
fi
|
||||
log "replace mismatched cert: $domain (host $hid, cert $cid, ssl_forced=$want_force)"
|
||||
if request_cert_and_assign "$hid" "$domain" "$want_force"; then
|
||||
n_cert=$((n_cert + 1))
|
||||
log "ok reassigned matching cert: $domain"
|
||||
else
|
||||
n_cert_fail=$((n_cert_fail + 1))
|
||||
log "FAIL reassign mismatched cert: $domain"
|
||||
fi
|
||||
if [ "$DRY_RUN" = 0 ]; then
|
||||
sleep "$NPM_SSL_FIX_SLEEP_LE"
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$sf" == "true" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Has cert, ssl not forced — align with want_force
|
||||
if [[ "$want_force" == "false" ]]; then
|
||||
n_skip=$((n_skip + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
log "enable Force SSL: $domain (host $hid, cert $cid)"
|
||||
if put_host_ssl "$hid" true; then
|
||||
n_force=$((n_force + 1))
|
||||
log "ok: $domain"
|
||||
else
|
||||
n_force_fail=$((n_force_fail + 1))
|
||||
log "FAIL: $domain"
|
||||
fi
|
||||
done < <(echo "$HOSTS_JSON" | jq -c '.[]')
|
||||
|
||||
log "done: force_ssl_ok=$n_force force_ssl_fail=$n_force_fail new_certs_ok=$n_cert new_certs_fail=$n_cert_fail skipped_rpc_or_wildcard=$n_skip dry_run=$DRY_RUN"
|
||||
if [ "$DRY_RUN" = 1 ]; then
|
||||
log "Re-run without --dry-run to apply."
|
||||
fi
|
||||
@@ -45,10 +45,10 @@ phoenix.sankofa.nexus → http://${IP_SANKOFA_PHOENIX_API}:${SANKOFA_PHOENIX_API
|
||||
www.phoenix.sankofa.nexus → http://${IP_SANKOFA_PHOENIX_API}:${SANKOFA_PHOENIX_API_PORT}
|
||||
the-order.sankofa.nexus → http://${IP_ORDER_HAPROXY}:80
|
||||
explorer.d-bis.org → http://${IP_BLOCKSCOUT}:80
|
||||
rpc-http-pub.d-bis.org → https://${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-192.168.11.252}}}}}}}:443 (WebSocket)
|
||||
rpc-ws-pub.d-bis.org → https://${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-192.168.11.252}}}}}}}:443 (WebSocket)
|
||||
rpc-http-prv.d-bis.org → https://${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-192.168.11.251}}}}}}}:443 (WebSocket)
|
||||
rpc-ws-prv.d-bis.org → https://${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-192.168.11.251}}}}}}}:443 (WebSocket)
|
||||
rpc-http-pub.d-bis.org → http://${RPC_PUBLIC_1:-192.168.11.221}:8545 (WebSocket)
|
||||
rpc-ws-pub.d-bis.org → http://${RPC_PUBLIC_1:-192.168.11.221}:8546 (WebSocket)
|
||||
rpc-http-prv.d-bis.org → http://${RPC_CORE_1:-192.168.11.211}:8545 (WebSocket)
|
||||
rpc-ws-prv.d-bis.org → http://${RPC_CORE_1:-192.168.11.211}:8546 (WebSocket)
|
||||
dbis-admin.d-bis.org → http://${IP_DBIS_FRONTEND:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-192.168.11.13}}}}}0}:80
|
||||
dbis-api.d-bis.org → http://${IP_DBIS_API:-${IP_DBIS_API:-192.168.11.155}}:3000
|
||||
dbis-api-2.d-bis.org → http://${IP_DBIS_API_2:-${IP_DBIS_API_2:-192.168.11.156}}:3000
|
||||
@@ -57,7 +57,7 @@ mim4u.org → http://${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SER
|
||||
www.mim4u.org → http://${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-192.168.11.36}}}}}}:80
|
||||
secure.mim4u.org → http://${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-192.168.11.36}}}}}}:80
|
||||
training.mim4u.org → http://${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-192.168.11.36}}}}}}:80
|
||||
rpc.public-0138.defi-oracle.io → https://${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-192.168.11.252}}}}}}}:443
|
||||
rpc.public-0138.defi-oracle.io → https://${RPC_THIRDWEB_PRIMARY:-192.168.11.240}:443
|
||||
DOMAINS
|
||||
|
||||
cat "$DOMAINS_FILE" | nl -w2 -s'. '
|
||||
|
||||
@@ -173,10 +173,10 @@ create_proxy_host "the-order.sankofa.nexus" "http" "192.168.11.39" "80" "false"
|
||||
|
||||
# d-bis.org (9 domains)
|
||||
create_proxy_host "explorer.d-bis.org" "http" "${IP_BLOCKSCOUT:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-192.168.11.14}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-http-pub.d-bis.org" "https" "${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-192.168.11.252}}}}}}}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-ws-pub.d-bis.org" "https" "${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-192.168.11.252}}}}}}}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-http-prv.d-bis.org" "https" "${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-192.168.11.251}}}}}}}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-ws-prv.d-bis.org" "https" "${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-192.168.11.251}}}}}}}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-http-pub.d-bis.org" "https" "${RPC_PUBLIC_1:-192.168.11.221}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-ws-pub.d-bis.org" "https" "${RPC_PUBLIC_1:-192.168.11.221}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-http-prv.d-bis.org" "https" "${RPC_CORE_1:-192.168.11.211}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-ws-prv.d-bis.org" "https" "${RPC_CORE_1:-192.168.11.211}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "dbis-admin.d-bis.org" "http" "${IP_DBIS_FRONTEND:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-192.168.11.13}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "dbis-api.d-bis.org" "http" "${IP_DBIS_API:-${IP_DBIS_API:-192.168.11.155}}" "3000" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "dbis-api-2.d-bis.org" "http" "${IP_DBIS_API_2:-${IP_DBIS_API_2:-192.168.11.156}}" "3000" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
@@ -189,7 +189,7 @@ create_proxy_host "secure.mim4u.org" "http" "${IP_SERVICE_36:-${IP_SERVICE_36:-$
|
||||
create_proxy_host "training.mim4u.org" "http" "${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-192.168.11.36}}}}}}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
|
||||
# defi-oracle.io (1 domain)
|
||||
create_proxy_host "rpc.public-0138.defi-oracle.io" "https" "${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-192.168.11.252}}}}}}}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc.public-0138.defi-oracle.io" "https" "${RPC_THIRDWEB_PRIMARY:-192.168.11.240}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
|
||||
@@ -315,10 +315,10 @@ fi
|
||||
|
||||
# d-bis.org (9 domains)
|
||||
create_proxy_host "explorer.d-bis.org" "http" "${IP_BLOCKSCOUT:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-192.168.11.14}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-http-pub.d-bis.org" "https" "${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-192.168.11.252}}}}}}}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-ws-pub.d-bis.org" "https" "${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-192.168.11.252}}}}}}}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-http-prv.d-bis.org" "https" "${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-192.168.11.251}}}}}}}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-ws-prv.d-bis.org" "https" "${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-192.168.11.251}}}}}}}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-http-pub.d-bis.org" "http" "${RPC_PUBLIC_1:-192.168.11.221}" "8545" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-ws-pub.d-bis.org" "http" "${RPC_PUBLIC_1:-192.168.11.221}" "8546" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-http-prv.d-bis.org" "http" "${RPC_CORE_1:-192.168.11.211}" "8545" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-ws-prv.d-bis.org" "http" "${RPC_CORE_1:-192.168.11.211}" "8546" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "dbis-admin.d-bis.org" "http" "${IP_DBIS_FRONTEND:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-192.168.11.13}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "dbis-api.d-bis.org" "http" "${IP_DBIS_API:-${IP_DBIS_API:-192.168.11.155}}" "3000" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "dbis-api-2.d-bis.org" "http" "${IP_DBIS_API_2:-${IP_DBIS_API_2:-192.168.11.156}}" "3000" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
|
||||
131
scripts/nginx-proxy-manager/normalize-npmplus-managed-advanced-config.py
Executable file
131
scripts/nginx-proxy-manager/normalize-npmplus-managed-advanced-config.py
Executable file
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
||||
ENV_PATH = PROJECT_ROOT / '.env'
|
||||
|
||||
MINIMAL_REFERRER = 'add_header Referrer-Policy "strict-origin-when-cross-origin" always;'
|
||||
|
||||
MANAGED_ADVANCED_CONFIG = {
|
||||
'explorer.d-bis.org': MINIMAL_REFERRER,
|
||||
'sankofa.nexus': '',
|
||||
'phoenix.sankofa.nexus': '',
|
||||
'the-order.sankofa.nexus': '',
|
||||
'rpc-ws-pub.d-bis.org': MINIMAL_REFERRER,
|
||||
'rpc-http-prv.d-bis.org': MINIMAL_REFERRER,
|
||||
'rpc-ws-prv.d-bis.org': MINIMAL_REFERRER,
|
||||
'dbis-admin.d-bis.org': MINIMAL_REFERRER,
|
||||
'dbis-api.d-bis.org': '',
|
||||
'dbis-api-2.d-bis.org': '',
|
||||
'secure.d-bis.org': MINIMAL_REFERRER,
|
||||
'mim4u.org': MINIMAL_REFERRER,
|
||||
'www.mim4u.org': MINIMAL_REFERRER,
|
||||
'secure.mim4u.org': MINIMAL_REFERRER,
|
||||
'training.mim4u.org': MINIMAL_REFERRER,
|
||||
'rpc.public-0138.defi-oracle.io': MINIMAL_REFERRER,
|
||||
'studio.sankofa.nexus': '',
|
||||
}
|
||||
|
||||
|
||||
def load_env(path: Path) -> dict[str, str]:
|
||||
data: dict[str, str] = {}
|
||||
for raw_line in path.read_text().splitlines():
|
||||
line = raw_line.strip()
|
||||
if not line or line.startswith('#') or '=' not in line:
|
||||
continue
|
||||
key, value = line.split('=', 1)
|
||||
data[key] = value
|
||||
return data
|
||||
|
||||
|
||||
def curl_json(url: str, token: str | None, method: str = 'GET', payload: dict | None = None) -> dict | list:
|
||||
cmd = [
|
||||
'curl',
|
||||
'-s',
|
||||
'-k',
|
||||
'-L',
|
||||
'--connect-timeout',
|
||||
'10',
|
||||
'--max-time',
|
||||
'120',
|
||||
'-X',
|
||||
method,
|
||||
url,
|
||||
]
|
||||
if token:
|
||||
cmd.extend(['-H', f'Authorization: Bearer {token}'])
|
||||
if payload is not None:
|
||||
cmd.extend(['-H', 'Content-Type: application/json', '-d', json.dumps(payload)])
|
||||
raw = subprocess.check_output(cmd, text=True)
|
||||
return json.loads(raw)
|
||||
|
||||
|
||||
def normalize_adv(value: str | None) -> str:
|
||||
return (value or '').replace('\r\n', '\n').strip()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description='Normalize managed NPMplus per-host advanced_config values.')
|
||||
parser.add_argument('--dry-run', action='store_true', help='Show proposed changes without applying them')
|
||||
args = parser.parse_args()
|
||||
|
||||
env = load_env(ENV_PATH)
|
||||
npm_url = env.get('NPM_URL', 'https://192.168.11.167:81')
|
||||
auth = {'identity': env['NPM_EMAIL'], 'secret': env['NPM_PASSWORD']}
|
||||
token = curl_json(f'{npm_url}/api/tokens', None, method='POST', payload=auth)['token']
|
||||
hosts = curl_json(f'{npm_url}/api/nginx/proxy-hosts', token)
|
||||
|
||||
changed = 0
|
||||
for host in hosts:
|
||||
domains = [domain.lower() for domain in host.get('domain_names', [])]
|
||||
matched_domain = next((domain for domain in domains if domain in MANAGED_ADVANCED_CONFIG), None)
|
||||
if not matched_domain:
|
||||
continue
|
||||
|
||||
desired_adv = MANAGED_ADVANCED_CONFIG[matched_domain]
|
||||
current_adv = normalize_adv(host.get('advanced_config'))
|
||||
if current_adv == normalize_adv(desired_adv):
|
||||
print(f'SKIP {matched_domain}')
|
||||
continue
|
||||
|
||||
changed += 1
|
||||
if desired_adv == '':
|
||||
mode = 'clear'
|
||||
elif normalize_adv(desired_adv) == normalize_adv(MINIMAL_REFERRER):
|
||||
mode = 'minimal-referrer'
|
||||
else:
|
||||
mode = 'custom'
|
||||
print(f'UPDATE {matched_domain} -> {mode}')
|
||||
|
||||
if args.dry_run:
|
||||
continue
|
||||
|
||||
payload = {
|
||||
'forward_scheme': host['forward_scheme'],
|
||||
'forward_host': host['forward_host'],
|
||||
'forward_port': host['forward_port'],
|
||||
'allow_websocket_upgrade': host['allow_websocket_upgrade'],
|
||||
'block_exploits': host['block_exploits'],
|
||||
'advanced_config': desired_adv,
|
||||
}
|
||||
response = curl_json(f"{npm_url}/api/nginx/proxy-hosts/{host['id']}", token, method='PUT', payload=payload)
|
||||
if str(response.get('id')) != str(host['id']):
|
||||
print(f'FAILED {matched_domain}: unexpected response {json.dumps(response)[:400]}', file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if changed == 0:
|
||||
print('No managed advanced_config changes were needed.')
|
||||
elif args.dry_run:
|
||||
print(f'Dry run complete. {changed} host(s) would change.')
|
||||
else:
|
||||
print(f'Applied {changed} host(s).')
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main())
|
||||
@@ -15,6 +15,8 @@ NPMPLUS_ALLTRA_IP="${IP_NPMPLUS_ALLTRA_HYBX:-192.168.11.169}"
|
||||
NPM_URL="https://${NPMPLUS_ALLTRA_IP}:81"
|
||||
NPM_EMAIL="${NPM_EMAIL:-admin@example.org}"
|
||||
NPM_PASSWORD="${NPM_PASSWORD:-}"
|
||||
INCLUDE_PLACEHOLDER_HOSTS="${INCLUDE_PLACEHOLDER_HOSTS:-0}"
|
||||
SKIP_UNHEALTHY_UPSTREAMS="${SKIP_UNHEALTHY_UPSTREAMS:-1}"
|
||||
|
||||
if [ -z "$NPM_PASSWORD" ]; then
|
||||
echo "Set NPM_PASSWORD. Get from: ssh root@192.168.11.11 'pct exec 10235 -- cat /opt/.npm_pwd 2>/dev/null'"
|
||||
@@ -93,19 +95,74 @@ add_proxy_host() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Update existing proxy host to set block_exploits: false (fixes 405 on JSON-RPC POST to /)
|
||||
# NPM 2 PUT accepts only specific fields; try minimal payload and blockCommonExploits (camelCase)
|
||||
update_block_exploits() {
|
||||
fetch_proxy_hosts_json() {
|
||||
curl_auth -X GET "$NPM_URL/api/nginx/proxy-hosts"
|
||||
}
|
||||
|
||||
resolve_proxy_host_id() {
|
||||
local domain=$1
|
||||
local hosts_json=${2:-}
|
||||
[ -z "$hosts_json" ] && hosts_json=$(fetch_proxy_hosts_json)
|
||||
echo "$hosts_json" | jq -r --arg dom "$domain" '
|
||||
if type == "array" then .
|
||||
elif .data != null then .data
|
||||
elif .proxy_hosts != null then .proxy_hosts
|
||||
else []
|
||||
end
|
||||
| .[]
|
||||
| select(.domain_names | type == "array")
|
||||
| select(.domain_names[] == $dom)
|
||||
| .id
|
||||
' 2>/dev/null | head -n1
|
||||
}
|
||||
|
||||
origin_tcp_ready() {
|
||||
local fwd_host=$1
|
||||
local fwd_port=$2
|
||||
timeout 3 bash -lc "</dev/tcp/${fwd_host}/${fwd_port}" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
should_manage_proxy_host() {
|
||||
local domain=$1
|
||||
local fwd_host=$2
|
||||
local fwd_port=$3
|
||||
local purpose=${4:-active}
|
||||
if [ "$purpose" = "placeholder" ] && [ "$INCLUDE_PLACEHOLDER_HOSTS" != "1" ]; then
|
||||
echo " Skip placeholder host: $domain (set INCLUDE_PLACEHOLDER_HOSTS=1 after the real web service is deployed)"
|
||||
return 1
|
||||
fi
|
||||
if [ "$SKIP_UNHEALTHY_UPSTREAMS" = "1" ] && ! origin_tcp_ready "$fwd_host" "$fwd_port"; then
|
||||
echo " Skip $domain -> $fwd_host:$fwd_port (origin is not listening)"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Update existing proxy host while preserving cert/SSL state already on the row.
|
||||
update_proxy_host() {
|
||||
local domain=$1
|
||||
local fwd_host=$2
|
||||
local fwd_port=$3
|
||||
local ws=${4:-false}
|
||||
local hosts_json
|
||||
hosts_json=$(curl_auth -X GET "$NPM_URL/api/nginx/proxy-hosts")
|
||||
hosts_json=$(fetch_proxy_hosts_json)
|
||||
local arr
|
||||
arr=$(echo "$hosts_json" | jq -c '
|
||||
if type == "array" then .
|
||||
elif .data != null then .data
|
||||
elif .proxy_hosts != null then .proxy_hosts
|
||||
else []
|
||||
end
|
||||
' 2>/dev/null)
|
||||
[ -z "$arr" ] && return 1
|
||||
local id
|
||||
id=$(echo "$hosts_json" | jq -r ".[] | select(.domain_names | type == \"array\") | select(.domain_names[] == \"$domain\") | .id" 2>/dev/null | head -n1)
|
||||
id=$(echo "$arr" | jq -r --arg dom "$domain" '
|
||||
.[]
|
||||
| select(.domain_names | type == "array")
|
||||
| select(.domain_names[] == $dom)
|
||||
| .id
|
||||
' 2>/dev/null | head -n1)
|
||||
if [ -z "$id" ] || [ "$id" = "null" ]; then return 1; fi
|
||||
# Minimal payload (NPM 2 rejects "additional properties")
|
||||
local payload
|
||||
payload=$(jq -n \
|
||||
--arg scheme "http" --arg host "$fwd_host" --argjson port "$fwd_port" --argjson ws "$ws" \
|
||||
@@ -117,52 +174,91 @@ update_block_exploits() {
|
||||
local out_id
|
||||
out_id=$(echo "$resp" | jq -r '.id // empty' 2>/dev/null)
|
||||
if [ -n "$out_id" ] && [ "$out_id" != "null" ]; then
|
||||
echo " Updated block_exploits=false: $domain"
|
||||
echo " Updated: $domain -> $fwd_host:$fwd_port"
|
||||
return 0
|
||||
fi
|
||||
# NPM 2 may use camelCase: blockCommonExploits
|
||||
payload=$(jq -n \
|
||||
--arg scheme "http" --arg host "$fwd_host" --argjson port "$fwd_port" --argjson ws "$ws" \
|
||||
'{ forward_scheme: $scheme, forward_host: $host, forward_port: $port, allow_websocket_upgrade: $ws, blockCommonExploits: false }')
|
||||
resp=$(curl_auth -X PUT "$NPM_URL/api/nginx/proxy-hosts/$id" -H "Content-Type: application/json" -d "$payload")
|
||||
out_id=$(echo "$resp" | jq -r '.id // empty' 2>/dev/null)
|
||||
if [ -n "$out_id" ] && [ "$out_id" != "null" ]; then
|
||||
echo " Updated blockCommonExploits=false: $domain"
|
||||
echo " Updated: $domain -> $fwd_host:$fwd_port"
|
||||
return 0
|
||||
fi
|
||||
echo " Warning: could not set block_exploits false via API for $domain. Turn off 'Block Common Exploits' in NPM UI (Advanced) for this proxy host."
|
||||
local host_obj
|
||||
host_obj=$(echo "$arr" | jq -c --arg dom "$domain" '
|
||||
.[]
|
||||
| select(.domain_names | type == "array")
|
||||
| select(.domain_names[] == $dom)
|
||||
' 2>/dev/null | head -n1)
|
||||
if [ -n "$host_obj" ]; then
|
||||
payload=$(echo "$host_obj" | jq -c --arg host "$fwd_host" --argjson port "$fwd_port" --argjson ws "$ws" '
|
||||
{
|
||||
domain_names,
|
||||
forward_scheme,
|
||||
forward_host: $host,
|
||||
forward_port: $port,
|
||||
allow_websocket_upgrade: $ws,
|
||||
block_exploits,
|
||||
certificate_id,
|
||||
ssl_forced,
|
||||
caching_enabled,
|
||||
advanced_config,
|
||||
access_list_id,
|
||||
enabled,
|
||||
http2_support,
|
||||
hsts_enabled,
|
||||
hsts_subdomains
|
||||
}
|
||||
' 2>/dev/null)
|
||||
if [ -n "$payload" ]; then
|
||||
resp=$(curl_auth -X PUT "$NPM_URL/api/nginx/proxy-hosts/$id" -H "Content-Type: application/json" -d "$payload")
|
||||
out_id=$(echo "$resp" | jq -r '.id // empty' 2>/dev/null)
|
||||
if [ -n "$out_id" ] && [ "$out_id" != "null" ]; then
|
||||
echo " Updated: $domain -> $fwd_host:$fwd_port"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
echo " Warning: could not update $domain via API. Check the NPM UI for this proxy host."
|
||||
return 1
|
||||
}
|
||||
|
||||
add_or_update_proxy_host() {
|
||||
local domain=$1
|
||||
local fwd_host=$2
|
||||
local fwd_port=$3
|
||||
local ws=${4:-false}
|
||||
local purpose=${5:-active}
|
||||
should_manage_proxy_host "$domain" "$fwd_host" "$fwd_port" "$purpose" || return 0
|
||||
if add_proxy_host "$domain" "$fwd_host" "$fwd_port" "$ws"; then
|
||||
return 0
|
||||
fi
|
||||
update_proxy_host "$domain" "$fwd_host" "$fwd_port" "$ws"
|
||||
}
|
||||
|
||||
# Add or fix Alltra/HYBX + Nathan core-2 proxy hosts (third NPMplus = 76.53.10.38 → 192.168.11.169)
|
||||
# RPC hosts must have block_exploits false or POST to / returns 405
|
||||
add_proxy_host "rpc-core-2.d-bis.org" "192.168.11.212" 8545 true || true
|
||||
add_proxy_host "rpc-alltra.d-bis.org" "192.168.11.172" 8545 true || true
|
||||
add_proxy_host "rpc-alltra-2.d-bis.org" "192.168.11.173" 8545 true || true
|
||||
add_proxy_host "rpc-alltra-3.d-bis.org" "192.168.11.174" 8545 true || true
|
||||
add_proxy_host "rpc-hybx.d-bis.org" "192.168.11.246" 8545 true || true
|
||||
add_proxy_host "rpc-hybx-2.d-bis.org" "192.168.11.247" 8545 true || true
|
||||
add_proxy_host "rpc-hybx-3.d-bis.org" "192.168.11.248" 8545 true || true
|
||||
add_proxy_host "cacti-alltra.d-bis.org" "192.168.11.177" 80 false || true
|
||||
add_proxy_host "cacti-hybx.d-bis.org" "192.168.11.251" 80 false || true
|
||||
# Firefly (Alltra: 6202-6203 @ .175,.176; HYBX: 6204-6205 @ .249,.250) — port 80 typical for web UI
|
||||
add_proxy_host "firefly-alltra-1.d-bis.org" "192.168.11.175" 80 false || true
|
||||
add_proxy_host "firefly-alltra-2.d-bis.org" "192.168.11.176" 80 false || true
|
||||
add_proxy_host "firefly-hybx-1.d-bis.org" "192.168.11.249" 80 false || true
|
||||
add_proxy_host "firefly-hybx-2.d-bis.org" "192.168.11.250" 80 false || true
|
||||
# Fabric / Indy (Alltra: 6001,6401 @ .178,.179; HYBX: 6002,6402 @ .252,.253) — port 80 or adjust in NPM UI
|
||||
add_proxy_host "fabric-alltra.d-bis.org" "192.168.11.178" 80 false || true
|
||||
add_proxy_host "indy-alltra.d-bis.org" "192.168.11.179" 80 false || true
|
||||
add_proxy_host "fabric-hybx.d-bis.org" "192.168.11.252" 80 false || true
|
||||
add_proxy_host "indy-hybx.d-bis.org" "192.168.11.253" 80 false || true
|
||||
echo "Ensuring block_exploits=false for RPC hosts (fixes 405 on JSON-RPC POST)..."
|
||||
update_block_exploits "rpc-core-2.d-bis.org" "192.168.11.212" 8545 true || true
|
||||
update_block_exploits "rpc-alltra.d-bis.org" "192.168.11.172" 8545 true || true
|
||||
update_block_exploits "rpc-alltra-2.d-bis.org" "192.168.11.173" 8545 true || true
|
||||
update_block_exploits "rpc-alltra-3.d-bis.org" "192.168.11.174" 8545 true || true
|
||||
update_block_exploits "rpc-hybx.d-bis.org" "192.168.11.246" 8545 true || true
|
||||
update_block_exploits "rpc-hybx-2.d-bis.org" "192.168.11.247" 8545 true || true
|
||||
update_block_exploits "rpc-hybx-3.d-bis.org" "192.168.11.248" 8545 true || true
|
||||
add_or_update_proxy_host "rpc-core-2.d-bis.org" "192.168.11.212" 8545 true active || true
|
||||
add_or_update_proxy_host "rpc-alltra.d-bis.org" "192.168.11.172" 8545 true active || true
|
||||
add_or_update_proxy_host "rpc-alltra-2.d-bis.org" "192.168.11.173" 8545 true active || true
|
||||
add_or_update_proxy_host "rpc-alltra-3.d-bis.org" "192.168.11.174" 8545 true active || true
|
||||
add_or_update_proxy_host "rpc-hybx.d-bis.org" "192.168.11.246" 8545 true active || true
|
||||
add_or_update_proxy_host "rpc-hybx-2.d-bis.org" "192.168.11.247" 8545 true active || true
|
||||
add_or_update_proxy_host "rpc-hybx-3.d-bis.org" "192.168.11.248" 8545 true active || true
|
||||
add_or_update_proxy_host "cacti-alltra.d-bis.org" "192.168.11.177" 80 false active || true
|
||||
add_or_update_proxy_host "cacti-hybx.d-bis.org" "192.168.11.251" 80 false active || true
|
||||
# Firefly / Fabric / Indy web surfaces are placeholders until the actual HTTP listener is deployed.
|
||||
add_or_update_proxy_host "firefly-alltra-1.d-bis.org" "192.168.11.175" 80 false placeholder || true
|
||||
add_or_update_proxy_host "firefly-alltra-2.d-bis.org" "192.168.11.176" 80 false placeholder || true
|
||||
add_or_update_proxy_host "firefly-hybx-1.d-bis.org" "192.168.11.249" 80 false placeholder || true
|
||||
add_or_update_proxy_host "firefly-hybx-2.d-bis.org" "192.168.11.250" 80 false placeholder || true
|
||||
add_or_update_proxy_host "fabric-alltra.d-bis.org" "192.168.11.178" 80 false placeholder || true
|
||||
add_or_update_proxy_host "indy-alltra.d-bis.org" "192.168.11.179" 80 false placeholder || true
|
||||
add_or_update_proxy_host "fabric-hybx.d-bis.org" "192.168.11.252" 80 false placeholder || true
|
||||
add_or_update_proxy_host "indy-hybx.d-bis.org" "192.168.11.253" 80 false placeholder || true
|
||||
|
||||
echo ""
|
||||
echo "Done. Request Let's Encrypt certs in NPMplus UI for each domain."
|
||||
echo "Done. Request Let's Encrypt certs in NPMplus UI for each active domain."
|
||||
echo "Placeholder Firefly/Fabric/Indy hosts are skipped by default until INCLUDE_PLACEHOLDER_HOSTS=1 and the real web service is listening."
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
# Add NPMplus proxy hosts for dev/Codespaces (fourth NPMplus at 192.168.11.170)
|
||||
# Dev VM (Gitea) + direction to all three Proxmox VE admin panels.
|
||||
# Dev VM (:3000) for dev.d-bis.org + codespaces; gitea.d-bis.org defaults to infra Gitea (VMID 104 @ IP_GITEA_INFRA :80).
|
||||
# Override: GITEA_PUBLIC_UPSTREAM_HOST=$IP_DEV_VM GITEA_PUBLIC_UPSTREAM_PORT=3000 to use dev-local Gitea for the public hostname.
|
||||
# Proxmox VE admin panels: pve.*.d-bis.org → :8006 (websocket).
|
||||
# Usage: NPM_URL=https://192.168.11.170:81 NPM_PASSWORD=xxx bash scripts/nginx-proxy-manager/update-npmplus-fourth-proxy-hosts.sh
|
||||
# Or use NPM_EMAIL + NPM_PASSWORD from .env (NPM_EMAIL_FOURTH / NPM_PASSWORD_FOURTH if set).
|
||||
# See: docs/04-configuration/DEV_CODESPACES_76_53_10_40.md
|
||||
@@ -14,6 +16,9 @@ source "$PROJECT_ROOT/config/ip-addresses.conf" 2>/dev/null || true
|
||||
# Fourth NPMplus (dev/Codespaces)
|
||||
NPMPLUS_FOURTH_IP="${IP_NPMPLUS_FOURTH:-192.168.11.170}"
|
||||
IP_DEV_VM="${IP_DEV_VM:-192.168.11.59}"
|
||||
IP_GITEA_INFRA="${IP_GITEA_INFRA:-192.168.11.31}"
|
||||
GITEA_PUBLIC_UPSTREAM_HOST="${GITEA_PUBLIC_UPSTREAM_HOST:-$IP_GITEA_INFRA}"
|
||||
GITEA_PUBLIC_UPSTREAM_PORT="${GITEA_PUBLIC_UPSTREAM_PORT:-80}"
|
||||
PROXMOX_ML110="${PROXMOX_HOST_ML110:-192.168.11.10}"
|
||||
PROXMOX_R630_01="${PROXMOX_HOST_R630_01:-192.168.11.11}"
|
||||
PROXMOX_R630_02="${PROXMOX_HOST_R630_02:-192.168.11.12}"
|
||||
@@ -198,9 +203,9 @@ add_or_update_proxy_host() {
|
||||
update_proxy_host "$domain" "$fwd_host" "$fwd_port" "$ws"
|
||||
}
|
||||
|
||||
# Dev VM (Gitea on 3000); dev and codespaces as aliases
|
||||
# Dev VM stack on :3000; public Gitea hostname → infra CT 104 by default (config/ip-addresses.conf)
|
||||
add_or_update_proxy_host "dev.d-bis.org" "$IP_DEV_VM" 3000 false || true
|
||||
add_or_update_proxy_host "gitea.d-bis.org" "$IP_DEV_VM" 3000 false || true
|
||||
add_or_update_proxy_host "gitea.d-bis.org" "$GITEA_PUBLIC_UPSTREAM_HOST" "$GITEA_PUBLIC_UPSTREAM_PORT" false || true
|
||||
add_or_update_proxy_host "codespaces.d-bis.org" "$IP_DEV_VM" 3000 false || true
|
||||
|
||||
# Proxmox VE admin panels (port 8006; websocket required for console)
|
||||
|
||||
118
scripts/nginx-proxy-manager/update-npmplus-info-defi-oracle-only.sh
Executable file
118
scripts/nginx-proxy-manager/update-npmplus-info-defi-oracle-only.sh
Executable file
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env bash
|
||||
# Update NPMplus forward targets for info.defi-oracle.io only (avoids full fleet run).
|
||||
# Same upstreams as update-npmplus-proxy-hosts-api.sh (IP_INFO_DEFI_ORACLE_WEB :80).
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||||
_orig_npm_url="${NPM_URL:-}"
|
||||
_orig_npm_email="${NPM_EMAIL:-}"
|
||||
_orig_npm_password="${NPM_PASSWORD:-}"
|
||||
if [ -f "$PROJECT_ROOT/.env" ]; then
|
||||
set +u
|
||||
# shellcheck source=/dev/null
|
||||
source "$PROJECT_ROOT/.env"
|
||||
set -u
|
||||
fi
|
||||
if [ -f "$PROJECT_ROOT/smom-dbis-138/.env" ]; then
|
||||
set +u
|
||||
# shellcheck source=/dev/null
|
||||
source "$PROJECT_ROOT/smom-dbis-138/.env"
|
||||
set -u
|
||||
fi
|
||||
[ -n "$_orig_npm_url" ] && NPM_URL="$_orig_npm_url"
|
||||
[ -n "$_orig_npm_email" ] && NPM_EMAIL="$_orig_npm_email"
|
||||
[ -n "$_orig_npm_password" ] && NPM_PASSWORD="$_orig_npm_password"
|
||||
[ -f "$PROJECT_ROOT/config/ip-addresses.conf" ] && source "$PROJECT_ROOT/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
NPM_URL="${NPM_URL:-https://${IP_NPMPLUS}:81}"
|
||||
NPM_EMAIL="${NPM_EMAIL:-}"
|
||||
NPM_PASSWORD="${NPM_PASSWORD:-}"
|
||||
if [ -z "$NPM_PASSWORD" ]; then
|
||||
echo "NPM_PASSWORD is required (repo .env or export)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
NPM_CURL_MAX_TIME="${NPM_CURL_MAX_TIME:-300}"
|
||||
curl_npm() { curl -s -k -L --connect-timeout 10 --max-time "$NPM_CURL_MAX_TIME" "$@"; }
|
||||
|
||||
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
|
||||
http_url="${NPM_URL/https:/http:}"
|
||||
if try_connect "$http_url/"; then
|
||||
NPM_URL="$http_url"
|
||||
echo "Using HTTP NPM URL: $NPM_URL"
|
||||
fi
|
||||
fi
|
||||
|
||||
AUTH_JSON=$(jq -n --arg identity "$NPM_EMAIL" --arg secret "$NPM_PASSWORD" '{identity:$identity,secret:$secret}')
|
||||
TOKEN_RESPONSE=$(curl_npm -X POST "$NPM_URL/api/tokens" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$AUTH_JSON")
|
||||
TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.token // empty' 2>/dev/null || echo "")
|
||||
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
|
||||
echo "NPM authentication failed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Fetching proxy host list..."
|
||||
PROXY_HOSTS_JSON=$(curl_npm -X GET "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
resolve_proxy_host_id() {
|
||||
local domain="$1"
|
||||
echo "$PROXY_HOSTS_JSON" | jq -r --arg d "$domain" '
|
||||
.[] | select(.domain_names | type == "array") |
|
||||
select(any(.domain_names[]; (. | tostring | ascii_downcase) == ($d | ascii_downcase))) |
|
||||
.id' 2>/dev/null | head -n1
|
||||
}
|
||||
|
||||
INFO_IP="${INFO_DEFI_ORACLE_UPSTREAM_IP:-${IP_INFO_DEFI_ORACLE_WEB:-192.168.11.218}}"
|
||||
INFO_PORT="${INFO_DEFI_ORACLE_UPSTREAM_PORT:-80}"
|
||||
|
||||
put_forward() {
|
||||
local domain="$1"
|
||||
local canonical="${2:-}"
|
||||
local HOST_ID
|
||||
HOST_ID=$(resolve_proxy_host_id "$domain")
|
||||
if [ -z "$HOST_ID" ] || [ "$HOST_ID" = "null" ]; then
|
||||
echo "No NPM proxy host named $domain — add it in NPM UI or run full update-npmplus-proxy-hosts-api.sh"
|
||||
return 1
|
||||
fi
|
||||
local adv_line="" manage_adv=false
|
||||
if [ -n "$canonical" ]; then
|
||||
adv_line="return 301 ${canonical}\$request_uri;"
|
||||
manage_adv=true
|
||||
fi
|
||||
local UPDATE_PAYLOAD
|
||||
UPDATE_PAYLOAD=$(jq -n \
|
||||
--arg scheme "http" \
|
||||
--arg hostname "$INFO_IP" \
|
||||
--argjson port "$INFO_PORT" \
|
||||
--argjson websocket false \
|
||||
--argjson block_exploits false \
|
||||
--arg adv "$adv_line" \
|
||||
--argjson manage_adv "$manage_adv" \
|
||||
'{
|
||||
forward_scheme: $scheme,
|
||||
forward_host: $hostname,
|
||||
forward_port: $port,
|
||||
allow_websocket_upgrade: $websocket,
|
||||
block_exploits: $block_exploits
|
||||
} + (if $manage_adv then {advanced_config: $adv} else {} end)')
|
||||
local RESP
|
||||
RESP=$(curl_npm -X PUT "$NPM_URL/api/nginx/proxy-hosts/$HOST_ID" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$UPDATE_PAYLOAD")
|
||||
if ! echo "$RESP" | jq -e '.id' >/dev/null 2>&1; then
|
||||
echo "PUT failed for $domain: $(echo "$RESP" | jq -c . 2>/dev/null || echo "$RESP" | head -c 300)"
|
||||
return 1
|
||||
fi
|
||||
echo "OK $domain -> http://${INFO_IP}:${INFO_PORT}"
|
||||
}
|
||||
|
||||
echo "Updating info.defi-oracle.io → http://${INFO_IP}:${INFO_PORT}"
|
||||
put_forward "info.defi-oracle.io"
|
||||
put_forward "www.info.defi-oracle.io" "https://info.defi-oracle.io"
|
||||
echo "Done."
|
||||
@@ -155,6 +155,33 @@ validate_canonical_https_redirect() {
|
||||
return 0
|
||||
}
|
||||
|
||||
ADVANCED_CONFIG_CLEAR_SENTINEL="__CLEAR_ADVANCED_CONFIG__"
|
||||
|
||||
default_advanced_config_for_domain() {
|
||||
local domain="${1,,}"
|
||||
|
||||
case "$domain" in
|
||||
explorer.d-bis.org|dbis-admin.d-bis.org|secure.d-bis.org|relay-mainnet-cw.d-bis.org|mim4u.org|www.mim4u.org|secure.mim4u.org|training.mim4u.org|rpc-ws-pub.d-bis.org|rpc-http-prv.d-bis.org|rpc-ws-prv.d-bis.org|rpc.public-0138.defi-oracle.io)
|
||||
# NPMplus already synthesizes the shared security headers in hsts.conf. For
|
||||
# these hosts we only keep a single referrer policy at the edge and avoid
|
||||
# stacking a second CSP / XFO / XCTO / XXSS block from per-host advanced_config.
|
||||
cat <<'EOF'
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
EOF
|
||||
return 0
|
||||
;;
|
||||
sankofa.nexus|phoenix.sankofa.nexus|the-order.sankofa.nexus|dbis-api.d-bis.org|dbis-api-2.d-bis.org|studio.sankofa.nexus)
|
||||
# These origins already emit their own CSP / referrer policy. Send an empty
|
||||
# advanced_config on PUT so stale per-host header blocks are actively cleared.
|
||||
# Studio now owns its / -> /studio/ redirect in the app layer, not at NPMplus.
|
||||
printf '%s\n' "$ADVANCED_CONFIG_CLEAR_SENTINEL"
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# 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() {
|
||||
@@ -165,11 +192,20 @@ add_proxy_host() {
|
||||
local block_exploits=${5:-false}
|
||||
local canonical_https="${6:-}"
|
||||
local adv_line=""
|
||||
local manage_adv="false"
|
||||
if [ -n "$canonical_https" ] && ! validate_canonical_https_redirect "$canonical_https" "add_proxy_host($domain)"; then
|
||||
return 1
|
||||
fi
|
||||
if [ -n "$canonical_https" ]; then
|
||||
adv_line="return 301 ${canonical_https}\$request_uri;"
|
||||
manage_adv="true"
|
||||
elif adv_line="$(default_advanced_config_for_domain "$domain" 2>/dev/null)"; then
|
||||
manage_adv="true"
|
||||
if [ "$adv_line" = "$ADVANCED_CONFIG_CLEAR_SENTINEL" ]; then
|
||||
adv_line=""
|
||||
fi
|
||||
else
|
||||
adv_line=""
|
||||
fi
|
||||
local payload
|
||||
payload=$(jq -n \
|
||||
@@ -179,6 +215,7 @@ add_proxy_host() {
|
||||
--argjson ws "$websocket" \
|
||||
--argjson block_exploits "$([ "$block_exploits" = "true" ] && echo true || echo false)" \
|
||||
--arg adv "$adv_line" \
|
||||
--argjson manage_adv "$manage_adv" \
|
||||
'{
|
||||
domain_names: [$domain],
|
||||
forward_scheme: "http",
|
||||
@@ -188,7 +225,7 @@ add_proxy_host() {
|
||||
block_exploits: $block_exploits,
|
||||
certificate_id: null,
|
||||
ssl_forced: false
|
||||
} + (if $adv != "" then {advanced_config: $adv} else {} end)' 2>/dev/null)
|
||||
} + (if $manage_adv then {advanced_config: $adv} else {} end)' 2>/dev/null)
|
||||
if [ -z "$payload" ]; then
|
||||
echo " ❌ Failed to build payload for $domain"
|
||||
return 1
|
||||
@@ -280,8 +317,17 @@ update_proxy_host() {
|
||||
local be_json="false"
|
||||
[ "$block_exploits" = "true" ] && be_json="true"
|
||||
local adv_line=""
|
||||
local manage_adv="false"
|
||||
if [ -n "$canonical_https" ]; then
|
||||
adv_line="return 301 ${canonical_https}\$request_uri;"
|
||||
manage_adv="true"
|
||||
elif adv_line="$(default_advanced_config_for_domain "$domain" 2>/dev/null)"; then
|
||||
manage_adv="true"
|
||||
if [ "$adv_line" = "$ADVANCED_CONFIG_CLEAR_SENTINEL" ]; then
|
||||
adv_line=""
|
||||
fi
|
||||
else
|
||||
adv_line=""
|
||||
fi
|
||||
UPDATE_PAYLOAD=$(jq -n \
|
||||
--arg scheme "$scheme" \
|
||||
@@ -290,13 +336,14 @@ update_proxy_host() {
|
||||
--argjson websocket "$websocket" \
|
||||
--argjson block_exploits "$be_json" \
|
||||
--arg adv "$adv_line" \
|
||||
--argjson manage_adv "$manage_adv" \
|
||||
'{
|
||||
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)' 2>/dev/null || echo "")
|
||||
} + (if $manage_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" \
|
||||
@@ -344,12 +391,27 @@ 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
|
||||
# ThirdWeb / public-0138 edge (VMID 2400 nginx HTTPS) — default IP must match ALL_VMIDS_ENDPOINTS if env is unset
|
||||
# rpc.public-0138.defi-oracle.io — same Besu JSON-RPC as rpc-http-pub.d-bis.org (VMID 2201). historic: VM 2400 HTTPS edge caused 502 when nginx/tunnel drifted; HTTP upstream avoids HTTPS-to-HTTPS proxy issues for JSON-RPC POST.
|
||||
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)); }
|
||||
update_proxy_host "rpc.public-0138.defi-oracle.io" "http://${RPC_PUBLIC_1}:8545" 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" "http://${RPC_PUBLIC_1}:8545" 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))
|
||||
# info.defi-oracle.io — Chain 138 info hub SPA on dedicated web LXC (default VMID 2410 / IP_INFO_DEFI_ORACLE_WEB).
|
||||
# This stays on the primary public edge so publication does not depend on a long-lived Cloudflare tunnel object.
|
||||
INFO_DEFI_ORACLE_UPSTREAM_IP="${INFO_DEFI_ORACLE_UPSTREAM_IP:-${IP_INFO_DEFI_ORACLE_WEB:-192.168.11.218}}"
|
||||
INFO_DEFI_ORACLE_UPSTREAM_PORT="${INFO_DEFI_ORACLE_UPSTREAM_PORT:-80}"
|
||||
update_proxy_host "info.defi-oracle.io" "http://${INFO_DEFI_ORACLE_UPSTREAM_IP}:${INFO_DEFI_ORACLE_UPSTREAM_PORT}" false false && updated_count=$((updated_count + 1)) || { add_proxy_host "info.defi-oracle.io" "${INFO_DEFI_ORACLE_UPSTREAM_IP}" "${INFO_DEFI_ORACLE_UPSTREAM_PORT}" false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "www.info.defi-oracle.io" "http://${INFO_DEFI_ORACLE_UPSTREAM_IP}:${INFO_DEFI_ORACLE_UPSTREAM_PORT}" false false "https://info.defi-oracle.io" && updated_count=$((updated_count + 1)) || { add_proxy_host "www.info.defi-oracle.io" "${INFO_DEFI_ORACLE_UPSTREAM_IP}" "${INFO_DEFI_ORACLE_UPSTREAM_PORT}" false false "https://info.defi-oracle.io" && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
# Optional relay health publication for off-LAN monitors like Promod.
|
||||
# Set CCIP_RELAY_MAINNET_CW_PUBLIC_HOST in .env to publish the mainnet-cw health
|
||||
# endpoint through NPMplus without exposing a raw UDM Pro port-forward.
|
||||
CCIP_RELAY_MAINNET_CW_PUBLIC_HOST="${CCIP_RELAY_MAINNET_CW_PUBLIC_HOST:-}"
|
||||
CCIP_RELAY_MAINNET_CW_UPSTREAM_IP="${CCIP_RELAY_MAINNET_CW_UPSTREAM_IP:-${PROXMOX_HOST_R630_01:-192.168.11.11}}"
|
||||
CCIP_RELAY_MAINNET_CW_UPSTREAM_PORT="${CCIP_RELAY_MAINNET_CW_UPSTREAM_PORT:-9863}"
|
||||
if [ -n "$CCIP_RELAY_MAINNET_CW_PUBLIC_HOST" ]; then
|
||||
update_proxy_host "$CCIP_RELAY_MAINNET_CW_PUBLIC_HOST" "http://${CCIP_RELAY_MAINNET_CW_UPSTREAM_IP}:${CCIP_RELAY_MAINNET_CW_UPSTREAM_PORT}" false false && updated_count=$((updated_count + 1)) || { add_proxy_host "$CCIP_RELAY_MAINNET_CW_PUBLIC_HOST" "${CCIP_RELAY_MAINNET_CW_UPSTREAM_IP}" "${CCIP_RELAY_MAINNET_CW_UPSTREAM_PORT}" false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
fi
|
||||
# rpc.d-bis.org / rpc2.d-bis.org and WS variants → VMID 2201 (besu-rpc-public-1); add if missing to fix 405
|
||||
update_proxy_host "rpc.d-bis.org" "http://${RPC_PUBLIC_1}:8545" true false && updated_count=$((updated_count + 1)) || { add_proxy_host "rpc.d-bis.org" "${RPC_PUBLIC_1}" 8545 true false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "rpc2.d-bis.org" "http://${RPC_PUBLIC_1}:8545" true false && updated_count=$((updated_count + 1)) || { add_proxy_host "rpc2.d-bis.org" "${RPC_PUBLIC_1}" 8545 true false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
@@ -379,6 +441,10 @@ done
|
||||
update_proxy_host "data.d-bis.org" "http://${IP_DBIS_API:-192.168.11.155}:3000" false && updated_count=$((updated_count + 1)) || { add_proxy_host "data.d-bis.org" "${IP_DBIS_API:-192.168.11.155}" 3000 false true && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
# DApp (VMID 5801) — frontend-dapp for Chain 138 bridge
|
||||
update_proxy_host "dapp.d-bis.org" "http://${IP_DAPP_LXC:-192.168.11.58}:80" false && updated_count=$((updated_count + 1)) || { add_proxy_host "dapp.d-bis.org" "${IP_DAPP_LXC:-192.168.11.58}" 80 false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
# Gitea (VMID 104 default) — aligns primary NPMplus with config/ip-addresses.conf GITEA_PUBLIC_UPSTREAM_*
|
||||
GITEA_PUBLIC_UPSTREAM_HOST="${GITEA_PUBLIC_UPSTREAM_HOST:-${IP_GITEA_INFRA:-192.168.11.31}}"
|
||||
GITEA_PUBLIC_UPSTREAM_PORT="${GITEA_PUBLIC_UPSTREAM_PORT:-80}"
|
||||
update_proxy_host "gitea.d-bis.org" "http://${GITEA_PUBLIC_UPSTREAM_HOST}:${GITEA_PUBLIC_UPSTREAM_PORT}" false && updated_count=$((updated_count + 1)) || { add_proxy_host "gitea.d-bis.org" "${GITEA_PUBLIC_UPSTREAM_HOST}" "${GITEA_PUBLIC_UPSTREAM_PORT}" false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
# MIM4U - VMID 7810 (mim-web-1) @ ${IP_MIM_WEB:-192.168.11.37} - Web Frontend serves main site and proxies /api/* to 7811
|
||||
update_proxy_host "mim4u.org" "http://${IP_MIM_WEB:-192.168.11.37}:80" false && updated_count=$((updated_count + 1)) || { add_proxy_host "mim4u.org" "${IP_MIM_WEB:-192.168.11.37}" 80 false true && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "www.mim4u.org" "http://${IP_MIM_WEB:-192.168.11.37}:80" false && updated_count=$((updated_count + 1)) || { add_proxy_host "www.mim4u.org" "${IP_MIM_WEB:-192.168.11.37}" 80 false true && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
|
||||
|
||||
94
scripts/nginx-proxy-manager/upsert-ccip-relay-mainnet-cw-proxy-host.sh
Executable file
94
scripts/nginx-proxy-manager/upsert-ccip-relay-mainnet-cw-proxy-host.sh
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env bash
|
||||
# Upsert only the NPMplus proxy host for CCIP mainnet-cw relay health (no full fleet update).
|
||||
# Use when update-npmplus-proxy-hosts-api.sh is slow or you need a quick relay-only change.
|
||||
#
|
||||
# Tries POST (create) first so a new hostname does not require downloading the full proxy-host list
|
||||
# (which can be slow or time out on large NPM instances).
|
||||
#
|
||||
# Env: NPM_URL, NPM_EMAIL, NPM_PASSWORD (from .env); optional:
|
||||
# CCIP_RELAY_MAINNET_CW_PUBLIC_HOST (default relay-mainnet-cw.d-bis.org)
|
||||
# CCIP_RELAY_MAINNET_CW_UPSTREAM_IP (default PROXMOX_HOST_R630_01 or 192.168.11.11)
|
||||
# CCIP_RELAY_MAINNET_CW_UPSTREAM_PORT (default 9863)
|
||||
# NPM_CURL_MAX_TIME (default 300)
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
_orig_npm_url="${NPM_URL:-}"
|
||||
_orig_npm_email="${NPM_EMAIL:-}"
|
||||
_orig_npm_password="${NPM_PASSWORD:-}"
|
||||
if [ -f "$PROJECT_ROOT/.env" ]; then set +u; source "$PROJECT_ROOT/.env"; set -u; fi
|
||||
if [ -f "$PROJECT_ROOT/smom-dbis-138/.env" ]; then set +u; source "$PROJECT_ROOT/smom-dbis-138/.env"; set -u; fi
|
||||
[ -n "$_orig_npm_url" ] && NPM_URL="$_orig_npm_url"
|
||||
[ -n "$_orig_npm_email" ] && NPM_EMAIL="$_orig_npm_email"
|
||||
[ -n "$_orig_npm_password" ] && NPM_PASSWORD="$_orig_npm_password"
|
||||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
# Default HTTPS — plain http:// on :81 often 301s to https:// and breaks token POST if curl -L downgrades body.
|
||||
NPM_URL="${NPM_URL:-https://${IP_NPMPLUS}:81}"
|
||||
NPM_EMAIL="${NPM_EMAIL:-nsatoshi2007@hotmail.com}"
|
||||
NPM_PASSWORD="${NPM_PASSWORD:-}"
|
||||
[ -z "$NPM_PASSWORD" ] && { echo "NPM_PASSWORD required (.env or export)"; exit 1; }
|
||||
|
||||
DOMAIN="${CCIP_RELAY_MAINNET_CW_PUBLIC_HOST:-relay-mainnet-cw.d-bis.org}"
|
||||
UP_IP="${CCIP_RELAY_MAINNET_CW_UPSTREAM_IP:-${PROXMOX_HOST_R630_01:-192.168.11.11}}"
|
||||
UP_PORT="${CCIP_RELAY_MAINNET_CW_UPSTREAM_PORT:-9863}"
|
||||
|
||||
NPM_CURL_MAX_TIME="${NPM_CURL_MAX_TIME:-300}"
|
||||
curl_npm() { curl -s -k -L --http1.1 --connect-timeout 30 --max-time "$NPM_CURL_MAX_TIME" "$@"; }
|
||||
|
||||
try_connect() { curl -s -k -L -o /dev/null --connect-timeout 5 --max-time 20 "$1" 2>/dev/null; }
|
||||
if ! try_connect "$NPM_URL/"; then
|
||||
http_url="${NPM_URL/https:/http:}"
|
||||
try_connect "$http_url/" && NPM_URL="$http_url"
|
||||
fi
|
||||
|
||||
AUTH_JSON=$(jq -n --arg identity "$NPM_EMAIL" --arg secret "$NPM_PASSWORD" '{identity:$identity,secret:$secret}')
|
||||
TOKEN=$(curl_npm -X POST "$NPM_URL/api/tokens" -H "Content-Type: application/json" -d "$AUTH_JSON" | jq -r '.token // empty')
|
||||
[ -n "$TOKEN" ] && [ "$TOKEN" != "null" ] || { echo "NPM auth failed"; exit 1; }
|
||||
|
||||
ADV='add_header Referrer-Policy "strict-origin-when-cross-origin" always;'
|
||||
PAYLOAD_ADD=$(jq -n \
|
||||
--arg domain "$DOMAIN" \
|
||||
--arg host "$UP_IP" \
|
||||
--argjson port "$UP_PORT" \
|
||||
--arg adv "$ADV" \
|
||||
'{domain_names:[$domain],forward_scheme:"http",forward_host:$host,forward_port:$port,allow_websocket_upgrade:false,block_exploits:false,certificate_id:null,ssl_forced:false,advanced_config:$adv}')
|
||||
|
||||
echo "Trying create (POST) for $DOMAIN -> http://${UP_IP}:${UP_PORT}"
|
||||
RESP=$(curl_npm -X POST "$NPM_URL/api/nginx/proxy-hosts" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$PAYLOAD_ADD")
|
||||
if echo "$RESP" | jq -e '.id' >/dev/null 2>&1; then
|
||||
echo "OK created id=$(echo "$RESP" | jq -r .id)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ERR_MSG=$(echo "$RESP" | jq -r '.message // .error.message // .error // empty' 2>/dev/null || echo "")
|
||||
if ! echo "$ERR_MSG" | grep -qiE 'already|in use|exist|duplicate|unique'; then
|
||||
echo "Create failed (not a duplicate case): $ERR_MSG"
|
||||
echo "$RESP" | jq . 2>/dev/null || echo "$RESP"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Host exists or name in use; fetching proxy list for PUT ($ERR_MSG)"
|
||||
PROXY_JSON=$(curl_npm -X GET "$NPM_URL/api/nginx/proxy-hosts" -H "Authorization: Bearer $TOKEN")
|
||||
if [ -z "$PROXY_JSON" ] || [ "$PROXY_JSON" = "[]" ]; then
|
||||
echo "Empty proxy list response (timeout or NPM error). Try NPM_CURL_MAX_TIME=600 or run from LAN."
|
||||
exit 28
|
||||
fi
|
||||
HOST_ID=$(echo "$PROXY_JSON" | jq -r --arg d "$DOMAIN" '.[] | select(.domain_names | type == "array") | select(any(.domain_names[]; (. | tostring | ascii_downcase) == ($d | ascii_downcase))) | .id' | head -n1)
|
||||
|
||||
if [ -z "$HOST_ID" ] || [ "$HOST_ID" = "null" ]; then
|
||||
echo "Could not resolve proxy host id for $DOMAIN after duplicate error."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Updating proxy host $DOMAIN (id=$HOST_ID) -> http://${UP_IP}:${UP_PORT}"
|
||||
PAYLOAD_PUT=$(jq -n \
|
||||
--arg host "$UP_IP" \
|
||||
--argjson port "$UP_PORT" \
|
||||
--arg adv "$ADV" \
|
||||
'{forward_scheme:"http",forward_host:$host,forward_port:$port,allow_websocket_upgrade:false,block_exploits:false,advanced_config:$adv}')
|
||||
RESP=$(curl_npm -X PUT "$NPM_URL/api/nginx/proxy-hosts/$HOST_ID" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$PAYLOAD_PUT")
|
||||
echo "$RESP" | jq -e '.id' >/dev/null && echo "OK updated" || { echo "$RESP" | jq . 2>/dev/null || echo "$RESP"; exit 1; }
|
||||
85
scripts/nginx-proxy-manager/upsert-ccip-relay-mainnet-cw-via-ssh.sh
Executable file
85
scripts/nginx-proxy-manager/upsert-ccip-relay-mainnet-cw-via-ssh.sh
Executable file
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run CCIP relay NPM upsert from a Proxmox host (default r630-01) with good LAN path to NPMplus.
|
||||
# Expands NPM_* and CCIP_* into a remote bash script with printf %q (safe quoting; not passed on argv).
|
||||
#
|
||||
# Usage (repo root):
|
||||
# bash scripts/nginx-proxy-manager/upsert-ccip-relay-mainnet-cw-via-ssh.sh
|
||||
# Env:
|
||||
# NPM_RELAY_UPSERT_SSH default root@192.168.11.11
|
||||
# NPM_URL default http://192.168.11.167:81 (HTTP on LAN)
|
||||
# load-project-env: NPM_EMAIL, NPM_PASSWORD, CCIP_RELAY_MAINNET_CW_*
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
# shellcheck source=/dev/null
|
||||
source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
||||
|
||||
SSH_HOST="${NPM_RELAY_UPSERT_SSH:-root@192.168.11.11}"
|
||||
# NPMplus admin returns 301 HTTP→HTTPS on :81; token POST must use HTTPS (see NPM_URL in .env).
|
||||
NPM_URL_USE="${NPM_URL:-https://${IP_NPMPLUS:-192.168.11.167}:81}"
|
||||
|
||||
DOMAIN="${CCIP_RELAY_MAINNET_CW_PUBLIC_HOST:-relay-mainnet-cw.d-bis.org}"
|
||||
UP_IP="${CCIP_RELAY_MAINNET_CW_UPSTREAM_IP:-${PROXMOX_HOST_R630_01:-192.168.11.11}}"
|
||||
UP_PORT="${CCIP_RELAY_MAINNET_CW_UPSTREAM_PORT:-9863}"
|
||||
|
||||
[ -n "${NPM_PASSWORD:-}" ] || { echo "NPM_PASSWORD required (.env)"; exit 1; }
|
||||
[ -n "${NPM_EMAIL:-}" ] || { echo "NPM_EMAIL required (.env)"; exit 1; }
|
||||
|
||||
echo "SSH $SSH_HOST → NPM $NPM_URL_USE → $DOMAIN → http://${UP_IP}:${UP_PORT}"
|
||||
|
||||
# Unquoted heredoc: local expands $(printf '%q' ...) into the remote script; use \$ for remote expansions.
|
||||
# shellcheck disable=SC2087
|
||||
ssh -o BatchMode=yes -o ConnectTimeout=15 "$SSH_HOST" bash <<EOF
|
||||
set -euo pipefail
|
||||
NPM_URL=$(printf '%q' "$NPM_URL_USE")
|
||||
NPM_EMAIL=$(printf '%q' "$NPM_EMAIL")
|
||||
NPM_PASSWORD=$(printf '%q' "$NPM_PASSWORD")
|
||||
DOMAIN=$(printf '%q' "$DOMAIN")
|
||||
UP_IP=$(printf '%q' "$UP_IP")
|
||||
UP_PORT=$(printf '%q' "$UP_PORT")
|
||||
|
||||
curl_npm() { curl -s -k -L --http1.1 --connect-timeout 20 --max-time 300 "\$@"; }
|
||||
|
||||
AUTH_JSON=\$(jq -n --arg identity "\$NPM_EMAIL" --arg secret "\$NPM_PASSWORD" '{identity:\$identity,secret:\$secret}')
|
||||
TOKEN=\$(curl_npm -X POST "\$NPM_URL/api/tokens" -H "Content-Type: application/json" -d "\$AUTH_JSON" | jq -r '.token // empty')
|
||||
[ -n "\$TOKEN" ] && [ "\$TOKEN" != "null" ] || { echo "NPM auth failed on remote"; exit 1; }
|
||||
|
||||
ADV='add_header Referrer-Policy "strict-origin-when-cross-origin" always;'
|
||||
PAYLOAD_ADD=\$(jq -n \\
|
||||
--arg domain "\$DOMAIN" \\
|
||||
--arg host "\$UP_IP" \\
|
||||
--argjson port "\$UP_PORT" \\
|
||||
--arg adv "\$ADV" \\
|
||||
'{domain_names:[\$domain],forward_scheme:"http",forward_host:\$host,forward_port:\$port,allow_websocket_upgrade:false,block_exploits:false,certificate_id:null,ssl_forced:false,advanced_config:\$adv}')
|
||||
|
||||
echo "POST create \$DOMAIN"
|
||||
RESP=\$(curl_npm -X POST "\$NPM_URL/api/nginx/proxy-hosts" -H "Authorization: Bearer \$TOKEN" -H "Content-Type: application/json" -d "\$PAYLOAD_ADD")
|
||||
if echo "\$RESP" | jq -e '.id' >/dev/null 2>&1; then
|
||||
echo "OK created id=\$(echo "\$RESP" | jq -r .id)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ERR_MSG=\$(echo "\$RESP" | jq -r '.message // .error.message // .error // empty' 2>/dev/null || echo "")
|
||||
if ! echo "\$ERR_MSG" | grep -qiE 'already|in use|exist|duplicate|unique'; then
|
||||
echo "Create failed: \$ERR_MSG"
|
||||
echo "\$RESP" | jq . 2>/dev/null || echo "\$RESP"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Duplicate / exists; GET proxy list for PUT (\$ERR_MSG)"
|
||||
PROXY_JSON=\$(curl_npm -X GET "\$NPM_URL/api/nginx/proxy-hosts" -H "Authorization: Bearer \$TOKEN")
|
||||
HOST_ID=\$(echo "\$PROXY_JSON" | jq -r --arg d "\$DOMAIN" '.[] | select(.domain_names | type == "array") | select(any(.domain_names[]; (. | tostring | ascii_downcase) == (\$d | ascii_downcase))) | .id' | head -n1)
|
||||
[ -n "\$HOST_ID" ] && [ "\$HOST_ID" != "null" ] || { echo "Could not find host id for \$DOMAIN"; exit 1; }
|
||||
|
||||
PAYLOAD_PUT=\$(jq -n \\
|
||||
--arg host "\$UP_IP" \\
|
||||
--argjson port "\$UP_PORT" \\
|
||||
--arg adv "\$ADV" \\
|
||||
'{forward_scheme:"http",forward_host:\$host,forward_port:\$port,allow_websocket_upgrade:false,block_exploits:false,advanced_config:\$adv}')
|
||||
echo "PUT id=\$HOST_ID"
|
||||
RESP=\$(curl_npm -X PUT "\$NPM_URL/api/nginx/proxy-hosts/\$HOST_ID" -H "Authorization: Bearer \$TOKEN" -H "Content-Type: application/json" -d "\$PAYLOAD_PUT")
|
||||
echo "\$RESP" | jq -e '.id' >/dev/null && echo "OK updated" || { echo "\$RESP" | jq . 2>/dev/null; exit 1; }
|
||||
EOF
|
||||
|
||||
echo "Done."
|
||||
88
scripts/nginx-proxy-manager/upsert-omdnl-org-proxy-host.sh
Executable file
88
scripts/nginx-proxy-manager/upsert-omdnl-org-proxy-host.sh
Executable file
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env bash
|
||||
# Create or update NPMplus proxy host: omdnl.org + www.omdnl.org → static nginx upstream.
|
||||
#
|
||||
# Add Cloudflare A records first (scripts/cloudflare/configure-omdnl-org-dns.sh).
|
||||
# Then request certificates in NPM (SSL) once DNS resolves.
|
||||
#
|
||||
# Env: NPM_URL, NPM_EMAIL, NPM_PASSWORD; optional:
|
||||
# OMDNL_ORG_UPSTREAM_IP (default IP_OMDNL_ORG_WEB / 192.168.11.222)
|
||||
# OMDNL_ORG_UPSTREAM_PORT (default 80)
|
||||
# NPM_CURL_MAX_TIME (default 300)
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
_orig_npm_url="${NPM_URL:-}"
|
||||
_orig_npm_email="${NPM_EMAIL:-}"
|
||||
_orig_npm_password="${NPM_PASSWORD:-}"
|
||||
if [ -f "$PROJECT_ROOT/.env" ]; then set +u; source "$PROJECT_ROOT/.env"; set -u; fi
|
||||
[ -n "$_orig_npm_url" ] && NPM_URL="$_orig_npm_url"
|
||||
[ -n "$_orig_npm_email" ] && NPM_EMAIL="$_orig_npm_email"
|
||||
[ -n "$_orig_npm_password" ] && NPM_PASSWORD="$_orig_npm_password"
|
||||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
NPM_URL="${NPM_URL:-https://${IP_NPMPLUS:-192.168.11.167}:81}"
|
||||
NPM_EMAIL="${NPM_EMAIL:-}"
|
||||
NPM_PASSWORD="${NPM_PASSWORD:-}"
|
||||
[ -z "$NPM_PASSWORD" ] && { echo "NPM_PASSWORD required (.env or export)" >&2; exit 1; }
|
||||
|
||||
UP_IP="${OMDNL_ORG_UPSTREAM_IP:-${IP_OMDNL_ORG_WEB:-192.168.11.222}}"
|
||||
UP_PORT="${OMDNL_ORG_UPSTREAM_PORT:-80}"
|
||||
|
||||
NPM_CURL_MAX_TIME="${NPM_CURL_MAX_TIME:-300}"
|
||||
curl_npm() { curl -s -k -L --http1.1 --connect-timeout 30 --max-time "$NPM_CURL_MAX_TIME" "$@"; }
|
||||
|
||||
try_connect() { curl -s -k -L -o /dev/null --connect-timeout 5 --max-time 20 "$1" 2>/dev/null; }
|
||||
if ! try_connect "$NPM_URL/"; then
|
||||
http_url="${NPM_URL/https:/http:}"
|
||||
try_connect "$http_url/" && NPM_URL="$http_url"
|
||||
fi
|
||||
|
||||
AUTH_JSON=$(jq -n --arg identity "$NPM_EMAIL" --arg secret "$NPM_PASSWORD" '{identity:$identity,secret:$secret}')
|
||||
TOKEN=$(curl_npm -X POST "$NPM_URL/api/tokens" -H "Content-Type: application/json" -d "$AUTH_JSON" | jq -r '.token // empty')
|
||||
[ -n "$TOKEN" ] && [ "$TOKEN" != "null" ] || { echo "NPM auth failed" >&2; exit 1; }
|
||||
|
||||
ADV='add_header Referrer-Policy "strict-origin-when-cross-origin" always;'
|
||||
PAYLOAD_ADD=$(jq -n \
|
||||
--argjson domains '["omdnl.org","www.omdnl.org"]' \
|
||||
--arg host "$UP_IP" \
|
||||
--argjson port "$UP_PORT" \
|
||||
--arg adv "$ADV" \
|
||||
'{domain_names:$domains,forward_scheme:"http",forward_host:$host,forward_port:$port,allow_websocket_upgrade:false,block_exploits:true,certificate_id:null,ssl_forced:false,advanced_config:$adv}')
|
||||
|
||||
echo "Trying create (POST) omdnl.org + www → http://${UP_IP}:${UP_PORT}"
|
||||
RESP=$(curl_npm -X POST "$NPM_URL/api/nginx/proxy-hosts" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$PAYLOAD_ADD")
|
||||
if echo "$RESP" | jq -e '.id' >/dev/null 2>&1; then
|
||||
echo "OK created id=$(echo "$RESP" | jq -r .id)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ERR_MSG=$(echo "$RESP" | jq -r '.message // .error.message // .error // empty' 2>/dev/null || echo "")
|
||||
if ! echo "$ERR_MSG" | grep -qiE 'already|in use|exist|duplicate|unique'; then
|
||||
echo "Create failed (not a duplicate case): $ERR_MSG" >&2
|
||||
echo "$RESP" | jq . 2>/dev/null || echo "$RESP"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Host exists; fetching proxy list for PUT ($ERR_MSG)"
|
||||
PROXY_JSON=$(curl_npm -X GET "$NPM_URL/api/nginx/proxy-hosts" -H "Authorization: Bearer $TOKEN")
|
||||
HOST_ID=$(echo "$PROXY_JSON" | jq -r '
|
||||
.[] | select(.domain_names | type == "array") |
|
||||
select(any(.domain_names[]; (. | tostring | ascii_downcase) == "omdnl.org")) |
|
||||
.id' | head -n1)
|
||||
|
||||
if [ -z "$HOST_ID" ] || [ "$HOST_ID" = "null" ]; then
|
||||
echo "Could not resolve proxy host id for omdnl.org." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Updating proxy host id=$HOST_ID -> http://${UP_IP}:${UP_PORT}"
|
||||
PAYLOAD_PUT=$(jq -n \
|
||||
--arg host "$UP_IP" \
|
||||
--argjson port "$UP_PORT" \
|
||||
--arg adv "$ADV" \
|
||||
'{forward_scheme:"http",forward_host:$host,forward_port:$port,allow_websocket_upgrade:false,block_exploits:true,advanced_config:$adv}')
|
||||
RESP=$(curl_npm -X PUT "$NPM_URL/api/nginx/proxy-hosts/$HOST_ID" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$PAYLOAD_PUT")
|
||||
echo "$RESP" | jq -e '.id' >/dev/null && echo "OK updated" || { echo "$RESP" | jq . 2>/dev/null || echo "$RESP"; exit 1; }
|
||||
Reference in New Issue
Block a user