Compare commits

20 Commits
master ... main

Author SHA1 Message Date
defiQUG
8d5540bf1d chore: sync submodule pointers (ai-mcp, cross-chain, dbis_core, explorer, gru-docs, metamask, smom-dbis-138)
Some checks are pending
Deploy to Phoenix / deploy (push) Waiting to run
Made-with: Cursor
2026-03-27 18:38:10 -07:00
defiQUG
2d4b35c3ee docs(stage4): archive deployment-reports README + E2E evidence hygiene
- deployment-reports: historical notice + SOT links (no per-file edits)
- archive README: link deployment-reports folder
- E2E_ENDPOINTS_LIST: evidence retention + prune script pointer
- prune-e2e-verification-evidence.sh: dry-run default, --apply + KEEP_DAYS

Made-with: Cursor
2026-03-27 16:41:49 -07:00
defiQUG
f0fb00987a docs(stage3): MASTER_PLAN/TODO + NOT_IMPLEMENTED — R21 complete
- MASTER_PLAN gaps + §3.1 table rows for the-order / cutover
- MASTER_TODO_EXPANDED: R21 [x]; Config/DNS GAPS tasks [x]
- NOT_IMPLEMENTED: Sankofa/Order row = routing done, scope note
- HIGH_PRIORITY R21–R24 line; BLITZKRIEG R21–R22 blurb

Made-with: Cursor
2026-03-27 15:41:47 -07:00
defiQUG
70a6d66e4d docs(stage2): mark R21 / Sankofa cutover done across 00-meta checklists
- REMAINING_TASKS_BREAKDOWN_MISSING_INFO §2 + step 4
- REMAINING_WORK_BREAKDOWN_AND_ANSWERS Sankofa Q&A + one-line summary
- REMAINING_COMPONENTS R21; operator-only + improvements + checklists

Made-with: Cursor
2026-03-27 15:40:45 -07:00
defiQUG
21c839b9b5 docs(stage1): GAPS + placeholders master — The Order / cutover live
- GAPS §2.1: replace TBD table with 2026-03 live routing + cutover v1.1 note
- PLACEHOLDERS: Sankofa cutover row matches SANKOFA_CUTOVER_PLAN v1.1

Made-with: Cursor
2026-03-27 15:38:40 -07:00
defiQUG
4f383490a3 docs(A): sync high-value runbooks for The Order (10210 HAProxy)
- SANKOFA_CUTOVER_PLAN: live backends table, fix TBDs, historical step labels
- SANKOFA_THE_ORDER_CHECKLIST: replace with done + bypass + pointers
- DNS comprehensive + streamlined tables: the-order row and sankofa zone live
- E2E Cloudflare runbook: the-order backend column

Made-with: Cursor
2026-03-27 15:24:54 -07:00
defiQUG
a086c451c3 docs: sync The Order routing (10210 HAProxy) and fix stale TBDs
- E2E, ALL_VMIDS, operator checklist, RPC_ENDPOINTS_MASTER, DNS/NPM architecture
- PROXMOX deployment template: the-order wired via 10210
- Placeholders master + r630-02 incomplete summary for 10210
- CT 10210: chown /var/cache on host idmap (mandb clean) — applied on cluster

Made-with: Cursor
2026-03-27 15:06:06 -07:00
defiQUG
430431f2f6 feat(order): HAProxy on 10210, NPM → 192.168.11.39:80
- Add order-haproxy config template and provision-order-haproxy-10210.sh (SSH to r630-01)
- Document one-time unprivileged CT idmap chown repair when apt fails
- Default THE_ORDER_UPSTREAM_* to IP_ORDER_HAPROXY:80; portal bypass via env
- Align update-sankofa-npmplus-proxy-hosts.sh, AGENTS, ALL_VMIDS, E2E notes

Made-with: Cursor
2026-03-27 14:05:37 -07:00
defiQUG
0df175d9cb chore: stop tracking legacy NPMplus backup tarballs (use local backups/npmplus/)
Made-with: Cursor
2026-03-27 13:44:56 -07:00
defiQUG
96eb0a6660 chore: ignore backups/npmplus (NPMplus backup script output)
Made-with: Cursor
2026-03-27 13:44:44 -07:00
defiQUG
436b13ad3d docs: E2E evidence after operator NPM sync (2026-03-27)
- Public + private verification reports (e2e-verification-20260327_134032 / _134137)
- E2E_ENDPOINTS_LIST: refresh stats and note rpc.defi-oracle.io optional-when-fail behavior

Made-with: Cursor
2026-03-27 13:42:50 -07:00
defiQUG
a2645b5285 NPM: validate canonical_https for www redirects; docs and env example
- Reject non-https, paths, and injection-prone chars in advanced_config 301 targets
- E2E list: phoenix marketing note, the-order HAProxy remediation, 2026-03-27 passes
- AGENTS.md: scoped Cloudflare token pointer; smom-dbis-138 dotenv load note
- .env.master.example: DNS script flags and scoped token guidance

Made-with: Cursor
2026-03-27 12:29:40 -07:00
defiQUG
17b923ffdf Follow-ups: DNS dry-run/zone-only, Order NPM IDs, E2E Location assert, the-order block_exploits
- update-all-dns-to-public-ip.sh: --dry-run (no CF API), --zone-only=ZONE, help before .env, env CLOUDFLARE_DNS_DRY_RUN/DNS_ZONE_ONLY
- update-sankofa-npmplus-proxy-hosts.sh: the-order + www.the-order by ID (env SANKOFA_NPM_ID_THE_ORDER, SANKOFA_NPM_ID_WWW_THE_ORDER, THE_ORDER_UPSTREAM_*)
- update-npmplus-proxy-hosts-api.sh: the-order.sankofa.nexus uses block_exploits false like sankofa portal
- verify-end-to-end-routing.sh: E2E_WWW_CANONICAL_BASE + Location validation (fail on wrong apex); keep local redirect vars
- docs: ALL_VMIDS www 301 lines, E2E_ENDPOINTS_LIST verifier/DNS notes; AGENTS.md Cloudflare script pointer

Made-with: Cursor
2026-03-27 11:27:39 -07:00
defiQUG
50a3973662 DNS/scripts: include www.the-order.sankofa.nexus in zone lists and NPM cleanup
- export-cloudflare-dns-records.sh: baseline DOMAIN_ZONES entry
- update-all-dns-to-public-ip.sh: Cloudflare name www.the-order for sankofa.nexus zone
- cleanup-npmplus-duplicate-certificates.sh: SANKOFA_DOMAINS for LE grouping

Made-with: Cursor
2026-03-27 00:31:14 -07:00
defiQUG
a36ccbbd77 NPM: canonical 301 for www sankofa/phoenix/the-order; E2E pass on 301/308
- update-npmplus-proxy-hosts-api.sh: optional advanced_config 301 via 5th/6th args; wire www.the-order → https://the-order.sankofa.nexus; document OSJ portal and the_order repo path
- update-sankofa-npmplus-proxy-hosts.sh: same 301 for www rows via 4th pipe field
- verify-end-to-end-routing.sh: www.the-order in inventory; treat 301/308 as HTTPS pass for www.sankofa, www.phoenix, www.the-order
- configure-npmplus-domains.js: comment — avoid duplicate redirection UI rows for Sankofa www
- AGENTS.md, ALL_VMIDS_ENDPOINTS.md, E2E_ENDPOINTS_LIST.md: Order portal and www redirect notes

Made-with: Cursor
2026-03-27 00:30:28 -07:00
defiQUG
b9d3c10d01 ops: CCIP relay systemd unit, TsunamiSwap VM 5010 inventory script
- config/systemd/ccip-relay.service for /opt/smom-dbis-138/services/relay/start-relay.sh
- tsunamiswap-vm-5010-provision.sh checks qm status on PROXMOX_HOST
- AGENTS.md pointers for relay and TsunamiSwap

Made-with: Cursor
2026-03-27 00:27:10 -07:00
defiQUG
00afd38a57 feat(deploy): Sankofa portal sync excludes secrets; ensure NextAuth on CT
- Tar excludes .env/.env.local; post-sync sets NEXTAUTH_URL on .env and .env.local
- New sankofa-portal-ensure-nextauth-on-ct.sh; optional SANKOFA_PORTAL_NEXTAUTH_URL
- AGENTS.md pointer to ensure script

Made-with: Cursor
2026-03-26 18:56:57 -07:00
defiQUG
47b1ec0992 docs: note portal strict ESLint and optional hardening
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
Made-with: Cursor
2026-03-25 21:16:08 -07:00
defiQUG
15406797a4 docs: refresh Sankofa portal build notes (strict TS, ESLint warnings)
Made-with: Cursor
2026-03-25 20:47:27 -07:00
defiQUG
abe7afb9ab docs: add public sector live deployment checklist (Phoenix 7800/7801)
Made-with: Cursor
2026-03-25 20:46:57 -07:00
95 changed files with 3192 additions and 194 deletions

View File

@@ -17,6 +17,8 @@ PROXMOX_TOKEN_VALUE=
PROXMOX_ALLOW_ELEVATED=
# --- Cloudflare ---
# Prefer CLOUDFLARE_API_TOKEN scoped to Zone:DNS:Edit on the zones you use (avoid global Account API key when possible).
# Bulk DNS script: scripts/update-all-dns-to-public-ip.sh — use --dry-run and --zone-only=sankofa.nexus (etc.) before wide updates.
CLOUDFLARE_API_TOKEN=
CLOUDFLARE_EMAIL=
CLOUDFLARE_API_KEY=

3
.gitignore vendored
View File

@@ -16,6 +16,9 @@ yarn.lock
*.log
logs/
# NPMplus backups (backup-npmplus.sh — tarballs and extracted trees; may contain certs/DB)
backups/npmplus/
# OS files
.DS_Store
Thumbs.db

36
AGENTS.md Normal file
View File

@@ -0,0 +1,36 @@
# Proxmox workspace — agent instructions
Single canonical copy for Cursor/Codex. (If your editor also loads `.cursor/rules`, treat those as overlays.)
## Scope
Orchestration for Proxmox VE, Chain 138 (`smom-dbis-138/`), explorers, NPMplus, and deployment runbooks.
## Quick pointers
| Need | Location |
|------|-----------|
| Doc index | `docs/MASTER_INDEX.md` |
| cXAUC/cXAUT unit | 1 full token = 1 troy oz Au — `docs/11-references/EXPLORER_TOKEN_LIST_CROSSCHECK.md` (section 5.1) |
| PMM mesh 6s tick | `smom-dbis-138/scripts/reserve/pmm-mesh-6s-automation.sh``docs/integration/ORACLE_AND_KEEPER_CHAIN138.md` (PMM mesh automation) |
| VMID / IP / FQDN | `docs/04-configuration/ALL_VMIDS_ENDPOINTS.md` |
| Ops template + JSON | `docs/03-deployment/PROXMOX_VE_OPERATIONAL_DEPLOYMENT_TEMPLATE.md`, `config/proxmox-operational-template.json` |
| Live vs template (read-only SSH) | `bash scripts/verify/audit-proxmox-operational-template.sh` |
| Config validation | `bash scripts/validation/validate-config-files.sh` |
| smom-dbis-138 `.env` in bash scripts | Prefer `source smom-dbis-138/scripts/lib/deployment/dotenv.sh` + `load_deployment_env --repo-root "$PROJECT_ROOT"` (trims RPC URL line endings). From an interactive shell: `source smom-dbis-138/scripts/load-env.sh`. Proxmox root scripts: `source scripts/lib/load-project-env.sh` (also trims common RPC vars). |
| Sankofa portal → CT 7801 (build + restart) | `./scripts/deployment/sync-sankofa-portal-7801.sh` (`--dry-run` first); sets `NEXTAUTH_URL` on CT via `sankofa-portal-ensure-nextauth-on-ct.sh` |
| CCIP relay (r630-01 host) | Unit: `config/systemd/ccip-relay.service``/etc/systemd/system/ccip-relay.service`; `systemctl enable --now ccip-relay` |
| TsunamiSwap VM 5010 check | `./scripts/deployment/tsunamiswap-vm-5010-provision.sh` (inventory only until VM exists) |
| The Order portal (`https://the-order.sankofa.nexus`) | OSJ management UI (secure auth); source repo **the_order** at `~/projects/the_order`. NPM upstream defaults to **order-haproxy** CT **10210** (`IP_ORDER_HAPROXY:80`); use `THE_ORDER_UPSTREAM_*` to point at the Sankofa portal if 10210 is down. Provision HAProxy: `scripts/deployment/provision-order-haproxy-10210.sh`. **`www.the-order.sankofa.nexus`** → **301** apex (same as www.sankofa / www.phoenix). |
| Portal login + Keycloak systemd + `.env` (prints password once) | `./scripts/deployment/enable-sankofa-portal-login-7801.sh` (`--dry-run` first) |
| Completable (no LAN) | `./scripts/run-completable-tasks-from-anywhere.sh` |
| Operator (LAN + secrets) | `./scripts/run-all-operator-tasks-from-lan.sh` (use `--skip-backup` if `NPM_PASSWORD` unset) |
| Cloudflare bulk DNS → `PUBLIC_IP` | `./scripts/update-all-dns-to-public-ip.sh` — use **`--dry-run`** and **`--zone-only=sankofa.nexus`** (or `d-bis.org` / `mim4u.org` / `defi-oracle.io`) to limit scope; see script header. Prefer scoped **`CLOUDFLARE_API_TOKEN`** (see `.env.master.example`). |
## Rules of engagement
- Review scripts before running; prefer `--dry-run` where supported.
- Do not run the full operator flow when everything is healthy unless the user explicitly wants broad fixes (NPM/nginx/RPC churn).
- Chain 138 deploy RPC: `http://192.168.11.211:8545` (Core). Read-only / non-deploy checks may use public RPC per project rules.
Full detail: see embedded workspace rules and `docs/00-meta/OPERATOR_READY_CHECKLIST.md`.

View File

@@ -0,0 +1,27 @@
# HAProxy on VMID 10210 (order-haproxy @ 192.168.11.39).
# NPMplus terminates TLS and forwards HTTP to :80 here; we proxy to the Sankofa/Order Next.js portal.
# Deploy: scripts/deployment/provision-order-haproxy-10210.sh (substitutes __BACKEND_HOST__ / __BACKEND_PORT__).
global
log stdout format raw local0
maxconn 4096
defaults
log global
mode http
option httplog
option dontlognull
option forwardfor
timeout connect 10s
timeout client 300s
timeout server 300s
timeout tunnel 3600s
frontend fe_http
bind *:80
# Client used HTTPS at NPM; help Next.js / auth callbacks
http-request set-header X-Forwarded-Proto https if !{ hdr(X-Forwarded-Proto) -m found }
default_backend be_portal
backend be_portal
server portal __BACKEND_HOST__:__BACKEND_PORT__ check inter 10s fall 3 rise 2 maxconn 1000

View File

@@ -0,0 +1,23 @@
# Install on Proxmox host (e.g. r630-01) where /opt/smom-dbis-138/services/relay exists:
# sudo cp config/systemd/ccip-relay.service /etc/systemd/system/ccip-relay.service
# sudo systemctl daemon-reload && sudo systemctl enable --now ccip-relay
#
# Uses start-relay.sh (loads parent .env and relay/.env.local).
[Unit]
Description=CCIP relay service (Chain 138 to Mainnet)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/smom-dbis-138/services/relay
ExecStart=/bin/bash /opt/smom-dbis-138/services/relay/start-relay.sh
Restart=on-failure
RestartSec=15
StartLimitIntervalSec=300
StartLimitBurst=5
[Install]
WantedBy=multi-user.target

View File

@@ -270,7 +270,7 @@
| R18 | Ensure Blockscout (VMID 5000) is up and /api reachable | Health checks |
| R19 | Run forge test before deploying; integration tests where available | Pre-deploy |
| R20 | NatSpec on public contract functions | Code quality |
| R21 | When The Order deployed: NPMplus proxy host; document in RPC_ENDPOINTS_MASTER | Sankofa/The Order go-live |
| R21 | **Done 2026-03:** NPMplus Order via 10210; documented in RPC_ENDPOINTS_MASTER, ALL_VMIDS | Complete |
| R22 | Document or configure blocks #2#6 in NETWORK_ARCHITECTURE | When decided |
| R23 | Scripts: progress indicators; --dry-run; config validation | Script updates |
| R24 | Keep config/token-mapping.json as single source of truth for 138↔Mainnet | Adding tokens |
@@ -299,8 +299,8 @@
| Item | Recommendation |
|------|----------------|
| the-order.sankofa.nexus | When The Order portal deployed: add NPMplus proxy host; document in RPC_ENDPOINTS_MASTER, ALL_VMIDS_ENDPOINTS |
| Sankofa cutover plan | Replace <TARGET_IP>, <TARGET_PORT>, TBDs with actual IPs/ports when deployed |
| the-order.sankofa.nexus | **Live:** NPM → `192.168.11.39:80` (10210 → portal :3000) |
| Sankofa cutover plan | **Updated** v1.1 (2026-03-27); legacy API snippets may still use <TARGET_*> |
| sankofa.nexus / phoenix routing | Ensure NPMplus proxy targets 192.168.11.51:3000 and 192.168.11.50:4000 per master docs; only explorer.d-bis.org → 192.168.11.140 |
| Public blocks #2#6 | Document in NETWORK_ARCHITECTURE / NETWORK_CONFIGURATION_MASTER when assigned or mark reserved |

View File

@@ -125,7 +125,7 @@ Full operator actions: **[RECOMMENDATIONS_OPERATOR_CHECKLIST.md](RECOMMENDATIONS
| R8R11 | RPC_URL_138; GAS_PRICE on 138; phased deploy; nonce/tx stuck runbooks |
| R12R16 | Keep runbooks in sync; document addresses per chain; run verification after deploy; env per env |
| R17R20 | Monitor bridges; Blockscout up; forge test pre-deploy; NatSpec |
| R21R24 | The Order NPMplus; blocks #2#6; script progress/dry-run/validation; token-mapping.json source of truth |
| R21R24 | **R21 done 2026-03** (Order NPM/10210); R22 blocks #2#6; R23 script UX/validation; R24 token-mapping.json |
---

View File

@@ -96,9 +96,9 @@
| # | Action | When |
|---|--------|------|
| R21 | The Order / Sankofa NPMplus proxy host | When The Order portal deployed: add proxy; document in RPC_ENDPOINTS_MASTER, ALL_VMIDS_ENDPOINTS |
| R21 | The Order / Sankofa NPMplus | **Done 2026-03** — Order → 10210 `.39:80`; see ALL_VMIDS, RPC_ENDPOINTS_MASTER |
| R22 | Document or configure blocks #2#6 in NETWORK_ARCHITECTURE | When decided |
| Sankofa cutover | Replace <TARGET_IP>, <TARGET_PORT>, TBDs in SANKOFA_CUTOVER_PLAN | When deployed |
| Sankofa cutover | **Done** — SANKOFA_CUTOVER_PLAN v1.1; fleet script `update-npmplus-proxy-hosts-api.sh` |
| 7581 | VLAN enablement, observability stack, CCIP fleet, sovereign tenants, missing containers | Per NEXT_STEPS_MASTER and deployment phases |
---

View File

@@ -172,7 +172,7 @@ Dry-run deployments and cross-chain reconciliation.
Source: NOT_CHANGED_BY_DESIGN.
**Configuration and DNS (R21R22)**
Sankofa alignment and configuration blocks 26.
Sankofa zone NPM/docs **aligned (R21 done 2026-03)**; blocks #2#6 still TBD.
Source: ALL_REQUIREMENTS.
**Quick Wins (R23)**

View File

@@ -119,7 +119,7 @@ flowchart TB
Consolidated from [GAPS_AND_RECOMMENDATIONS_CONSOLIDATED.md](../GAPS_AND_RECOMMENDATIONS_CONSOLIDATED.md), [REQUIRED_FIXES_UPDATES_GAPS.md](../REQUIRED_FIXES_UPDATES_GAPS.md), [ALL_IMPROVEMENTS_AND_GAPS_INDEX.md](../ALL_IMPROVEMENTS_AND_GAPS_INDEX.md), and [NEXT_STEPS_MASTER.md](NEXT_STEPS_MASTER.md). Detailed tables stay in those docs; below are the resolution rules.
- **Secrets and API keys:** No real keys in `.env.example` (token-aggregation, root); use placeholders; document in [MASTER_SECRETS_INVENTORY.md](../04-configuration/MASTER_SECRETS_INVENTORY.md). Rotate any exposed keys.
- **Config/DNS TBDs:** the-order.sankofa.nexus, Sankofa cutover plan `<TARGET_IP>`, RPC_ENDPOINTS_MASTER placeholders — **When The Order / Sankofa deployed, update NPMplus and docs; remove TBD.**
- **Config/DNS (Sankofa zone):** **Done 2026-03** — the-order via **10210** `192.168.11.39:80`; cutover plan v1.1; RPC_ENDPOINTS_MASTER + ALL_VMIDS updated. Re-run `update-npmplus-proxy-hosts-api.sh` after infra changes. Legacy doc snippets may still show `<TARGET_IP>` in API examples.
- **Network placeholders:** Public blocks #2#6 in [NETWORK_ARCHITECTURE.md](../02-architecture/NETWORK_ARCHITECTURE.md) — **Document when assigned or mark reserved.**
- **Code placeholders:** See Section 3.1 below (one-line resolution table).
- **Documentation placeholders:** Emergency hotline and example URLs in dbis_core nostro-vostro — Done ("To be configured"). the-order REMAINING_TODOS.md — **Create or archive and fix links.**
@@ -131,8 +131,8 @@ Consolidated from [GAPS_AND_RECOMMENDATIONS_CONSOLIDATED.md](../GAPS_AND_RECOMME
| Item | Location | Resolution |
|------|----------|------------|
| API keys in .env.example | token-aggregation, root | Replace with placeholders; document in MASTER_SECRETS_INVENTORY; rotate if exposed. |
| the-order.sankofa.nexus | RPC_ENDPOINTS_MASTER, ALL_VMIDS_ENDPOINTS | When The Order portal deployed: add NPMplus proxy host and document IP:port. |
| Sankofa cutover plan TBDs | SANKOFA_CUTOVER_PLAN | Replace `<TARGET_IP>`, `<TARGET_PORT>` when Sankofa deployed. |
| the-order.sankofa.nexus | RPC_ENDPOINTS_MASTER, ALL_VMIDS_ENDPOINTS | **Done:** NPM → 10210 `.39:80` → portal `:3000`. |
| Sankofa cutover plan | SANKOFA_CUTOVER_PLAN | **Done v1.1** — live tables; substitute `<TARGET_*>` only if reusing old API curl templates. |
| sankofa.nexus / phoenix routes | RPC_ENDPOINTS_MASTER | Keep in sync with NPMplus; remove "placeholder (routes to Blockscout)" when pointing to Sankofa/Phoenix. |
| Public blocks #2#6 | NETWORK_ARCHITECTURE, NETWORK_CONFIGURATION_MASTER | Document when assigned or mark reserved. |
| AlltraAdapter fee | AlltraAdapter.sol | Implement configurable setBridgeFee; document in PLACEHOLDERS_AND_TBD. Update when ALL Mainnet fee known. |

View File

@@ -60,7 +60,7 @@
| R18 | Explorer health: Blockscout VMID 5000, /api reachable | [ ] |
| R19 | Test before deploy: forge test smom-dbis-138, alltra-lifi-settlement; integration tests | [x] |
| R20 | NatSpec on public contract functions | [x] |
| R21 | Sankofa/The Order: when deployed add NPMplus proxy; RPC_ENDPOINTS_MASTER, SANKOFA_CUTOVER_PLAN TBDs | [ ] |
| R21 | Sankofa/The Order: NPMplus + docs (10210 HAProxy path) | [x] |
| R22 | Network placeholders: blocks #2#6 in NETWORK_ARCHITECTURE when assigned | [ ] |
| R23 | Scripts: progress indicators; --dry-run where missing; extend config validation | [x] |
@@ -252,9 +252,9 @@
| Task | Status |
|------|--------|
| the-order.sankofa.nexus when portal deployed; NPMplus proxy + RPC_ENDPOINTS_MASTER | [ ] |
| Sankofa cutover: replace TBDs in SANKOFA_CUTOVER_PLAN | [ ] |
| NPMplus proxy: sankofa → 7801/.51:3000, phoenix → 7800/.50:4000; only explorer → .140 | [ ] |
| the-order.sankofa.nexus; NPMplus + RPC_ENDPOINTS_MASTER | [x] |
| Sankofa cutover: SANKOFA_CUTOVER_PLAN v1.1 | [x] |
| NPMplus proxy: sankofa → .51:3000, phoenix → .50:4000, the-order → .39:80; only explorer → .140 | [x] |
| Blocks #2#6 in NETWORK_ARCHITECTURE when assigned | [ ] |
### smom-dbis-138 (GAPS §3)

View File

@@ -71,7 +71,7 @@
| Area | Deliverables |
|------|--------------|
| **Sankofa / The Order** | Checklist: replace &lt;TARGET_IP&gt;/&lt;TARGET_PORT&gt;; update ALL_VMIDS_ENDPOINTS, RPC_ENDPOINTS_MASTER; NPMplus proxy for the-order.sankofa.nexus; "where to update when done" (PLACEHOLDERS_AND_TBD, REMAINING_COMPONENTS). See [SANKOFA_THE_ORDER_CHECKLIST](../04-configuration/SANKOFA_THE_ORDER_CHECKLIST.md) or SANKOFA_CUTOVER_PLAN. |
| **Sankofa / The Order** | **Routing done 2026-03** (NPM, ALL_VMIDS, RPC_ENDPOINTS_MASTER, SANKOFA_CUTOVER_PLAN v1.1, [SANKOFA_THE_ORDER_CHECKLIST](../04-configuration/SANKOFA_THE_ORDER_CHECKLIST.md)). This row retained for design-scope doc; implementation of app features (OMNIS SDK, legal vendors, etc.) remains separate. |
| **OMNIS — Sankofa Phoenix SDK** | Integration spec: required SDK interface (getAuthUrl, validateToken, getUserInfo), env vars, fallback. See [OMNIS_SANKOFA_PHOENIX_SDK_INTEGRATION_SPEC](../04-configuration/OMNIS_SANKOFA_PHOENIX_SDK_INTEGRATION_SPEC.md). Dependency note in PLACEHOLDERS_AND_TBD / PLACEHOLDERS_AND_COMPLETION_MASTER_LIST: "Blocked on Sankofa Phoenix SDK availability." |
| **the-order — legal-documents** | Vendor/implementation matrix (court-efiling, e-signature, document-security): Option, Prerequisites, Steps, "Where to update when done." See [LEGAL_DOCUMENTS_IMPLEMENTATION](LEGAL_DOCUMENTS_IMPLEMENTATION.md). Update GAPS_AND_RECOMMENDATIONS_CONSOLIDATED, PLACEHOLDERS_AND_COMPLETION_MASTER_LIST when done. |
| **dbis_core** | Runbook or comment "When to implement": Prometheus when monitoring stack is up; Redis when caching needed. See [DBIS_CORE_WHEN_TO_IMPLEMENT](DBIS_CORE_WHEN_TO_IMPLEMENT.md). No new code; doc/checklist only. |

View File

@@ -39,8 +39,8 @@ Use this checklist when you have operator or LAN access to complete the remainin
| # | Action | Notes |
|---|--------|-------|
| R21 | The Order / Sankofa NPMplus proxy host | When The Order portal deployed: add proxy in NPMplus; document in RPC_ENDPOINTS_MASTER, ALL_VMIDS_ENDPOINTS |
| Sankofa cutover | Replace &lt;TARGET_IP&gt;, &lt;TARGET_PORT&gt;, TBDs in SANKOFA_CUTOVER_PLAN with actual values |
| R21 | The Order / Sankofa NPMplus | **Done 2026-03** — see ALL_VMIDS, RPC_ENDPOINTS_MASTER, `update-npmplus-proxy-hosts-api.sh` |
| Sankofa cutover | **Done** SANKOFA_CUTOVER_PLAN v1.1 |
| Blocks #2#6 | Document in NETWORK_ARCHITECTURE / NETWORK_CONFIGURATION_MASTER when assigned or mark reserved |
| 7581 | VLAN enablement, observability stack, CCIP fleet, sovereign tenants, missing containers | Per NEXT_STEPS_MASTER and deployment phases |

View File

@@ -1,6 +1,6 @@
# Operator Ready Checklist — Copy-Paste Commands
**Last Updated:** 2026-03-04
**Last Updated:** 2026-03-27
**Purpose:** Single page with exact commands to complete every pending todo. Run from **repo root** on a host with **LAN** access (and `smom-dbis-138/.env` with `PRIVATE_KEY`, `NPM_PASSWORD` where noted).
**Do you have all necessary creds?** See [OPERATOR_CREDENTIALS_CHECKLIST.md](OPERATOR_CREDENTIALS_CHECKLIST.md) — per-task list of LAN, PRIVATE_KEY, NPM_PASSWORD, RPC_URL_138, SSH, LINK, gas, token balance.
@@ -15,6 +15,22 @@
---
## Completed in this session (2026-03-26)
| Item | Result |
|------|--------|
| NPMplus recovery | VMID `10233` was wedged on `192.168.11.167:81` (TCP connect, no HTTP). `pct reboot 10233` on `r630-01` restored the expected `301` response on port `81`. |
| NPMplus API updater | `NPM_URL=https://192.168.11.167:81 bash scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh` completed with **39 hosts updated, 0 failed**. |
| Sankofa / Order / Studio routing | **Superseded 2026-03-27:** Order hostnames default to **order-haproxy** `http://192.168.11.39:80` (10210 → `.51:3000`). Through 2026-03-26 NPM pointed Order directly at portal `:3000`. `studio.sankofa.nexus``http://192.168.11.72:8000`. |
| Public E2E | Latest run `bash scripts/verify/verify-end-to-end-routing.sh --profile=public` exited `0` with **Failed: 0**, **DNS passed: 37**, **HTTPS passed: 22**. Sankofa, Phoenix, Studio, The Order, DBIS, Mifos, and MIM4U public endpoints passed. Evidence: `docs/04-configuration/verification-evidence/e2e-verification-20260326_115013/`. |
| Private E2E | Latest run `bash scripts/verify/verify-end-to-end-routing.sh --profile=private` exited `0` with **Failed: 0** and **DNS passed: 4**. `rpc-http-prv.d-bis.org`, `rpc-fireblocks.d-bis.org`, `rpc-ws-prv.d-bis.org`, and `ws.rpc-fireblocks.d-bis.org` all passed. Evidence: `docs/04-configuration/verification-evidence/e2e-verification-20260326_120939/`. |
| NPMplus backup | Fresh backup completed: `backups/npmplus/backup-20260326_115622.tar.gz`. API exports succeeded; direct SQLite file copy and certbot path copy were partial/warn-only, but the backup manifest and compressed bundle were created successfully. |
| Blockscout verification run | `./scripts/verify/run-contract-verification-with-proxy.sh` completed; contracts were submitted or skipped if already verified. `WETH10` returned `The address is not a smart contract`; others like `Multicall`, `Aggregator`, `Proxy`, `CCIPSender`, `CCIPWETH10Bridge`, and `CCIPWETH9Bridge` submitted successfully. |
| Private RPC redirect fix | `rpc-http-prv.d-bis.org` no longer returns HTTP `301` on JSON-RPC POST. Live NPMplus host `11` was updated to `ssl_forced=false` while preserving upstream `192.168.11.211:8545`. |
| NPM creds loading | For NPM-only runs, prefer targeted `grep` of `NPM_EMAIL` / `NPM_PASSWORD` if full `.env` export triggers `Argument list too long`. |
---
## 1. High: Cronos closure + reachable CCIP funding
**Ref:** [CONFIG_READY_CHAINS_COMPLETION_RUNBOOK](../07-ccip/CONFIG_READY_CHAINS_COMPLETION_RUNBOOK.md)
@@ -84,6 +100,8 @@ Single contract retry: `./scripts/verify/run-contract-verification-with-proxy.sh
**Runbook:** [502_DEEP_DIVE_ROOT_CAUSES_AND_FIXES.md](502_DEEP_DIVE_ROOT_CAUSES_AND_FIXES.md)
**Current status after 2026-03-26:** no public 502s reproduced in the latest public E2E run. Use this section only if those endpoints regress.
---
## 5. LAN: Run all operator tasks (backup + verify ± deploy ± create-vms)
@@ -211,8 +229,14 @@ bash scripts/verify/backup-npmplus.sh
**NPMplus RPC fix (405):** From LAN: `bash scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh`. Verify: `bash scripts/verify/verify-end-to-end-routing.sh`.
**Status (2026-03-26):** main NPMplus API update completed successfully with `39 hosts updated, 0 failed`; public E2E now passes for Sankofa root, Phoenix, Studio, and The Order. Re-run only when upstream targets or proxy definitions change.
**Latest backup evidence:** `backups/npmplus/backup-20260326_115622.tar.gz`
**NPMplus API unreachable (167/169):** Restart Docker inside NPMplus LXC: `./scripts/maintenance/fix-npmplus-services-via-proxmox-ssh.sh` (SSH to r630-01, restarts npmplus in 10233 and 10235).
**If port 81 accepts TCP but hangs at HTTP:** reboot CT `10233` with `pct reboot 10233` on `r630-01`, then retry the API updater.
**E2E from LAN (no public DNS):** If E2E fails at DNS (`Could not resolve host`), use [E2E_DNS_FROM_LAN_RUNBOOK.md](../04-configuration/E2E_DNS_FROM_LAN_RUNBOOK.md): append `config/e2e-hosts-append.txt` to `/etc/hosts`, then run `E2E_USE_SYSTEM_RESOLVER=1 ./scripts/verify/verify-end-to-end-routing.sh --profile=public`. Revert with `sudo ./scripts/verify/remove-e2e-hosts-from-etc-hosts.sh`.
**E2E profiles:** Use `--profile=public` for public endpoints (default) or `--profile=private` for private/admin RPC only. Run sequentially to avoid timestamp collision in evidence dirs. **Known E2E warnings** (502/404 and WS): [E2E_ENDPOINTS_LIST.md](../04-configuration/E2E_ENDPOINTS_LIST.md) § Known E2E warnings and Remediation. MIM4U web 502s and WS test-format warnings are **non-blocking** for contract/pool completion.
@@ -221,6 +245,25 @@ bash scripts/verify/backup-npmplus.sh
---
## 8.5 PMM mesh (6s oracle / keeper / PMMWETH poll)
**Ref:** `smom-dbis-138/docs/integration/ORACLE_AND_KEEPER_CHAIN138.md` (PMM mesh automation)
```bash
cd smom-dbis-138
# .env should include: PRIVATE_KEY, AGGREGATOR_ADDRESS, PRICE_FEED_KEEPER_ADDRESS (optional: KEEPER_PRIVATE_KEY if different from PRIVATE_KEY)
./scripts/reserve/set-price-feed-keeper-interval.sh 6 # once per keeper deployment if interval was 30s
./scripts/update-oracle-price.sh # verify transmitter + gas (Besu needs explicit gas limit in script)
./scripts/reserve/sync-weth-mock-price.sh # if CHAIN138_WETH_MOCK_PRICE_FEED is set (keeper WETH path)
mkdir -p logs
nohup ./scripts/reserve/pmm-mesh-6s-automation.sh >> logs/pmm-mesh-automation.log 2>&1 &
# journalctl equivalent: tail -f logs/pmm-mesh-automation.log
```
**systemd:** `config/systemd/chain138-pmm-mesh-automation.service.example` — copy, set `User` and absolute paths, `enable --now`.
---
## 9. Wemix token verification (Deferred)
This is intentionally deferred with the rest of the Wemix path. If the chain is brought back into scope later, open [scan.wemix.com/tokens](https://scan.wemix.com/tokens); confirm WETH, USDT, USDC addresses. If different, update `config/token-mapping-multichain.json` and [WEMIX_TOKEN_VERIFICATION.md](../07-ccip/WEMIX_TOKEN_VERIFICATION.md). Then:

View File

@@ -1,6 +1,6 @@
# Placeholders and What Needs to Be Completed — Master List
**Last Updated:** 2026-02-13
**Last Updated:** 2026-03-27
**Purpose:** Single list of every placeholder and what must be completed (code, config, docs, ops).
**Completion pass (2026-02-13):** OMNIS backend routes (POST/PUT budgets, POST documents/upload, PATCH profile) done; authController token blacklisting (in-memory + TOKEN_BLACKLIST_ENABLED); TezosRelayService Taquito skeleton + mock gated; Smart accounts .env.example + runbook; dbis_core Redis stub, Prometheus/risk comments, deal-execution tests skipped with ticket; CCIPLogger decision (omit unless monitoring); .bak listed and deprecated in BAK_FILES_DEPRECATION; deployment gaps (env table, TransactionMirror script, DEPLOYMENT_GAPS_COMPLETED); NPMplus HA and storage monitor already have ALERT_EMAIL/ALERT_WEBHOOK; deploy.sh TODO comments for migration/health; the-order legal-documents vendor integration README; root .gitignore (venv, __pycache__, .phase1).
@@ -25,8 +25,8 @@
| Placeholder | Location | What to complete |
|-------------|----------|------------------|
| **the-order.sankofa.nexus** | [ALL_VMIDS_ENDPOINTS](../04-configuration/ALL_VMIDS_ENDPOINTS.md), [RPC_ENDPOINTS_MASTER](../04-configuration/RPC_ENDPOINTS_MASTER.md) | When The Order portal is deployed: add NPMplus proxy host and document IP:port in RPC_ENDPOINTS_MASTER and ALL_VMIDS_ENDPOINTS. |
| **Sankofa cutover plan** | [SANKOFA_CUTOVER_PLAN](../04-configuration/SANKOFA_CUTOVER_PLAN.md) | Replace `<TARGET_IP>`, `<TARGET_PORT>`, and table TBDs with actual Sankofa service IPs/ports when deployed. |
| **the-order.sankofa.nexus** | [ALL_VMIDS_ENDPOINTS](../04-configuration/ALL_VMIDS_ENDPOINTS.md), [RPC_ENDPOINTS_MASTER](../04-configuration/RPC_ENDPOINTS_MASTER.md) | **Done 2026-03-27:** NPM → 10210 `192.168.11.39:80` (HAProxy → portal :3000). Keep docs in sync if routing changes. |
| **Sankofa cutover plan** | [SANKOFA_CUTOVER_PLAN](../04-configuration/SANKOFA_CUTOVER_PLAN.md) | **Done 2026-03-27:** v1.1 lists live backends (incl. The Order via 10210). Legacy API examples may still contain `<TARGET_*>` placeholders—substitute real values if you reuse them. |
| **sankofa.nexus / phoenix.sankofa.nexus** | [ALL_VMIDS_ENDPOINTS](../04-configuration/ALL_VMIDS_ENDPOINTS.md), [RPC_ENDPOINTS_MASTER](../04-configuration/RPC_ENDPOINTS_MASTER.md), [DNS_NPMPLUS_VM](../04-configuration/DNS_NPMPLUS_VM_COMPREHENSIVE_ARCHITECTURE.md) | **Doc fix done:** Correct targets: sankofa → 192.168.11.51:3000 (VMID 7801), phoenix → 192.168.11.50:4000 (VMID 7800). **Operator:** Ensure NPMplus proxy hosts use these, not 192.168.11.140. Only explorer.d-bis.org → .140. |
| **Public blocks #2#6** | [NETWORK_ARCHITECTURE](../02-architecture/NETWORK_ARCHITECTURE.md), [NETWORK_CONFIGURATION_MASTER](../11-references/NETWORK_CONFIGURATION_MASTER.md) | Document when blocks are assigned or mark as “reserved”. |
| **PROXMOX_HOST / PROXMOX_TOKEN_SECRET** | smom-dbis-138-proxmox/README.md | Keep as `proxmox.example.com`, `your-token-secret`; document in deployment guide. |

View File

@@ -65,7 +65,7 @@
| # | Action | When |
|---|--------|------|
| R21 | When The Order is deployed: NPMplus proxy host; document in RPC_ENDPOINTS_MASTER and ALL_VMIDS_ENDPOINTS; replace SANKOFA_CUTOVER_PLAN TBDs | Sankofa/The Order go-live |
| R21 | **Done 2026-03:** NPMplus + ALL_VMIDS + RPC_ENDPOINTS_MASTER + SANKOFA_CUTOVER_PLAN v1.1 | Complete |
| R22 | Document or configure blocks #2#6 in NETWORK_ARCHITECTURE and NETWORK_CONFIGURATION_MASTER (or mark reserved); see NETWORK_PLACEHOLDERS_DECISION | When decided |
## Quick wins (R23)

View File

@@ -166,7 +166,7 @@ See **Part 2** and [GAPS_AND_RECOMMENDATIONS_CONSOLIDATED](../GAPS_AND_RECOMMEND
| # | Recommendation | Action |
|---|----------------|--------|
| R21 | **Sankofa / The Order** | When The Order portal is deployed, add NPMplus proxy host and document in RPC_ENDPOINTS_MASTER and ALL_VMIDS_ENDPOINTS; replace SANKOFA_CUTOVER_PLAN TBDs with actual IPs/ports. |
| R21 | **Sankofa / The Order** | **Done 2026-03:** NPMplus + docs (ALL_VMIDS, RPC_ENDPOINTS_MASTER, SANKOFA_CUTOVER_PLAN v1.1). HAProxy: `provision-order-haproxy-10210.sh`. |
| R22 | **Network placeholders** | Document or configure blocks #2#6 in NETWORK_ARCHITECTURE and NETWORK_CONFIGURATION_MASTER when assigned. |
### 2.9 Quick wins (code)

View File

@@ -108,13 +108,12 @@
---
## 2. Sankofa cutover (missing TBDs)
## 2. Sankofa cutover (**documented — 2026-03**)
| | Detail |
|---|--------|
| **Needed** | For each Sankofa domain: target VMID, target IP, target port, service type. |
| **Missing** | **the-order.sankofa.nexus:** VMID, IP, port, service type still **TBD** in [SANKOFA_CUTOVER_PLAN.md](../04-configuration/SANKOFA_CUTOVER_PLAN.md). Other four domains have values (e.g. 7801/192.168.11.51/3000 for sankofa.nexus). |
| **Where to get** | Deploy The Order portal; assign VMID and IP; document in SANKOFA_CUTOVER_PLAN.md table; then run cutover steps (replace proxy backends in NPMplus). |
| **Status** | Live backends in [SANKOFA_CUTOVER_PLAN.md](../04-configuration/SANKOFA_CUTOVER_PLAN.md) v1.1, [ALL_VMIDS_ENDPOINTS.md](../04-configuration/ALL_VMIDS_ENDPOINTS.md), [RPC_ENDPOINTS_MASTER.md](../04-configuration/RPC_ENDPOINTS_MASTER.md). The Order: NPM → **10210** `192.168.11.39:80` → portal **192.168.11.51:3000**. |
| **Ongoing** | If IPs/VMIDs change, run `scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh` and update the master docs. |
---
@@ -227,8 +226,8 @@
- Run `address-all-remaining-502s.sh --run-besu-fix --e2e` from LAN.
- Run Blockscout verification script.
4. **Fill TBDs**
- Sankofa: set the-order.sankofa.nexus target (VMID, IP, port) in SANKOFA_CUTOVER_PLAN.md.
4. **Sankofa / Order**
- **Done:** targets documented; refresh NPM with `update-npmplus-proxy-hosts-api.sh` after infra changes.
- CCIP: collect per-chain addresses (CCIP directory) and fund deployer wallets for Gnosis/Celo/Wemix.
5. **dbis_core**

View File

@@ -78,11 +78,11 @@
| Question | Answer |
|----------|--------|
| **What is it?** | Sankofa and The Order services deployed; DNS and NPMplus point to real IPs/ports; replace TBDs in docs. |
| **Prerequisites** | Sankofa and The Order deployed; IPs and ports known (e.g. sankofa 192.168.11.51:3000 VMID 7801, phoenix 192.168.11.50:4000 VMID 7800 — already in docs). |
| **Who** | Ops when services are live. |
| **Steps to complete** | 1. Deploy Sankofa/The Order per your deployment process. 2. In [SANKOFA_CUTOVER_PLAN](../04-configuration/SANKOFA_CUTOVER_PLAN.md): replace `<TARGET_IP>`, `<TARGET_PORT>`, table TBDs with actual IPs/ports. 3. In NPMplus: ensure proxy hosts for sankofa.nexus and phoenix.sankofa.nexus point to 192.168.11.51:3000 and 192.168.11.50:4000 (not .140). 4. When The Order portal is deployed: add NPMplus proxy for the-order.sankofa.nexus; document in [RPC_ENDPOINTS_MASTER](../04-configuration/RPC_ENDPOINTS_MASTER.md) and [ALL_VMIDS_ENDPOINTS](../04-configuration/ALL_VMIDS_ENDPOINTS.md). |
| **Where to update when done** | [PLACEHOLDERS](PLACEHOLDERS_AND_COMPLETION_MASTER_LIST.md) §2; [GAPS](../GAPS_AND_RECOMMENDATIONS_CONSOLIDATED.md) §2.12.2; [REMAINING](REMAINING_COMPONENTS_TASKS_AND_RECOMMENDATIONS.md) R21. |
| **What is it?** | Sankofa zone on production backends; NPMplus and master docs aligned (incl. The Order via **10210** HAProxy). |
| **Prerequisites** | LAN + `NPM_PASSWORD` for fleet updater; portal 7801 and Phoenix 7800 healthy. |
| **Who** | Ops for NPM refresh after any VM/IP change. |
| **Steps to complete** | **Done 2026-03:** See [SANKOFA_CUTOVER_PLAN](../04-configuration/SANKOFA_CUTOVER_PLAN.md) v1.1. Maintain with `scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh`. Bypass Order HAProxy if needed: `THE_ORDER_UPSTREAM_IP=192.168.11.51 THE_ORDER_UPSTREAM_PORT=3000`. |
| **Where to update when done** | [PLACEHOLDERS](PLACEHOLDERS_AND_COMPLETION_MASTER_LIST.md) §2; [GAPS](../GAPS_AND_RECOMMENDATIONS_CONSOLIDATED.md) §2.12.2; R21 marked **done** in [REMAINING_COMPONENTS](REMAINING_COMPONENTS_TASKS_AND_RECOMMENDATIONS.md). |
---
@@ -295,7 +295,7 @@
| Trust official | Open PR to trustwallet/wallet-core with registry entry (coinId 10000138, chainId 138); run codegen/tests. |
| CoinGecko/CMC | Submit chain + tokens via CoinGecko (and CMC) process; use COINGECKO_SUBMISSION_GUIDE and token docs. |
| Consensys | Use CONSENSYS_OUTREACH_PACKAGE; contact Consensys for Swaps/Bridge support for 138. |
| Sankofa cutover | When deployed: replace TBDs in SANKOFA_CUTOVER_PLAN; set NPMplus proxies to .51/.50; add the-order when live. |
| Sankofa cutover | **Done:** v1.1 cutover plan + NPM; Order via .39:80 (10210). Re-run updater after changes. |
| Blockscout verify | From LAN: `source smom-dbis-138/.env; ./scripts/verify/run-contract-verification-with-proxy.sh`. |
| Multicall vs Oracle | Check explorer for 0x99b35...; document which contract it is in CONTRACT_ADDRESSES_REFERENCE. |
| AlltraAdapter fee | After deploy: call `setBridgeFee(fee_wei)`; set ALLTRA_BRIDGE_FEE in .env; document in PLACEHOLDERS_AND_TBD. |

View File

@@ -0,0 +1,143 @@
# Proxmox VE — Operational deployment template
**Last Updated:** 2026-03-25
**Status:** Active — ties hypervisors, LAN/WAN, cluster peering, Chain 138 Besu tiers, NPMplus ingress, FQDNs, and deployment gates into one place.
**Machine-readable:** [`config/proxmox-operational-template.json`](../../config/proxmox-operational-template.json) (sync when you change VMIDs/IPs/FQDNs).
**Authoritative detail (do not drift):**
- VMID, port, status tables: [`docs/04-configuration/ALL_VMIDS_ENDPOINTS.md`](../04-configuration/ALL_VMIDS_ENDPOINTS.md)
- Shell/env single source: [`config/ip-addresses.conf`](../../config/ip-addresses.conf)
- Edge, port forwards, four NPMplus picture: [`docs/11-references/NETWORK_CONFIGURATION_MASTER.md`](../11-references/NETWORK_CONFIGURATION_MASTER.md)
- Contract deploy order / gates: [`docs/03-deployment/DEPLOYMENT_ORDER_OF_OPERATIONS.md`](DEPLOYMENT_ORDER_OF_OPERATIONS.md)
---
## 1. Proxmox VE hosts (management)
| Hostname | MGMT IP | Proxmox UI | Cluster | Role (target) |
|----------|---------|------------|---------|----------------|
| ml110 | 192.168.11.10 | https://192.168.11.10:8006 | h (legacy) | Planned WAN aggregator (OPNsense/pfSense); **migrate CT/VM off before repurpose** |
| r630-01 | 192.168.11.11 | https://192.168.11.11:8006 | h | Primary: Chain 138 RPC/CCIP-adjacent workloads, Sankofa Phoenix stack, much of DBIS |
| r630-02 | 192.168.11.12 | https://192.168.11.12:8006 | h | Firefly, MIM4U, Mifos LXC, extra NPMplus instances, supporting infra |
**LAN:** 192.168.11.0/24, gateway **192.168.11.1** (UDM Pro), VLAN 11. Extended node IP plan (r630-03 …): `config/ip-addresses.conf` comments.
---
## 2. Cluster peering (Corosync / quorum)
| Item | Value / note |
|------|----------------|
| Cluster name | **h** (verify live: `pvecm status`) |
| Ring | Typically same L2/L3 as MGMT — **192.168.11.0/24** |
| UDP ports | **54055412** between all nodes (+ SSH 22, API **8006** TCP) |
| Quorum | Odd node count preferred; during ml110 removal use 2-node awareness (risk window) or add qdevice |
Cluster and UDM: [`docs/04-configuration/UDM_PRO_PROXMOX_CLUSTER.md`](../04-configuration/UDM_PRO_PROXMOX_CLUSTER.md). **Live inventory:** [`docs/04-configuration/ALL_VMIDS_ENDPOINTS.md`](../04-configuration/ALL_VMIDS_ENDPOINTS.md), [`config/proxmox-operational-template.json`](../../config/proxmox-operational-template.json).
---
## 3. Chain 138 Besu — peering model (summary)
| Layer | VMID range (typical) | IPv4 pattern | P2P |
|--------|----------------------|--------------|-----|
| Validators | 10001004 | 192.168.11.100104 | 30303 — **to sentries**, not raw public |
| Sentries | 15001506 | .150.154, .213.214 | Boundary / fan-out |
| Core RPC (deploy) | 2101 | **192.168.11.211** | 8545/8546 + 30303 |
| Core RPC (Nathan core-2) | 2102 | **192.168.11.212** | NPMplus **10235** / tunnel |
| Public RPC | 2201 | **192.168.11.221** | Frontends / bridge / read-mostly |
| Named RPC | 23032308 | .233.238 | Partner-dedicated |
| ThirdWeb stack | 24002403 | .240.243 | Includes translator/nginx on 2400 |
Canonical roles and adjacency rules: [`docs/02-architecture/CHAIN138_CANONICAL_NETWORK_ROLES_VALIDATORS_SENTRY_AND_RPC.md`](../02-architecture/CHAIN138_CANONICAL_NETWORK_ROLES_VALIDATORS_SENTRY_AND_RPC.md).
---
## 4. NPMplus and public ingress
| VMID | Internal IP(s) | Public IP (typical) | Purpose |
|------|----------------|---------------------|---------|
| 10233 | 192.168.11.166 / **.167** | 76.53.10.36 | Main d-bis.org, explorer, Option B RPC, MIM4U |
| 10234 | 192.168.11.168 | 76.53.10.37 | Secondary HA (confirm running) |
| 10235 | 192.168.11.169 | 76.53.10.38 (alt **76.53.10.42**) | rpc-core-2, Alltra, HYBX |
| 10236 | 192.168.11.170 | 76.53.10.40 | Dev / Codespaces tunnel, Gitea, Proxmox admin |
| 10237 | 192.168.11.171 | (tunnel/Mifos) | mifos.d-bis.org → VMID 5800 |
UDM Pro forwards **80 / 443** (and **81** where documented) to the matching internal IP. Detail: [`docs/04-configuration/NPMPLUS_FOUR_INSTANCES_MASTER.md`](../04-configuration/NPMPLUS_FOUR_INSTANCES_MASTER.md).
---
## 5. FQDN → backend (high level)
Use the full table in **ALL_VMIDS_ENDPOINTS** (“NPMplus Endpoint Configuration Reference”). Critical correctness checks:
- **explorer.d-bis.org** → VMID **5000**, **192.168.11.140** (not Sankofa IPs).
- **sankofa.nexus** / **phoenix.sankofa.nexus** → VMID **7801** / **7800** at **.51:3000** / **.50:4000**.
- **rpc-http-prv / rpc-ws-prv** → **2101** (.211); **rpc-http-pub / rpc-ws-pub****2201** (.221).
- **rpc.public-0138.defi-oracle.io** → **2400** **192.168.11.240:443** (update NPM if still pointing at decommissioned IPs).
**the-order.sankofa.nexus:** NPMplus → order HAProxy **10210** @ **192.168.11.39:80** (proxies to Sankofa portal **192.168.11.51:3000**). See `scripts/deployment/provision-order-haproxy-10210.sh`.
### 5.1 Order stack (live VMIDs, r630-01 unless noted)
| VMID | Hostname | IP | Role (short) |
|------|----------|-----|----------------|
| 10030 | order-identity | 192.168.11.40 | Identity |
| 10040 | order-intake | 192.168.11.41 | Intake |
| 10050 | order-finance | 192.168.11.49 | Finance |
| 10060 | order-dataroom | 192.168.11.42 | Dataroom |
| 10070 | order-legal | **192.168.11.87** | Legal — **moved off .54 2026-03-25** (`IP_ORDER_LEGAL`); .54 is **only** VMID 7804 gov-portals |
| 10080 | order-eresidency | 192.168.11.43 | eResidency |
| 10090 | order-portal-public | 192.168.11.36 | Public portal |
| 10091 | order-portal-internal | 192.168.11.35 | Internal portal |
| 10092 | order-mcp-legal | 192.168.11.37 | MCP legal |
| 10200 | order-prometheus | 192.168.11.46 | Metrics |
| 10201 | order-grafana | 192.168.11.47 | Dashboards |
| 10202 | order-opensearch | 192.168.11.48 | Search |
| 10210 | order-haproxy | 192.168.11.39 | Edge / HAProxy |
**Redis:** `ORDER_REDIS_IP` = 192.168.11.38 in `ip-addresses.conf` — bind to live VMID via `pct list` / audit script.
---
## 6. Deployment requirements (cross-domain)
### 6.1 Platform (Proxmox / network)
- [ ] All cluster nodes **quorate**; storage sufficient for CT/VM disks (local-lvm / future Ceph per master plan).
- [ ] **vmbr0** VLAN-aware; each workload IP **unique** on 192.168.11.0/24 (see ALL_VMIDS conflict section).
- [ ] UDM Pro routes and port-forwards match **NETWORK_CONFIGURATION_MASTER**.
- [ ] NPMplus proxy host rows match **ALL_VMIDS** (no Blockscout IP on Sankofa hostnames).
### 6.2 Chain 138 (contracts / ops)
- [ ] **Core RPC** 2101 reachable: `http://192.168.11.211:8545` for **deploy only** (not public RPC).
- [ ] `smom-dbis-138/.env`: `PRIVATE_KEY`, `RPC_URL_138`, nonce discipline — **DEPLOYMENT_ORDER_OF_OPERATIONS** Phase 0.
- [ ] Optional: `./scripts/deployment/preflight-chain138-deploy.sh` before any broadcast.
### 6.3 Application / operator
- [ ] Repo **`.env`** + **`smom-dbis-138/.env`** for operator scripts (`scripts/lib/load-project-env.sh`).
- [ ] Blockscout / verify / NPM backup scripts per **OPERATOR_READY_CHECKLIST** when doing release ops.
---
## 7. Maintaining this template
1. Change **ALL_VMIDS_ENDPOINTS** and/or **ip-addresses.conf** first (operator truth).
2. Update **`config/proxmox-operational-template.json`** so automation (future CMDB, checks) stays aligned.
3. Run **`./scripts/validation/validate-config-files.sh`** (includes JSON shape check for the template).
4. **Live diff (read-only, SSH):** from repo root on a host with SSH to Proxmox nodes: **`bash scripts/verify/audit-proxmox-operational-template.sh`**. Compares template VMIDs to `pct`/`qm` lists on ML110 + R630s (override **`PROXMOX_HOSTS`** if needed).
---
## 8. Related runbooks
| Topic | Doc |
|-------|-----|
| Operational runbooks index | [`OPERATIONAL_RUNBOOKS.md`](OPERATIONAL_RUNBOOKS.md) |
| Phoenix / Sankofa deploy | [`PHOENIX_DEPLOYMENT_RUNBOOK.md`](PHOENIX_DEPLOYMENT_RUNBOOK.md) |
| NPMplus health | [`docs/04-configuration/NPMPLUS_QUICK_REF.md`](../04-configuration/NPMPLUS_QUICK_REF.md) |
| 13-node / HA roadmap | [`docs/02-architecture/R630_13_NODE_DOD_HA_MASTER_PLAN.md`](../02-architecture/R630_13_NODE_DOD_HA_MASTER_PLAN.md) |

View File

@@ -0,0 +1,117 @@
# Public sector live deployment checklist (Complete Credential, SMOA, Phoenix)
**Last updated:** 2026-03-23
**Related:** [PUBLIC_SECTOR_TENANCY_MARKETPLACE_AND_DEPLOYMENT_BASELINE.md](../02-architecture/PUBLIC_SECTOR_TENANCY_MARKETPLACE_AND_DEPLOYMENT_BASELINE.md), [COMPLETE_CREDENTIAL_EIDAS_PROGRAM_REPOS.md](../11-references/COMPLETE_CREDENTIAL_EIDAS_PROGRAM_REPOS.md), [DEPLOY_CONFIRM_AND_FULL_E2E_RUNBOOK.md](../00-meta/DEPLOY_CONFIRM_AND_FULL_E2E_RUNBOOK.md), [`config/public-sector-program-manifest.json`](../../config/public-sector-program-manifest.json)
This checklist tracks **proxmox-repo automation** and **sibling repos** (`../complete-credential`, `../smoa`). Rows marked **Done (session)** were executed from an operator host with LAN access unless noted.
---
## Execution log (2026-03-23)
| Action | Result |
|--------|--------|
| Sankofa `api` + `portal` (workstation) | API: `websocket.ts` imports `logger`; GraphQL/schema fixes under `api/src`. Portal: Apollo + dashboard GraphQL, UI primitives, **`root: true`** `.eslintrc.json` with **`@typescript-eslint` + strict `no-explicit-any` / `no-console` / a11y / `import/order`** (optional hardening: lib clients typed with `unknown`, form `htmlFor`/`id`, escaped entities). **`pnpm exec tsc --noEmit`** + **`pnpm build`** clean. **Deploy:** sync `portal/` (+ lockfile) to CT **7801**, `pnpm install && pnpm build`, restart `sankofa-portal`; sync **7800** API if needed |
## Execution log (2026-03-26)
| Action | Result |
|--------|--------|
| `./scripts/run-all-operator-tasks-from-lan.sh` (live, no `--dry-run`) | Exit 0 (~36 min); W0-1 NPMplus RPC/proxy host updates; W0-3 live NPMplus backup; Blockscout verification step ran |
| NPMplus update script | Some hosts logged duplicate-create then PUT recovery; `rpc.tw-core.d-bis.org` and `*.tw-core.d-bis.org` showed repeated failures — **review those rows in NPM UI** if traffic depends on them |
| `scripts/maintenance/diagnose-vm-health-via-proxmox-ssh.sh` | Completed: Phoenix CTs **78007803** running on r630-01; NPMplus **10233** up; port 81 check OK |
| `scripts/maintenance/npmplus-verify-port81.sh` | **Restored** in repo; loopback :81 returns HTTP 301 (redirect) — treated as reachable |
| `pct exec 7800` / `7801`: `ss -tlnp` | **As of 2026-03-26 session:** no listeners. **As of 2026-03-23 follow-up:** **7800** API can reach `active` + `/health` on **:4000** when `sankofa-api` is deployed; **7801** portal needs **current** portal tree + successful **`pnpm build`** on the CT (see 2026-03-23 log row above) |
| `pct exec 7802` Keycloak | `http://127.0.0.1:8080/`**200**; `/health/ready` → 404 (version may use different health path) |
| `./scripts/run-completable-tasks-from-anywhere.sh` | Exit 0 |
| `E2E_ACCEPT_502_INTERNAL=1 ./scripts/verify/verify-end-to-end-routing.sh` | 0 failed; report `docs/04-configuration/verification-evidence/e2e-verification-20260325_182512/` |
| `./scripts/verify/run-contract-verification-with-proxy.sh` | Exit 0 |
| `complete-credential` Phase 1 compose + `run-phase1-synthetic.sh` | OK (operator console 8087 = 200) |
| `../smoa`: `./gradlew :app:assembleDebug` | BUILD SUCCESSFUL; APK: `smoa/app/build/outputs/apk/debug/app-debug.apk` |
---
## Execution log (2026-03-25)
| Action | Result |
|--------|--------|
| RPC `192.168.11.221:8545` / `192.168.11.211:8545` | HTTP 201 |
| SSH `root@192.168.11.10` / `.11` | OK (BatchMode) |
| `./scripts/run-completable-tasks-from-anywhere.sh` | Exit 0 |
| `./scripts/verify/check-contracts-on-chain-138.sh` | 59/59 present |
| `E2E_ACCEPT_502_INTERNAL=1 ./scripts/verify/verify-end-to-end-routing.sh` | 37 domains, 0 failed; report under `docs/04-configuration/verification-evidence/e2e-verification-20260325_165153/` |
| `https://phoenix.sankofa.nexus/`, `https://sankofa.nexus/` | HTTP 200 |
| `http://192.168.11.50:4000/health`, `:51:3000`, `:52:8080/health/ready` | No HTTP response from operator host (hosts ping; services may be down, firewalled, or not bound) — **re-check on Proxmox / in-container** |
| `./scripts/verify/backup-npmplus.sh --dry-run` | OK |
| `./scripts/verify/run-contract-verification-with-proxy.sh` | Exit 0 |
| `./scripts/run-all-operator-tasks-from-lan.sh --dry-run` | Printed wave0 + verify sequence |
| `cd smom-dbis-138 && forge test --match-path 'test/e2e/*.sol'` | Exit 0 |
| `cd ../smoa && ./gradlew smoaVerify --no-daemon` | Exit 0 |
| `complete-credential`: `git submodule status` | Submodules present on commits |
| `docker compose -f integration/docker-compose.phase1.yml config` | Valid |
| `docker compose -f integration/docker-compose.phase1.yml up -d` | All Phase 1 containers up |
| Rebuild + recreate `cc-operator-console`; `./integration/run-phase1-synthetic.sh` | OK |
---
## Checklist
| ID | Task | Status |
|----|------|--------|
| A1 | LAN / VPN; Proxmox SSH | Done (session) |
| A2 | Root `.env` + `smom-dbis-138/.env` for operator | Operator to confirm secrets present |
| A3 | `config/public-sector-program-manifest.json` valid | Done (completable) |
| B1 | NPMplus proxy + TLS for public FQDNs | **Done (2026-03-26)**`run-wave0-from-lan.sh` / update script applied; spot-check `rpc.tw-core` / `*.tw-core` in NPM if needed |
| B2 | `scripts/verify/backup-npmplus.sh` (live) | **Done (2026-03-26)** — W0-3 as part of `run-all-operator-tasks-from-lan.sh` |
| B3 | `scripts/maintenance/npmplus-verify-port81.sh` | **Done** — script restored; SSH `pct exec 10233` loopback :81 |
| C1 | Phoenix stack VMIDs 78007803 per `SERVICE_DESCRIPTIONS.md` | **7802 Keycloak:** HTTP 200 on `/` inside CT. **7800 API:** deploy/restart `sankofa-api` — expect listener **:4000**. **7801 portal:** deploy latest portal artifact (see 2026-03-23 log) — expect **:3000** |
| C2 | Keycloak realms: admin / tenant / org-unit RBAC | Product + IdP work — not automated here |
| C3 | Phoenix API + portal wired; GraphQL `/graphql`, `/health` | **API:** curl `http://192.168.11.50:4000/health` (and `/graphql` as needed). **Portal:** after **7801** build, curl `http://192.168.11.51:3000/` |
| C4 | Service catalog SKUs + entitlements (billing optional) | Product — see tenancy baseline G2 |
| D1 | SMOA LXC per `smoa/backend/docs/LXC-PROXMOX-CONTAINERS.md` | Deploy on Proxmox |
| D2 | SMOA API behind NPM | After D1 |
| D3 | Release APK + download URL or MDM | **Debug APK built (2026-03-26):** `../smoa/app/build/outputs/apk/debug/app-debug.apk` — publish via CI signed release + NPM/static URL or MDM |
| D4 | Device E2E against prod API | After D2D3 |
| E1 | `complete-credential` submodules initialized | Done (session) |
| E2 | Phase 1 Docker stack local/CI | Done (session) — not yet Proxmox production |
| E3 | `./integration/run-phase1-synthetic.sh` after console rebuild | Done (session) |
| E4 | Production slice / dedicated LXC for `cc-*` | Architecture choice (profile A/B/C) |
| F1 | Chain 138 on-chain contract check | Done (session) |
| F2 | Blockscout verification | Done (session) |
| F3 | Public E2E routing | Done (session, 502-tolerant flag) |
| G1 | Logs, metrics, DB backups for Phoenix + SMOA + CC DBs | Operational runbooks |
| G2 | Incident ownership per stack | Process |
---
## Quick commands (repo root unless noted)
```bash
./scripts/run-completable-tasks-from-anywhere.sh
source scripts/lib/load-project-env.sh && ./scripts/verify/check-contracts-on-chain-138.sh
E2E_ACCEPT_502_INTERNAL=1 ./scripts/verify/verify-end-to-end-routing.sh
./scripts/verify/run-contract-verification-with-proxy.sh
./scripts/verify/backup-npmplus.sh --dry-run # then run without --dry-run
```
**Complete Credential (sibling clone):**
```bash
cd ../complete-credential
docker compose -f integration/docker-compose.phase1.yml up -d --build
./integration/run-phase1-synthetic.sh
```
**SMOA:**
```bash
cd ../smoa && ./gradlew smoaVerify --no-daemon
```
---
## Follow-ups
1. **Phoenix LAN services:** From a host on the same L2 as `192.168.11.5053`, curl `/health` and portal port **3000**; if down, start CTs/VMs on Proxmox and confirm process listeners.
2. **Operator full wave:** `./scripts/run-all-operator-tasks-from-lan.sh` only when NPM RPC fix + backup + verify are intentionally desired (mutates NPM).
3. **Production Complete Credential:** Move from laptop Docker to **dedicated LXC** and NPM routes per deployment profile.

View File

@@ -1,9 +1,11 @@
# Complete VMID and Endpoints Reference
**Last Updated:** 2026-02-12
**Last Updated:** 2026-03-26
**Document Version:** 1.2
**Status:** Active Documentation — **Master (source of truth)** for VMID, IP, port, and domain mapping. See [MASTER_DOCUMENTATION_INDEX.md](../00-meta/MASTER_DOCUMENTATION_INDEX.md).
**Operational template (hosts, peering, deployment gates, JSON):** [../03-deployment/PROXMOX_VE_OPERATIONAL_DEPLOYMENT_TEMPLATE.md](../03-deployment/PROXMOX_VE_OPERATIONAL_DEPLOYMENT_TEMPLATE.md) · [`config/proxmox-operational-template.json`](../../config/proxmox-operational-template.json)
---
**Date**: 2026-01-20
@@ -46,6 +48,8 @@
**Note**: NPMplus primary is on VLAN 11 (192.168.11.167). Secondary NPMplus instance on r630-02 for HA configuration.
**Operational note (2026-03-26):** if `192.168.11.167:81` accepts TCP but hangs without returning HTTP, CT `10233` may be wedged even when networking looks healthy. Rebooting it from `r630-01` with `pct reboot 10233` restored the expected `301` on port `81` and unblocked the API updater.
---
## RPC Translator Supporting Services
@@ -198,7 +202,7 @@ The following VMIDs have been permanently removed:
|------|------------|----------|--------|-----------|---------|
| 10100 | 192.168.11.105 | dbis-postgres-primary | ✅ Running | PostgreSQL: 5432 | Primary database |
| 10101 | 192.168.11.106 | dbis-postgres-replica-1 | ✅ Running | PostgreSQL: 5432 | Database replica |
| 10120 | 192.168.11.120 | dbis-redis | ✅ Running | Redis: 6379 | Cache layer |
| 10120 | 192.168.11.125 | dbis-redis | ✅ Running | Redis: 6379 | Cache layer |
| 10130 | 192.168.11.130 | dbis-frontend | ✅ Running | Web: 80, 443 | Frontend admin console |
| 10150 | 192.168.11.155 | dbis-api-primary | ✅ Running | API: 3000 | Primary API server |
| 10151 | 192.168.11.156 | dbis-api-secondary | ✅ Running | API: 3000 | Secondary API server |
@@ -245,12 +249,14 @@ The following VMIDs have been permanently removed:
**Public Domains** (NPMplus routing):
- `sankofa.nexus` → Routes to `http://192.168.11.51:3000` (Sankofa Portal/VMID 7801) ✅
- `www.sankofa.nexus`Routes to `http://192.168.11.51:3000` (Sankofa Portal/VMID 7801)
- `www.sankofa.nexus`Same upstream as apex; NPM **`advanced_config`** issues **301** to **`https://sankofa.nexus`** (preserve path/query via `$request_uri`).
- `phoenix.sankofa.nexus` → Routes to `http://192.168.11.50:4000` (Phoenix API/VMID 7800) ✅
- `www.phoenix.sankofa.nexus`Routes to `http://192.168.11.50:4000` (Phoenix API/VMID 7800)
- `the-order.sankofa.nexus` → ⚠️ **TBD** (not yet configured)
- `www.phoenix.sankofa.nexus`Same upstream; **301** to **`https://phoenix.sankofa.nexus`**.
- `the-order.sankofa.nexus` / `www.the-order.sankofa.nexus` → OSJ management portal (secure auth). App source: **the_order** at `~/projects/the_order`. NPMplus default upstream: **order-haproxy** `http://192.168.11.39:80` (VMID **10210**), which proxies to Sankofa portal `http://192.168.11.51:3000` (7801). Fallback: set `THE_ORDER_UPSTREAM_IP` / `THE_ORDER_UPSTREAM_PORT` to `.51` / `3000` if HAProxy is offline. **`www.the-order.sankofa.nexus`** → **301** **`https://the-order.sankofa.nexus`** (same as `www.sankofa` / `www.phoenix`).
- `studio.sankofa.nexus` → Routes to `http://192.168.11.72:8000` (Sankofa Studio / VMID 7805)
**Public verification evidence (2026-03-26):** `bash scripts/verify/verify-end-to-end-routing.sh --profile=public` passed with `Failed: 0`; Sankofa root, Phoenix, Studio, and The Order returned `200`. See [verification_report.md](verification-evidence/e2e-verification-20260326_100057/verification_report.md).
**Service Details:**
- **Host:** r630-01 (192.168.11.11)
- **Network:** VLAN 11 (192.168.11.0/24)
@@ -261,6 +267,28 @@ The following VMIDs have been permanently removed:
---
### The Order — microservices (r630-01)
| VMID | IP Address | Hostname | Status | Endpoints | Purpose |
|------|------------|----------|--------|-----------|---------|
| 10030 | 192.168.11.40 | order-identity | ✅ Running | API | Identity |
| 10040 | 192.168.11.41 | order-intake | ✅ Running | API | Intake |
| 10050 | 192.168.11.49 | order-finance | ✅ Running | API | Finance |
| 10060 | 192.168.11.42 | order-dataroom | ✅ Running | Web: 80 | Dataroom |
| 10070 | **192.168.11.87** | order-legal | ✅ Running | API | Legal — **use `IP_ORDER_LEGAL` (.87); not .54** |
| 10080 | 192.168.11.43 | order-eresidency | ✅ Running | API | eResidency |
| 10090 | 192.168.11.36 | order-portal-public | ✅ Running | Web | Public portal |
| 10091 | 192.168.11.35 | order-portal-internal | ✅ Running | Web | Internal portal |
| 10092 | 192.168.11.37 | order-mcp-legal | ✅ Running | API | MCP legal |
| 10200 | 192.168.11.46 | order-prometheus | ✅ Running | 9090 | Metrics (`IP_ORDER_PROMETHEUS`; not Order Redis) |
| 10201 | 192.168.11.47 | order-grafana | ✅ Running | 3000 | Dashboards |
| 10202 | 192.168.11.48 | order-opensearch | ✅ Running | 9200 | Search |
| 10210 | 192.168.11.39 | order-haproxy | ✅ Running | 80 (HAProxy → portal :3000) | Edge for **the-order.sankofa.nexus**; HAProxy config via `config/haproxy/order-haproxy-10210.cfg.template` + `scripts/deployment/provision-order-haproxy-10210.sh` |
**Gov portals vs Order:** VMID **7804** alone uses **192.168.11.54** (`IP_GOV_PORTALS_DEV`). Order-legal must not use .54.
---
### Phoenix Vault Cluster (8640-8642)
| VMID | IP Address | Hostname | Status | Endpoints | Purpose |
@@ -368,7 +396,7 @@ Direct to RPC Nodes:
1. **192.168.11.50**: ✅ **RESOLVED**
- VMID 7800 (sankofa-api-1): 192.168.11.50 ✅ **UNIQUE**
- VMID 10070 (order-legal): Reassigned to 192.168.11.54
- VMID 10070 (order-legal): **192.168.11.87** (`IP_ORDER_LEGAL`) — moved off .54 2026-03-25 (ARP conflict with VMID 7804 gov-portals)
2. **192.168.11.51**: ✅ **RESOLVED**
- VMID 7801 (sankofa-portal-1): 192.168.11.51 ✅ **UNIQUE**
@@ -384,7 +412,7 @@ Direct to RPC Nodes:
**Verification:** ✅ All IPs verified unique, all services operational
**Documentation:** See `docs/archive/root-status-reports/IP_CONFLICT_RESOLUTION_COMPLETE.md` for historical details.
**IP conflicts (canonical):** [reports/status/IP_CONFLICTS_RESOLUTION_COMPLETE.md](../../reports/status/IP_CONFLICTS_RESOLUTION_COMPLETE.md); CCIP range move: [reports/status/IP_CONFLICTS_CCIP_RANGE_RESOLVED_20260201.md](../../reports/status/IP_CONFLICTS_CCIP_RANGE_RESOLVED_20260201.md). **Script:** `scripts/resolve-ip-conflicts.sh` (uses `config/ip-addresses.conf`).
---
@@ -481,7 +509,7 @@ This section lists all endpoints that should be configured in NPMplus, extracted
| `www.sankofa.nexus` | `192.168.11.51` | `http` | `3000` | ❌ No | Sankofa Portal (VMID 7801) ✅ **Deployed** |
| `phoenix.sankofa.nexus` | `192.168.11.50` | `http` | `4000` | ❌ No | Phoenix API - Cloud Platform Portal (VMID 7800) ✅ **Deployed** |
| `www.phoenix.sankofa.nexus` | `192.168.11.50` | `http` | `4000` | ❌ No | Phoenix API (VMID 7800) ✅ **Deployed** |
| `the-order.sankofa.nexus` | ⚠️ **TBD** | `http` | `TBD` | ❌ No | The Order Portal - ⚠️ **Not yet configured** |
| `the-order.sankofa.nexus`, `www.the-order.sankofa.nexus` | `192.168.11.39` (10210 HAProxy; default) or `192.168.11.51` (direct portal if env override) | `http` | `80` or `3000` | ❌ No | NPM → **.39:80** by default; HAProxy → **.51:3000** |
| `studio.sankofa.nexus` | `192.168.11.72` | `http` | `8000` | ❌ No | Sankofa Studio (FusionAI Creator) — VMID 7805 |
### Path-Based Routing Notes
@@ -509,7 +537,7 @@ Some domains use path-based routing in NPM configs:
| `explorer.d-bis.org` | 5000, 192.168.11.140:80 (web), :4000 (API) | — |
| `sankofa.nexus`, `www.sankofa.nexus` | 7801, 192.168.11.51:3000 | 192.168.11.140 (Blockscout) |
| `phoenix.sankofa.nexus`, `www.phoenix.sankofa.nexus` | 7800, 192.168.11.50:4000 | 192.168.11.140 (Blockscout) |
| `the-order.sankofa.nexus` | TBD (when The Order portal is deployed) | 192.168.11.140 (Blockscout) |
| `the-order.sankofa.nexus`, `www.the-order.sankofa.nexus` | 10210, 192.168.11.39:80 | 192.168.11.140 (Blockscout) |
| `studio.sankofa.nexus` | 7805, 192.168.11.72:8000 | — |
If NPMplus proxy hosts for sankofa.nexus or phoenix.sankofa.nexus currently point to 192.168.11.140, update them to the correct IP:port above. See [RPC_ENDPOINTS_MASTER.md](RPC_ENDPOINTS_MASTER.md) and table "Sankofa Phoenix Services" in this document.
@@ -518,7 +546,7 @@ If NPMplus proxy hosts for sankofa.nexus or phoenix.sankofa.nexus currently poin
---
**Last Updated**: 2026-01-18
**Last Updated**: 2026-03-27
**Maintained By**: Infrastructure Team
---

View File

@@ -1,7 +1,7 @@
# DNS → NPMplus → VM Comprehensive Architecture Table
**Last Updated:** 2026-01-31
**Document Version:** 1.0
**Last Updated:** 2026-03-27
**Document Version:** 1.1
**Status:** Active Documentation
---
@@ -62,7 +62,7 @@ Backend VMs (Various IPs) - Services with/without Nginx
| `www.sankofa.nexus` | A | 76.53.10.36 | DNS Only | 64 | 22 | `192.168.11.51:3000` | 7801 | 192.168.11.51 | sankofa-portal-1 | r630-01 | Sankofa Portal | ❌ No | 3000 | HTTP → 3000 |
| `phoenix.sankofa.nexus` | A | 76.53.10.36 | DNS Only | 51 | 23 | `192.168.11.50:4000` | 7800 | 192.168.11.50 | sankofa-api-1 | r630-01 | Phoenix API | ❌ No | 4000 | HTTP → 4000 |
| `www.phoenix.sankofa.nexus` | A | 76.53.10.36 | DNS Only | 63 | 24 | `192.168.11.50:4000` | 7800 | 192.168.11.50 | sankofa-api-1 | r630-01 | Phoenix API | ❌ No | 4000 | HTTP → 4000 |
| `the-order.sankofa.nexus` | A | 76.53.10.36 | DNS Only | 60 | 25 | ⚠️ TBD | TBD | TBD | — | — | The Order Portal | | | ⚠️ Configure when deployed |
| `the-order.sankofa.nexus` | A | 76.53.10.36 | DNS Only | 60 | 25 | `192.168.11.39:80` | 10210 | 192.168.11.39 | order-haproxy | r630-01 | The Order (HAProxy→portal) | ❌ No | 80 | HTTP → 80 → `.51:3000` |
| **defi-oracle.io Zone** |
| `rpc.public-0138.defi-oracle.io` | A | 76.53.10.36 | DNS Only | 56 | 26 | `192.168.11.240:443` | 2400 | 192.168.11.240 | thirdweb-rpc-1 | ml110 | ThirdWeb RPC | ✅ Yes | 443 | HTTPS → 443 |
@@ -291,7 +291,7 @@ nginx on VMID 2400 (192.168.11.240:443):
|--------|------------------|---------------------|
| `sankofa.nexus`, `www.sankofa.nexus` | 192.168.11.51:3000 (VMID 7801) | 192.168.11.140 |
| `phoenix.sankofa.nexus`, `www.phoenix.sankofa.nexus` | 192.168.11.50:4000 (VMID 7800) | 192.168.11.140 |
| `the-order.sankofa.nexus` | TBD when The Order portal is deployed | 192.168.11.140 |
| `the-order.sankofa.nexus`, `www.the-order.sankofa.nexus` | 192.168.11.39:80 (10210 HAProxy → .51:3000); www → 301 apex | 192.168.11.140 |
**Action:** If any Sankofa/Phoenix proxy host in NPMplus points to 192.168.11.140 (Blockscout), update it to the correct IP:port above. Only `explorer.d-bis.org` should point to 192.168.11.140.

View File

@@ -1,7 +1,7 @@
# DNS → NPMplus → VM Streamlined Architecture Table
**Last Updated:** 2026-01-31
**Document Version:** 1.0
**Last Updated:** 2026-03-27
**Document Version:** 1.1
**Status:** Active Documentation
---
@@ -59,17 +59,17 @@ Backend VMs (Various IPs) - Services with/without Nginx
| `secure.mim4u.org` | 59 | 19 | 7810 (mim-web-1) | 192.168.11.37 | 80 | ✅ Yes | MIM4U Secure Portal |
| `training.mim4u.org` | 61 | 20 | 7810 (mim-web-1) | 192.168.11.37 | 80 | ✅ Yes | MIM4U Training Portal |
### sankofa.nexus Zone (5 Domains) ⚠️
### sankofa.nexus zone (live backends)
| Domain | SSL Cert | NPMplus Proxy | Backend VM | IP | Port | Has Nginx | Service Type | Status |
|--------|----------|---------------|------------|----|----|-----------|--------------|--------|
| `sankofa.nexus` | 57 | 21 | ⚠️ TBD | 192.168.11.140 ⚠️ | 80 ⚠️ | ⚠️ TBD | Sankofa Main Portal | ⚠️ Not Deployed |
| `www.sankofa.nexus` | 64 | 22 | ⚠️ TBD | 192.168.11.140 ⚠️ | 80 ⚠️ | ⚠️ TBD | Sankofa Main Portal | ⚠️ Not Deployed |
| `phoenix.sankofa.nexus` | 51 | 23 | ⚠️ TBD | 192.168.11.140 ⚠️ | 80 ⚠️ | ⚠️ TBD | Phoenix Site | ⚠️ Not Deployed |
| `www.phoenix.sankofa.nexus` | 63 | 24 | ⚠️ TBD | 192.168.11.140 ⚠️ | 80 ⚠️ | ⚠️ TBD | Phoenix Site | ⚠️ Not Deployed |
| `the-order.sankofa.nexus` | 60 | 25 | ⚠️ TBD | 192.168.11.140 ⚠️ | 80 ⚠️ | ⚠️ TBD | The Order Portal | ⚠️ Not Deployed |
| Domain | SSL Cert (ex.) | NPMplus Proxy (ex.) | Backend VM | IP | Port | Has Nginx | Service type | Status |
|--------|------------------|---------------------|------------|----|------|-----------|--------------|--------|
| `sankofa.nexus` | 57 | 21 | 7801 | 192.168.11.51 | 3000 | ❌ No | Sankofa portal | ✅ Live |
| `www.sankofa.nexus` | 64 | 22 | 7801 | 192.168.11.51 | 3000 | ❌ No | Sankofa portal (301 apex) | ✅ Live |
| `phoenix.sankofa.nexus` | 51 | 23 | 7800 | 192.168.11.50 | 4000 | ❌ No | Phoenix API | ✅ Live |
| `www.phoenix.sankofa.nexus` | 63 | 24 | 7800 | 192.168.11.50 | 4000 | ❌ No | Phoenix API (301 apex) | ✅ Live |
| `the-order.sankofa.nexus` | 60 | 25 | 10210 | 192.168.11.39 | 80 | ❌ No | Order via HAProxy→portal | ✅ Live |
**⚠️ Note**: All Sankofa domains currently route to Blockscout (192.168.11.140) but services are NOT deployed. This is incorrect routing and needs to be fixed once services are deployed.
**Note:** SSL cert and NPM proxy **IDs** differ per installation—verify in NPM UI. **IPs/ports** are authoritative vs Blockscout (`.140` is only for `explorer.d-bis.org`). See [ALL_VMIDS_ENDPOINTS.md](ALL_VMIDS_ENDPOINTS.md).
### defi-oracle.io Zone (3 Domains)

View File

@@ -6,6 +6,11 @@
**Run E2E (public profile recommended):** `./scripts/verify/verify-end-to-end-routing.sh --profile=public` (from LAN with DNS or use `E2E_USE_SYSTEM_RESOLVER=1` and `/etc/hosts` per [E2E_DNS_FROM_LAN_RUNBOOK.md](E2E_DNS_FROM_LAN_RUNBOOK.md)).
**Run E2E (private/admin):** `./scripts/verify/verify-end-to-end-routing.sh --profile=private`.
**Latest verified public pass:** `2026-03-27` via `bash scripts/verify/verify-end-to-end-routing.sh --profile=public` with report at [verification_report.md](verification-evidence/e2e-verification-20260327_134032/verification_report.md). Result: exit `0`, `DNS passed: 38`, `Failed: 0`, `HTTPS passed: 19`, `Skipped / optional: 1` (after `run-all-operator-tasks-from-lan.sh` NPM sync; `rpc.defi-oracle.io` may log HTTP 405 on the verifier probe but stays non-failing for the profile).
**Latest verified private/admin pass:** `2026-03-27` via `bash scripts/verify/verify-end-to-end-routing.sh --profile=private` with report at [verification_report.md](verification-evidence/e2e-verification-20260327_134137/verification_report.md). Result: exit `0`, `DNS passed: 4`, `Failed: 0`.
**Evidence folders:** Each run creates `verification-evidence/e2e-verification-YYYYMMDD_HHMMSS/`. Commit the runs you want on record; older dirs can be removed locally to reduce noise (`scripts/maintenance/prune-e2e-verification-evidence.sh --dry-run` lists candidates). Routing truth is **not** inferred from old reports—use [ALL_VMIDS_ENDPOINTS.md](ALL_VMIDS_ENDPOINTS.md).
## Verification profiles
- **Public profile (default for routine E2E):** web, api, public RPC endpoints.
@@ -25,10 +30,11 @@
| secure.mim4u.org | web | https://secure.mim4u.org | MIM4U secure portal. |
| training.mim4u.org | web | https://training.mim4u.org | MIM4U training site. |
| sankofa.nexus | web | https://sankofa.nexus | Sankofa Nexus root / web. |
| www.sankofa.nexus | web | https://www.sankofa.nexus | Sankofa Nexus www. |
| phoenix.sankofa.nexus | web | https://phoenix.sankofa.nexus | Phoenix (Sankofa) web app. |
| www.phoenix.sankofa.nexus | web | https://www.phoenix.sankofa.nexus | Phoenix www. |
| the-order.sankofa.nexus | web | https://the-order.sankofa.nexus | Hosted client on the Sankofa Phoenix cloud services platform. |
| www.sankofa.nexus | web | https://www.sankofa.nexus | **301** to `https://sankofa.nexus` (canonical apex; NPM `advanced_config`). |
| phoenix.sankofa.nexus | web | https://phoenix.sankofa.nexus | Phoenix API (7800); E2E uses `/health` for HTTPS check. |
| www.phoenix.sankofa.nexus | web | https://www.phoenix.sankofa.nexus | **301** to `https://phoenix.sankofa.nexus` (canonical apex; NPM `advanced_config`). |
| the-order.sankofa.nexus | web | https://the-order.sankofa.nexus | OSJ management portal (secure auth); app **the_order** at `~/projects/the_order`. NPM upstream default: **order-haproxy** VMID **10210** `http://192.168.11.39:80` → portal **192.168.11.51:3000** (`provision-order-haproxy-10210.sh`). Override with `THE_ORDER_UPSTREAM_*` for direct portal if 10210 is down. |
| www.the-order.sankofa.nexus | web | https://www.the-order.sankofa.nexus | **301** to `https://the-order.sankofa.nexus` (canonical apex; NPM `advanced_config`). |
| studio.sankofa.nexus | web | https://studio.sankofa.nexus | Sankofa Studio (FusionAI Creator) at VMID 7805. |
| cacti-alltra.d-bis.org | web | https://cacti-alltra.d-bis.org | Cacti monitoring UI for Alltra. |
| cacti-hybx.d-bis.org | web | https://cacti-hybx.d-bis.org | Cacti monitoring UI for HYBX. |
@@ -75,6 +81,7 @@
| phoenix.sankofa.nexus | https://phoenix.sankofa.nexus |
| www.phoenix.sankofa.nexus | https://www.phoenix.sankofa.nexus |
| the-order.sankofa.nexus | https://the-order.sankofa.nexus |
| www.the-order.sankofa.nexus | https://www.the-order.sankofa.nexus |
| studio.sankofa.nexus | https://studio.sankofa.nexus |
| cacti-alltra.d-bis.org | https://cacti-alltra.d-bis.org |
| cacti-hybx.d-bis.org | https://cacti-hybx.d-bis.org |
@@ -148,6 +155,8 @@ When running from outside LAN or when backends are down, the following endpoints
**These known items do not block contract or pool completion.** Fix when convenient; E2E still passes when they are in `E2E_OPTIONAL_WHEN_FAIL`.
**2026-03-26 note:** after recovering NPMplus CT `10233` and re-running `update-npmplus-proxy-hosts-api.sh`, the latest public profile passed for all currently tested public domains, including Sankofa, Phoenix, Studio, The Order, DBIS, Mifos, and MIM4U.
| Endpoint | Typical cause |
|----------|----------------|
| dbis-admin.d-bis.org | 502 — backend (VMID 10130) unreachable from public |
@@ -155,9 +164,17 @@ When running from outside LAN or when backends are down, the following endpoints
| secure.d-bis.org | 502 — secure portal backend unreachable |
| mifos.d-bis.org | 502 — Mifos (VMID 5800) unreachable from public |
| mim4u.org, www.mim4u.org, secure.mim4u.org, training.mim4u.org | 502 — MIM4U web backends (192.168.11.37:80); non-blocking for contract/pool |
| studio.sankofa.nexus | 404 — FusionAI Creator (VMID 7805) path or proxy config |
| studio.sankofa.nexus | Historically 404 when the proxy misses `/studio/` or backend `192.168.11.72:8000`; verifier checks `/studio/`. Passed on 2026-03-26 after the NPMplus host update |
| phoenix.sankofa.nexus, www.phoenix.sankofa.nexus | (Resolved in verifier) Phoenix API (7800) is API-first; `verify-end-to-end-routing.sh` checks `https://…/health` (200), not `/`. A separate **marketing** site on the apex hostname (if desired) needs another upstream or app routes—NPM still points `phoenix.sankofa.nexus` at the Fastify API today. |
| the-order.sankofa.nexus | 502 if **10210** HAProxy or backend portal is down. NPM defaults upstream to **192.168.11.39:80** (order-haproxy). Fallback: `THE_ORDER_UPSTREAM_IP` / `THE_ORDER_UPSTREAM_PORT` = portal **192.168.11.51:3000** |
**WebSocket test-format warnings:** RPC WS tests may show "connection established but RPC test failed" when `wscat` is used: the upgrade succeeds but the scripts check for `"result"` in `wscat` output may miss due to output format or timing. Non-blocking for contract/pool. The script now also accepts Chain 138 chainId `0x8a` in output; WS connectivity is still confirmed by the upgrade (101).
**Verifier behavior (2026-03):** `openssl s_client` is wrapped with `timeout` (`E2E_OPENSSL_TIMEOUT` default 15s, `E2E_OPENSSL_X509_TIMEOUT` default 5s) so `--profile=private` / `--profile=all` cannot hang. **`--profile=all`** merges private and public `E2E_OPTIONAL_WHEN_FAIL` lists for temporary regressions. Install **`wscat`** (`npm install -g wscat`) for full WSS JSON-RPC checks; the script uses `wscat -n` to match `curl -k`, and now treats a clean `wscat` exit as a successful full WebSocket check even when the tool prints no JSON output.
**Canonical www redirects (2026-03):** For `www.sankofa.nexus`, `www.phoenix.sankofa.nexus`, and `www.the-order.sankofa.nexus`, HTTP **301**/**308** must include a **`Location`** whose host matches the expected apex (`E2E_WWW_CANONICAL_BASE` in `verify-end-to-end-routing.sh`). Wrong apex → HTTPS **fail**. Missing `Location`**warn**.
**Cloudflare bulk DNS:** `scripts/update-all-dns-to-public-ip.sh` supports **`--dry-run`** (no API calls) and **`--zone-only=sankofa.nexus`** (or `d-bis.org` | `mim4u.org` | `defi-oracle.io`) to limit blast radius. Env: `CLOUDFLARE_DNS_DRY_RUN=1`, `DNS_ZONE_ONLY=…`.
**WebSocket test-format warnings:** Older runs may show "connection established but RPC test failed" when `wscat` is used: the upgrade succeeded but the verifier expected printable `"result"` output. The script now accepts either explicit JSON output or a clean `wscat` exit, so current runs treat those WS checks as pass when the connection completes successfully. The script also accepts Chain 138 chainId `0x8a` in output.
### Remediation (when you want these to pass from public)
@@ -165,3 +182,4 @@ When running from outside LAN or when backends are down, the following endpoints
|------|--------|
| **502s (dbis-admin, dbis-api, secure, mifos)** | From LAN: `./scripts/maintenance/address-all-remaining-502s.sh [--run-besu-fix] [--e2e]` or `./scripts/maintenance/run-all-maintenance-via-proxmox-ssh.sh --e2e`. If NPMplus API is unreachable: `./scripts/maintenance/fix-npmplus-services-via-proxmox-ssh.sh`. Runbook: [502_DEEP_DIVE_ROOT_CAUSES_AND_FIXES.md](../00-meta/502_DEEP_DIVE_ROOT_CAUSES_AND_FIXES.md). |
| **404 studio.sankofa.nexus** | Ensure backend (VMID 7805, 192.168.11.72:8000) is up and NPMplus proxy for `studio.sankofa.nexus` points to it. See [ALL_VMIDS_ENDPOINTS.md](ALL_VMIDS_ENDPOINTS.md), [SANKOFA_STUDIO_E2E_FLOW.md](../03-deployment/SANKOFA_STUDIO_E2E_FLOW.md), [SANKOFA_STUDIO_DEPLOYMENT.md](../03-deployment/SANKOFA_STUDIO_DEPLOYMENT.md). |
| **the-order 502** | Check **10210** HAProxy (`curl http://192.168.11.39:80/` with `Host: the-order.sankofa.nexus`) and portal **192.168.11.51:3000**. Re-provision: `bash scripts/deployment/provision-order-haproxy-10210.sh`. NPM refresh: `bash scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh`. Direct portal bypass: `THE_ORDER_UPSTREAM_IP=192.168.11.51 THE_ORDER_UPSTREAM_PORT=3000` for that run. |

View File

@@ -135,7 +135,7 @@ See [DBIS_CORE_API_REFERENCE.md](../11-references/DBIS_CORE_API_REFERENCE.md).
### Sankofa Services (sankofa.nexus)
**Config TBD:** When The Order portal is deployed or Sankofa cutover is completed, update this table and [SANKOFA_CUTOVER_PLAN.md](SANKOFA_CUTOVER_PLAN.md) with actual IP:port and NPMplus proxy backends.
**NPMplus backends:** See [ALL_VMIDS_ENDPOINTS.md](ALL_VMIDS_ENDPOINTS.md). The Order uses **10210** (HAProxy) in front of the portal.
| Domain | Protocol | Target VMID | Target IP | Target Port | WebSocket | Notes |
|--------|----------|-------------|-----------|-------------|-----------|-------|
@@ -143,7 +143,8 @@ See [DBIS_CORE_API_REFERENCE.md](../11-references/DBIS_CORE_API_REFERENCE.md).
| `www.sankofa.nexus` | Redirect | - | - | - | ❌ No | Redirects to sankofa.nexus |
| `phoenix.sankofa.nexus` | HTTP | 7800 | 192.168.11.50 | 4000 | ❌ No | Phoenix API |
| `www.phoenix.sankofa.nexus` | Redirect | - | - | - | ❌ No | Redirects to phoenix.sankofa.nexus |
| `the-order.sankofa.nexus` | HTTP | TBD | TBD | TBD | ❌ No | ⚠️ Placeholder — not yet configured; add when The Order portal is deployed |
| `the-order.sankofa.nexus` | HTTP | 10210 | 192.168.11.39 | 80 | ❌ No | HAProxy → portal 7801 (192.168.11.51:3000); provision: `scripts/deployment/provision-order-haproxy-10210.sh` |
| `www.the-order.sankofa.nexus` | Redirect | - | - | - | ❌ No | 301 → `https://the-order.sankofa.nexus` (NPM advanced_config) |
---
@@ -183,7 +184,8 @@ secure.mim4u.org → http://192.168.11.37:80
training.mim4u.org → http://192.168.11.37:80
sankofa.nexus → http://192.168.11.51:3000
phoenix.sankofa.nexus → http://192.168.11.50:4000
the-order.sankofa.nexus → (TBD — add when The Order portal is deployed)
the-order.sankofa.nexus → http://192.168.11.39:80 (10210 HAProxy → 192.168.11.51:3000)
www.the-order.sankofa.nexus → 301 apex (NPM)
```
### Redirect Hosts
@@ -192,6 +194,7 @@ the-order.sankofa.nexus → (TBD — add when The Order portal is deployed)
www.mim4u.org → mim4u.org
www.sankofa.nexus → sankofa.nexus
www.phoenix.sankofa.nexus → phoenix.sankofa.nexus
www.the-order.sankofa.nexus → the-order.sankofa.nexus
```
---

View File

@@ -1,8 +1,10 @@
# Sankofa Cutover Plan
**Last Updated:** 2026-01-31
**Document Version:** 1.0
**Status:** Active Documentation
**Last Updated:** 2026-03-27
**Document Version:** 1.1
**Status:** Active Documentation (historical procedure + live targets)
**Live NPM routing (2026-03-27):** Sankofa / Phoenix / The Order / Studio are on production backends. Canonical: [ALL_VMIDS_ENDPOINTS.md](ALL_VMIDS_ENDPOINTS.md), [RPC_ENDPOINTS_MASTER.md](RPC_ENDPOINTS_MASTER.md). **The Order:** NPM → **192.168.11.39:80** (VMID **10210** HAProxy) → **192.168.11.51:3000** (portal 7801). Fleet updater: `scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh`. NPM proxy host numeric IDs below may differ from your DB—verify in NPM UI.
---
@@ -12,23 +14,22 @@
---
## Current State
## Current state (post-cutover)
### Sankofa Domains (5 Total)
### Sankofa zone domains (authoritative backends)
| Domain | SSL Cert ID | NPMplus Proxy Host ID | Current Backend | Status |
|--------|-------------|----------------------|-----------------|--------|
| `sankofa.nexus` | 57 | 21 | 192.168.11.140:80 (Blockscout) | ⚠️ Temporary |
| `www.sankofa.nexus` | 64 | 22 | 192.168.11.140:80 (Blockscout) | ⚠️ Temporary |
| `phoenix.sankofa.nexus` | 51 | 23 | 192.168.11.140:80 (Blockscout) | ⚠️ Temporary |
| `www.phoenix.sankofa.nexus` | 63 | 24 | 192.168.11.140:80 (Blockscout) | ⚠️ Temporary |
| `the-order.sankofa.nexus` | 60 | 25 | 192.168.11.140:80 (Blockscout) | ⚠️ Temporary |
| Domain | NPMplus forwards to (HTTP) | Origin stack | Notes |
|--------|----------------------------|--------------|--------|
| `sankofa.nexus`, `www.sankofa.nexus` | `192.168.11.51:3000` | VMID 7801 portal | `www` → 301 apex in NPM |
| `phoenix.sankofa.nexus`, `www.phoenix.sankofa.nexus` | `192.168.11.50:4000` | VMID 7800 API | `www` → 301 apex |
| `the-order.sankofa.nexus`, `www.the-order.sankofa.nexus` | `192.168.11.39:80` | VMID 10210 → `.51:3000` | `www` → 301 apex; HAProxy: `provision-order-haproxy-10210.sh` |
| `studio.sankofa.nexus` | `192.168.11.72:8000` | VMID 7805 | — |
**Current Issue**: All 5 Sankofa domains route to Blockscout (VMID 5000) but Sankofa services are NOT deployed.
**SSL:** Terminated at NPMplus (Lets Encrypt). **Do not** point these hostnames at Blockscout (`192.168.11.140`) except for explorer domains.
**SSL Certificates**: All certificates exist and are valid until 2026-04-16.
### Historical note (pre-2026 cutover)
**NPMplus Proxy Hosts**: All proxy hosts exist and are configured, but point to wrong backend.
Previously these hostnames temporarily targeted Blockscout. The step-by-step below documents that migration; IDs (SSL cert / proxy host #) were examples—confirm in your NPMplus instance.
---
@@ -67,9 +68,9 @@ done
| `www.sankofa.nexus` | 7801 | 192.168.11.51 | 3000 | Portal | Sankofa Portal (Microsoft Website) |
| `phoenix.sankofa.nexus` | 7800 | 192.168.11.50 | 4000 | API | Phoenix API (Azure-like Portal) |
| `www.phoenix.sankofa.nexus` | 7800 | 192.168.11.50 | 4000 | API | Phoenix API (Azure-like Portal) |
| `the-order.sankofa.nexus` | ⚠️ TBD | ⚠️ TBD | ⚠️ TBD | ⚠️ TBD | To be determined |
| `the-order.sankofa.nexus` | 10210 | 192.168.11.39 | 80 | HAProxy edge | Proxies to portal 7801 `:3000`; app **the_order** |
**Note**: Replace ⚠️ TBD with actual values once Sankofa services are deployed.
**Note:** `www.the-order.sankofa.nexus` uses the same NPM upstream as apex; NPM `advanced_config` 301 → `https://the-order.sankofa.nexus`.
### 3. Health Endpoints Verified
@@ -143,10 +144,9 @@ curl -s -k -X GET "$NPM_URL/api/nginx/proxy-hosts" \
jq '.[] | select(.domain_names[] == "sankofa.nexus")'
```
3. **Document Current State**:
- All 5 Sankofa domains currently route to `192.168.11.140:80` (Blockscout)
- SSL certificates exist (IDs: 51, 57, 60, 63, 64)
- Proxy hosts exist (IDs: 21-25)
3. **Document state (historical pre-cutover)**:
- Before cutover, these domains pointed at `192.168.11.140:80` (Blockscout)
- SSL certificates existed (example IDs: 51, 57, 60, 63, 64); proxy hosts (example 2125)—**confirm in your NPM DB**
---
@@ -167,9 +167,7 @@ for vmid in <SANKOFA_VMIDS>; do
done
```
3. **Document Actual IPs/Ports**:
- Update the TBD table above with actual values
- Record VMIDs, IPs, ports, and service types
3. **Document actual IPs/ports** (✅ filled in **Current state** section and [ALL_VMIDS_ENDPOINTS.md](ALL_VMIDS_ENDPOINTS.md))
---
@@ -224,9 +222,9 @@ curl -s -k -X PUT "$NPM_URL/api/nginx/proxy-hosts/$HOST_ID" \
| `www.sankofa.nexus` | 22 | 192.168.11.140:80 | 192.168.11.51:3000 |
| `phoenix.sankofa.nexus` | 23 | 192.168.11.140:80 | 192.168.11.50:4000 |
| `www.phoenix.sankofa.nexus` | 24 | 192.168.11.140:80 | 192.168.11.50:4000 |
| `the-order.sankofa.nexus` | 25 | 192.168.11.140:80 | ⚠️ TBD (to be determined) |
| `the-order.sankofa.nexus` | 25 (example) | 192.168.11.140:80 (old) | `192.168.11.39:80` (10210 HAProxy) |
**Note**: `the-order.sankofa.nexus` target service needs to be determined.
**Note:** Use `update-npmplus-proxy-hosts-api.sh` for domain-based updates; proxy host IDs vary.
---
@@ -319,19 +317,9 @@ cat docs/04-configuration/INGRESS_SOURCE_OF_TRUTH.json | jq '.backend_vms[] | se
---
### Step 7: Update Baseline Documentation
### Step 7: Update baseline documentation
**Update reference docs with actual values**:
1. **Update Comprehensive Architecture Doc**:
- File: `docs/04-configuration/DNS_NPMPLUS_VM_COMPREHENSIVE_ARCHITECTURE.md`
- Replace TBD values with actual Sankofa VM details
- Update status from ⚠️ to ✅
2. **Update Streamlined Table Doc**:
- File: `docs/04-configuration/DNS_NPMPLUS_VM_STREAMLINED_TABLE.md`
- Replace TBD values with actual Sankofa VM details
- Update status from ⚠️ Not Deployed to ✅ Active
**Status 2026-03-27:** Comprehensive and streamlined DNS/NPM tables, RPC_ENDPOINTS_MASTER, and ALL_VMIDS_ENDPOINTS list live backends (including The Order via 10210). Re-open this step only if VMIDs or IPs change.
---

View File

@@ -1,3 +1,23 @@
# Sankofa and The Order deployment checklist
# Sankofa and The Order — routing checklist
Replace TBDs with real IPs and ports when deployed. Update ALL_VMIDS_ENDPOINTS, RPC_ENDPOINTS_MASTER. Add NPMplus proxy for the-order.sankofa.nexus when The Order is live. When done update PLACEHOLDERS_AND_TBD and REMAINING_COMPONENTS_TASKS_AND_RECOMMENDATIONS. See NOT_IMPLEMENTED_FULL_SCOPE in docs/00-meta.
**Canonical:** [ALL_VMIDS_ENDPOINTS.md](ALL_VMIDS_ENDPOINTS.md) (NPM targets), [RPC_ENDPOINTS_MASTER.md](RPC_ENDPOINTS_MASTER.md) (Sankofa table).
## Done (production)
- [x] NPMplus **the-order.sankofa.nexus** / **www.the-order.sankofa.nexus****192.168.11.39:80** (VMID **10210** order-haproxy), HAProxy → **192.168.11.51:3000** (portal 7801).
- [x] **www.the-order****301** `https://the-order.sankofa.nexus` (NPM `advanced_config`).
- [x] HAProxy on 10210: `config/haproxy/order-haproxy-10210.cfg.template`, deploy `scripts/deployment/provision-order-haproxy-10210.sh`.
## If 10210 is down (bypass)
```bash
THE_ORDER_UPSTREAM_IP=192.168.11.51 THE_ORDER_UPSTREAM_PORT=3000 \
bash scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh
```
## Ongoing
- [ ] Keep **the_order** app and portal 7801 healthy (HAProxy only forwards).
- [ ] Re-run E2E: `scripts/verify/verify-end-to-end-routing.sh --profile=public`.
Related: [SANKOFA_CUTOVER_PLAN.md](SANKOFA_CUTOVER_PLAN.md) (history + same targets).

View File

@@ -0,0 +1,928 @@
[
{
"domain": "dbis-admin.d-bis.org",
"domain_type": "web",
"timestamp": "2026-03-27T13:40:32-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "dbis-admin.d-bis.org",
"issuer": "E7",
"expires": "Jun 15 06:47:43 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 200,
"response_time_seconds": 0.048185,
"has_hsts": true,
"has_csp": true,
"has_xfo": true
}
}
},
{
"domain": "rpc-alltra-3.d-bis.org",
"domain_type": "rpc-http",
"timestamp": "2026-03-27T13:40:33-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "172.67.220.49",
"expected_ip": "any"
},
"ssl": {
"status": "pass",
"cn": "d-bis.org",
"issuer": "WE1",
"expires": "May 27 07:40:56 2026 GMT"
},
"rpc_http": {
"status": "pass",
"chain_id": "0x8a"
}
}
},
{
"domain": "mifos.d-bis.org",
"domain_type": "web",
"timestamp": "2026-03-27T13:40:33-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "172.67.220.49",
"expected_ip": "any"
},
"ssl": {
"status": "pass",
"cn": "d-bis.org",
"issuer": "WE1",
"expires": "May 27 07:40:56 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 200,
"response_time_seconds": 0.129259,
"has_hsts": true,
"has_csp": false,
"has_xfo": true
}
}
},
{
"domain": "rpc-hybx-2.d-bis.org",
"domain_type": "rpc-http",
"timestamp": "2026-03-27T13:40:34-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "104.21.86.131",
"expected_ip": "any"
},
"ssl": {
"status": "pass",
"cn": "d-bis.org",
"issuer": "WE1",
"expires": "May 27 07:40:56 2026 GMT"
},
"rpc_http": {
"status": "pass",
"chain_id": "0x8a"
}
}
},
{
"domain": "cacti-hybx.d-bis.org",
"domain_type": "web",
"timestamp": "2026-03-27T13:40:34-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "104.21.86.131",
"expected_ip": "any"
},
"ssl": {
"status": "pass",
"cn": "d-bis.org",
"issuer": "WE1",
"expires": "May 27 07:40:56 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 200,
"response_time_seconds": 0.122747,
"has_hsts": true,
"has_csp": false,
"has_xfo": true
}
}
},
{
"domain": "sankofa.nexus",
"domain_type": "web",
"timestamp": "2026-03-27T13:40:35-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "sankofa.nexus",
"issuer": "E8",
"expires": "Jun 16 06:48:37 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 200,
"response_time_seconds": 0.088318,
"has_hsts": true,
"has_csp": true,
"has_xfo": true
}
}
},
{
"domain": "rpc-alltra.d-bis.org",
"domain_type": "rpc-http",
"timestamp": "2026-03-27T13:40:35-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "172.67.220.49",
"expected_ip": "any"
},
"ssl": {
"status": "pass",
"cn": "d-bis.org",
"issuer": "WE1",
"expires": "May 27 07:40:56 2026 GMT"
},
"rpc_http": {
"status": "pass",
"chain_id": "0x8a"
}
}
},
{
"domain": "rpc-http-pub.d-bis.org",
"domain_type": "rpc-http",
"timestamp": "2026-03-27T13:40:36-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "rpc-http-pub.d-bis.org",
"issuer": "E8",
"expires": "Jun 16 06:48:10 2026 GMT"
},
"rpc_http": {
"status": "pass",
"chain_id": "0x8a"
}
}
},
{
"domain": "rpc.public-0138.defi-oracle.io",
"domain_type": "rpc-http",
"timestamp": "2026-03-27T13:40:36-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "rpc.public-0138.defi-oracle.io",
"issuer": "E8",
"expires": "Apr 16 20:58:05 2026 GMT"
},
"rpc_http": {
"status": "pass",
"chain_id": "0x8a"
}
}
},
{
"domain": "studio.sankofa.nexus",
"domain_type": "web",
"timestamp": "2026-03-27T13:40:36-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "172.67.141.209",
"expected_ip": "any"
},
"ssl": {
"status": "pass",
"cn": "sankofa.nexus",
"issuer": "WE1",
"expires": "May 6 03:30:54 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 200,
"response_time_seconds": 0.158212,
"has_hsts": false,
"has_csp": false,
"has_xfo": false
}
}
},
{
"domain": "dbis-api.d-bis.org",
"domain_type": "api",
"timestamp": "2026-03-27T13:40:37-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "dbis-api.d-bis.org",
"issuer": "E7",
"expires": "Jun 16 06:47:45 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 200,
"response_time_seconds": 0.052015,
"has_hsts": true,
"has_csp": true,
"has_xfo": true
}
}
},
{
"domain": "rpc-hybx-3.d-bis.org",
"domain_type": "rpc-http",
"timestamp": "2026-03-27T13:40:37-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "172.67.220.49",
"expected_ip": "any"
},
"ssl": {
"status": "pass",
"cn": "d-bis.org",
"issuer": "WE1",
"expires": "May 27 07:40:56 2026 GMT"
},
"rpc_http": {
"status": "pass",
"chain_id": "0x8a"
}
}
},
{
"domain": "rpc.d-bis.org",
"domain_type": "rpc-http",
"timestamp": "2026-03-27T13:40:38-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "rpc.d-bis.org",
"issuer": "E7",
"expires": "Apr 30 13:35:45 2026 GMT"
},
"rpc_http": {
"status": "pass",
"chain_id": "0x8a"
}
}
},
{
"domain": "dapp.d-bis.org",
"domain_type": "web",
"timestamp": "2026-03-27T13:40:38-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "172.67.220.49",
"expected_ip": "any"
},
"ssl": {
"status": "pass",
"cn": "d-bis.org",
"issuer": "WE1",
"expires": "May 27 07:40:56 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 301,
"response_time_seconds": 0.134693,
"has_hsts": true,
"has_csp": false,
"has_xfo": false
}
}
},
{
"domain": "www.sankofa.nexus",
"domain_type": "web",
"timestamp": "2026-03-27T13:40:39-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "www.sankofa.nexus",
"issuer": "E7",
"expires": "Apr 16 20:59:41 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 301,
"response_time_seconds": 0.047036,
"canonical_redirect": true,
"location_header": "location: https://sankofa.nexus/"
}
}
},
{
"domain": "www.the-order.sankofa.nexus",
"domain_type": "web",
"timestamp": "2026-03-27T13:40:39-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "www.the-order.sankofa.nexus",
"issuer": "E8",
"expires": "Jun 25 04:52:05 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 301,
"response_time_seconds": 0.043245,
"canonical_redirect": true,
"location_header": "location: https://the-order.sankofa.nexus/"
}
}
},
{
"domain": "mim4u.org",
"domain_type": "web",
"timestamp": "2026-03-27T13:40:39-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "mim4u.org",
"issuer": "E8",
"expires": "Jun 16 06:47:53 2026 GMT"
},
"https": {
"status": "warn",
"http_code": 502,
"response_time_seconds": 0.089702
}
}
},
{
"domain": "ws.rpc.d-bis.org",
"domain_type": "rpc-ws",
"timestamp": "2026-03-27T13:40:40-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "ws.rpc.d-bis.org",
"issuer": "E8",
"expires": "Apr 30 03:43:05 2026 GMT"
},
"websocket": {
"status": "pass",
"http_code": "400",
"full_test": true,
"full_test_output": "result"
}
}
},
{
"domain": "phoenix.sankofa.nexus",
"domain_type": "web",
"timestamp": "2026-03-27T13:40:46-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "phoenix.sankofa.nexus",
"issuer": "E7",
"expires": "Jun 16 06:47:58 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 200,
"response_time_seconds": 0.047239,
"has_hsts": true,
"has_csp": true,
"has_xfo": true
}
}
},
{
"domain": "www.mim4u.org",
"domain_type": "web",
"timestamp": "2026-03-27T13:40:46-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "www.mim4u.org",
"issuer": "E8",
"expires": "Jun 15 06:47:54 2026 GMT"
},
"https": {
"status": "warn",
"http_code": 502,
"response_time_seconds": 0.055618
}
}
},
{
"domain": "wss.defi-oracle.io",
"domain_type": "rpc-ws",
"timestamp": "2026-03-27T13:40:46-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "wss.defi-oracle.io",
"issuer": "E8",
"expires": "Apr 30 03:44:57 2026 GMT"
},
"websocket": {
"status": "pass",
"http_code": "400",
"full_test": true,
"full_test_output": "result"
}
}
},
{
"domain": "the-order.sankofa.nexus",
"domain_type": "web",
"timestamp": "2026-03-27T13:40:52-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "the-order.sankofa.nexus",
"issuer": "E8",
"expires": "Jun 16 06:48:53 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 200,
"response_time_seconds": 0.065987,
"has_hsts": true,
"has_csp": true,
"has_xfo": true
}
}
},
{
"domain": "rpc2.d-bis.org",
"domain_type": "rpc-http",
"timestamp": "2026-03-27T13:40:52-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "rpc2.d-bis.org",
"issuer": "E8",
"expires": "Apr 30 03:40:50 2026 GMT"
},
"rpc_http": {
"status": "pass",
"chain_id": "0x8a"
}
}
},
{
"domain": "rpc-ws-pub.d-bis.org",
"domain_type": "rpc-ws",
"timestamp": "2026-03-27T13:40:53-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "rpc-ws-pub.d-bis.org",
"issuer": "E7",
"expires": "Jun 16 06:48:27 2026 GMT"
},
"websocket": {
"status": "pass",
"http_code": "400",
"full_test": true,
"full_test_output": "result"
}
}
},
{
"domain": "dev.d-bis.org",
"domain_type": "web",
"timestamp": "2026-03-27T13:40:58-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "104.21.86.131",
"expected_ip": "any"
},
"ssl": {
"status": "pass",
"cn": "d-bis.org",
"issuer": "WE1",
"expires": "May 27 07:40:56 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 200,
"response_time_seconds": 0.137467,
"has_hsts": true,
"has_csp": false,
"has_xfo": true
}
}
},
{
"domain": "rpc-alltra-2.d-bis.org",
"domain_type": "rpc-http",
"timestamp": "2026-03-27T13:40:59-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "172.67.220.49",
"expected_ip": "any"
},
"ssl": {
"status": "pass",
"cn": "d-bis.org",
"issuer": "WE1",
"expires": "May 27 07:40:56 2026 GMT"
},
"rpc_http": {
"status": "pass",
"chain_id": "0x8a"
}
}
},
{
"domain": "www.phoenix.sankofa.nexus",
"domain_type": "web",
"timestamp": "2026-03-27T13:40:59-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "www.phoenix.sankofa.nexus",
"issuer": "E8",
"expires": "Jun 15 06:48:02 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 301,
"response_time_seconds": 0.071859,
"canonical_redirect": true,
"location_header": "location: https://phoenix.sankofa.nexus/health"
}
}
},
{
"domain": "gitea.d-bis.org",
"domain_type": "web",
"timestamp": "2026-03-27T13:40:59-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "104.21.86.131",
"expected_ip": "any"
},
"ssl": {
"status": "pass",
"cn": "d-bis.org",
"issuer": "WE1",
"expires": "May 27 07:40:56 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 200,
"response_time_seconds": 0.113480,
"has_hsts": true,
"has_csp": false,
"has_xfo": true
}
}
},
{
"domain": "secure.mim4u.org",
"domain_type": "web",
"timestamp": "2026-03-27T13:41:00-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "secure.mim4u.org",
"issuer": "E8",
"expires": "Jun 16 06:48:46 2026 GMT"
},
"https": {
"status": "warn",
"http_code": 502,
"response_time_seconds": 0.039578
}
}
},
{
"domain": "explorer.d-bis.org",
"domain_type": "web",
"timestamp": "2026-03-27T13:41:00-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "explorer.d-bis.org",
"issuer": "E8",
"expires": "May 7 23:15:36 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 200,
"response_time_seconds": 0.039903,
"has_hsts": true,
"has_csp": true,
"has_xfo": true
},
"blockscout_api": {
"status": "pass",
"http_code": 200
}
}
},
{
"domain": "training.mim4u.org",
"domain_type": "web",
"timestamp": "2026-03-27T13:41:01-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "training.mim4u.org",
"issuer": "E7",
"expires": "Jun 16 06:49:02 2026 GMT"
},
"https": {
"status": "warn",
"http_code": 502,
"response_time_seconds": 0.037443
}
}
},
{
"domain": "dbis-api-2.d-bis.org",
"domain_type": "api",
"timestamp": "2026-03-27T13:41:01-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "dbis-api-2.d-bis.org",
"issuer": "E8",
"expires": "Apr 16 20:56:22 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 200,
"response_time_seconds": 0.036568,
"has_hsts": true,
"has_csp": true,
"has_xfo": true
}
}
},
{
"domain": "secure.d-bis.org",
"domain_type": "web",
"timestamp": "2026-03-27T13:41:01-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "secure.d-bis.org",
"issuer": "E7",
"expires": "Apr 16 20:58:28 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 200,
"response_time_seconds": 0.044836,
"has_hsts": true,
"has_csp": true,
"has_xfo": true
}
}
},
{
"domain": "rpc-hybx.d-bis.org",
"domain_type": "rpc-http",
"timestamp": "2026-03-27T13:41:01-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "104.21.86.131",
"expected_ip": "any"
},
"ssl": {
"status": "pass",
"cn": "d-bis.org",
"issuer": "WE1",
"expires": "May 27 07:40:56 2026 GMT"
},
"rpc_http": {
"status": "pass",
"chain_id": "0x8a"
}
}
},
{
"domain": "codespaces.d-bis.org",
"domain_type": "web",
"timestamp": "2026-03-27T13:41:02-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "172.67.220.49",
"expected_ip": "any"
},
"ssl": {
"status": "pass",
"cn": "d-bis.org",
"issuer": "WE1",
"expires": "May 27 07:40:56 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 200,
"response_time_seconds": 0.102393,
"has_hsts": true,
"has_csp": false,
"has_xfo": true
}
}
},
{
"domain": "rpc.defi-oracle.io",
"domain_type": "rpc-http",
"timestamp": "2026-03-27T13:41:02-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "*",
"issuer": "*",
"expires": "May 19 19:15:03 3025 GMT"
},
"rpc_http": {
"status": "skip",
"http_code": "405",
"error": "<html>\r\n<head><title>405 Not Allowed</title></head>\r\n<body>\r\n<center><h1>405 Not Allowed</h1></center>\r\n</body>\r\n</html>"
}
}
},
{
"domain": "ws.rpc2.d-bis.org",
"domain_type": "rpc-ws",
"timestamp": "2026-03-27T13:41:03-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "ws.rpc2.d-bis.org",
"issuer": "E7",
"expires": "Apr 30 03:43:58 2026 GMT"
},
"websocket": {
"status": "pass",
"http_code": "400",
"full_test": true,
"full_test_output": "result"
}
}
},
{
"domain": "cacti-alltra.d-bis.org",
"domain_type": "web",
"timestamp": "2026-03-27T13:41:08-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "104.21.86.131",
"expected_ip": "any"
},
"ssl": {
"status": "pass",
"cn": "d-bis.org",
"issuer": "WE1",
"expires": "May 27 07:40:56 2026 GMT"
},
"https": {
"status": "pass",
"http_code": 200,
"response_time_seconds": 0.133026,
"has_hsts": true,
"has_csp": false,
"has_xfo": true
}
}
}
]

View File

@@ -0,0 +1,20 @@
HTTP/2 200
date: Fri, 27 Mar 2026 20:41:09 GMT
content-type: text/html
alt-svc: h3=":443"; ma=86400
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
last-modified: Tue, 10 Mar 2026 14:38:11 GMT
referrer-policy: strict-origin-when-cross-origin
vary: Accept-Encoding
x-content-type-options: nosniff
x-dns-prefetch-control: off
x-frame-options: SAMEORIGIN
x-permitted-cross-domain-policies: none
cf-cache-status: DYNAMIC
strict-transport-security: max-age=31536000; includeSubDomains
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=f8NeZozda4HsovLIQL01oQj63nadMyYeqRDkiXAHVVtis4Io4fq6f5ClcyYkmhpL9CV%2FAUzvrqi5E6Rql%2Ft3Qa4YcM4WUjQP2gcVRnoTkTeJ2l5pQahvcWI5x5NtC1KocjV3p5BKlhQq"}]}
server: cloudflare
cf-ray: 9e3136d70f1727ec-LAX
0.133026

View File

@@ -0,0 +1,20 @@
HTTP/2 200
date: Fri, 27 Mar 2026 20:40:35 GMT
content-type: text/html
alt-svc: h3=":443"; ma=86400
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
last-modified: Tue, 10 Mar 2026 14:38:22 GMT
referrer-policy: strict-origin-when-cross-origin
vary: Accept-Encoding
x-content-type-options: nosniff
x-dns-prefetch-control: off
x-frame-options: SAMEORIGIN
x-permitted-cross-domain-policies: none
cf-cache-status: DYNAMIC
strict-transport-security: max-age=31536000; includeSubDomains
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=dWhmwhiBuOkBb4Zhh8n9L6nFgmZe3f8ajvfCrunlO1KNEanDxYaeT6e8c0Emd3%2FHzmdtEntKPMvGGzw3diaNrOWeNU3xchSFv5qBWDJ3fqZPTlYo0B872OcuyY9qXQNZ6cpk6dTxAA%3D%3D"}]}
server: cloudflare
cf-ray: 9e313602cda4c961-LAX
0.122747

View File

@@ -0,0 +1,17 @@
HTTP/2 200
date: Fri, 27 Mar 2026 20:41:02 GMT
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
x-dns-prefetch-control: off
x-frame-options: SAMEORIGIN
x-permitted-cross-domain-policies: none
cf-cache-status: DYNAMIC
strict-transport-security: max-age=31536000; includeSubDomains
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=cmll2l6EthHdX14gJDNzEheLY%2FY3pxyXR1y4YXOJJBh5n%2FoCd2eTf%2F7bCVykHvaIeVNv2Qy5spUQWO1tFMr2VjTHrzD6X0Rioskcb%2F9GQM%2Bg0KXsCqvHrVo7dTBB%2BSrxNK3nrJM%2FKg%3D%3D"}]}
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
server: cloudflare
cf-ray: 9e3136b01b1b2b77-LAX
alt-svc: h3=":443"; ma=86400
0.102393

View File

@@ -0,0 +1,15 @@
HTTP/2 301
date: Fri, 27 Mar 2026 20:40:38 GMT
content-type: text/html
location: https://dapp.d-bis.org/
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
cf-cache-status: DYNAMIC
strict-transport-security: max-age=31536000; includeSubDomains
x-content-type-options: nosniff
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=cCinyCyPjx0pMhMVnxKaVzYP9WOUQH%2FmCcWha0MGYJfl6PQTI9l3Qq3cDXhErs9AgF0SzNdi2MvYScUg0JI6auoO5yteaMvEtrYnWpf0lF7rCDjI27y3tmCwfaNdXHNNdw%3D%3D"}]}
server: cloudflare
cf-ray: 9e31361adf372efc-LAX
alt-svc: h3=":443"; ma=86400
0.134693

View File

@@ -0,0 +1,20 @@
HTTP/2 200
date: Fri, 27 Mar 2026 20:40:33 GMT
content-type: text/html
content-length: 31
vary: Accept-Encoding
last-modified: Tue, 10 Mar 2026 14:34:29 GMT
alt-svc: h3=":443"; ma=86400
x-xss-protection: 0
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
content-security-policy: upgrade-insecure-requests
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
referrer-policy: strict-origin-when-cross-origin
content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https: data:; style-src 'self' 'unsafe-inline' https: data:; font-src 'self' https: data:; img-src 'self' data: https: blob:; connect-src 'self' https: wss: ws:; media-src 'self' https: data:; object-src 'none'; base-uri 'self'; form-action 'self' https:; frame-ancestors 'none'; upgrade-insecure-requests
0.048185

View File

@@ -0,0 +1,19 @@
HTTP/2 200
date: Fri, 27 Mar 2026 20:41:01 GMT
content-type: text/html; charset=utf-8
content-length: 344
vary: Accept-Encoding
alt-svc: h3=":443"; ma=86400
x-xss-protection: 0
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
content-security-policy: upgrade-insecure-requests
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
referrer-policy: strict-origin-when-cross-origin
content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https: data:; style-src 'self' 'unsafe-inline' https: data:; font-src 'self' https: data:; img-src 'self' data: https: blob:; connect-src 'self' https: wss: ws:; media-src 'self' https: data:; object-src 'none'; base-uri 'self'; form-action 'self' https:; frame-ancestors 'none'; upgrade-insecure-requests
0.036568

View File

@@ -0,0 +1,19 @@
HTTP/2 200
date: Fri, 27 Mar 2026 20:40:37 GMT
content-type: text/html; charset=utf-8
content-length: 344
vary: Accept-Encoding
alt-svc: h3=":443"; ma=86400
x-xss-protection: 0
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
content-security-policy: upgrade-insecure-requests
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
referrer-policy: strict-origin-when-cross-origin
content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https: data:; style-src 'self' 'unsafe-inline' https: data:; font-src 'self' https: data:; img-src 'self' data: https: blob:; connect-src 'self' https: wss: ws:; media-src 'self' https: data:; object-src 'none'; base-uri 'self'; form-action 'self' https:; frame-ancestors 'none'; upgrade-insecure-requests
0.052015

View File

@@ -0,0 +1,17 @@
HTTP/2 200
date: Fri, 27 Mar 2026 20:40:59 GMT
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
x-dns-prefetch-control: off
x-frame-options: SAMEORIGIN
x-permitted-cross-domain-policies: none
cf-cache-status: DYNAMIC
strict-transport-security: max-age=31536000; includeSubDomains
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=qmt%2BbVFJ2EwVGI0OLmGJL8Lkx%2BERxAEqJsPQuMWo1d4t3AYUZrwU%2BdIR5cmwtOQAqOsAZN7wOelPdw4h%2FZVFHpW7oct8yg40Aze3%2BhVjifrgWiDtGRAU8Z%2FIQ1jV%2BaKM"}]}
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
server: cloudflare
cf-ray: 9e313698ab19490e-LAX
alt-svc: h3=":443"; ma=86400
0.137467

View File

@@ -0,0 +1 @@
{"average_block_time":2.0e3,"coin_image":"https://coin-images.coingecko.com/coins/images/39140/small/ETH.png?1720706783","coin_price":"1975.13","coin_price_change_percentage":-8.93,"gas_price_updated_at":"2026-03-27T20:40:55.112693Z","gas_prices":{"slow":2.0,"average":2.0,"fast":2.0},"gas_prices_update_in":25339,"gas_used_today":"421762900","market_cap":"0.000","network_utilization_percentage":0.0491656,"secondary_coin_image":null,"secondary_coin_price":null,"static_gas_price":null,"total_addresses":"441","total_blocks":"3352124","total_gas_used":"0","total_transactions":"28499","transactions_today":"6704","tvl":null}

View File

@@ -0,0 +1,20 @@
HTTP/2 200
date: Fri, 27 Mar 2026 20:41:00 GMT
content-type: text/html
content-length: 79248
vary: Accept-Encoding
last-modified: Fri, 27 Mar 2026 20:39:14 GMT
etag: "69c6eaf2-13590"
cache-control: no-store, no-cache, must-revalidate
content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net https://unpkg.com https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com; img-src 'self' data: https:; font-src 'self' https://cdnjs.cloudflare.com; connect-src 'self' https://explorer.d-bis.org wss://explorer.d-bis.org https://rpc-http-pub.d-bis.org wss://rpc-ws-pub.d-bis.org http://192.168.11.221:8545 ws://192.168.11.221:8546;
accept-ranges: bytes
alt-svc: h3=":443"; ma=86400
x-xss-protection: 0
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
referrer-policy: strict-origin-when-cross-origin
content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https: data:; style-src 'self' 'unsafe-inline' https: data:; font-src 'self' https: data:; img-src 'self' data: https: blob:; connect-src 'self' https: wss: ws:; media-src 'self' https: data:; object-src 'none'; base-uri 'self'; form-action 'self' https:; frame-ancestors 'none'; upgrade-insecure-requests

View File

@@ -0,0 +1,17 @@
HTTP/2 200
date: Fri, 27 Mar 2026 20:41:00 GMT
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
x-dns-prefetch-control: off
x-frame-options: SAMEORIGIN
x-permitted-cross-domain-policies: none
cf-cache-status: DYNAMIC
strict-transport-security: max-age=31536000; includeSubDomains
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=wY6qWCOjIlaaMg11zTMNBcKFuDsOIbZbbrXVu%2FRNkNMMsjETgQGbufbZo3Ow7YVZlAEYAt%2BFTRJ5mEeQgo8%2FQNy5JdOdzaP8VdFRy%2FfhnGk%2FzNAKZO8cjKCcfBu%2FQyHS0%2Bc%3D"}]}
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
server: cloudflare
cf-ray: 9e3136a0cd32d7ab-LAX
alt-svc: h3=":443"; ma=86400
0.113480

View File

@@ -0,0 +1,20 @@
HTTP/2 200
date: Fri, 27 Mar 2026 20:40:34 GMT
content-type: text/html
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=Lg4tY0tUDoH9QvsPHHjl61IXVrGNonfx5jn4IiNf4HGj4VBE8QTez4vHyWTk%2FGh3DZcwXRbHprUcCuwmkzVuT7iMlHfEhViCaRXP49i98n1vXfkgzP8bA4FDoDCLlUfpB68%3D"}]}
last-modified: Mon, 31 Mar 2025 07:37:06 GMT
referrer-policy: strict-origin-when-cross-origin
vary: Accept-Encoding
x-content-type-options: nosniff
x-dns-prefetch-control: off
x-frame-options: SAMEORIGIN
x-permitted-cross-domain-policies: none
cf-cache-status: DYNAMIC
strict-transport-security: max-age=31536000; includeSubDomains
server: cloudflare
cf-ray: 9e3135fd0c332b62-LAX
alt-svc: h3=":443"; ma=86400
0.129259

View File

@@ -0,0 +1,18 @@
HTTP/2 502
date: Fri, 27 Mar 2026 20:40:40 GMT
content-type: text/html
content-length: 122
alt-svc: h3=":443"; ma=86400
x-xss-protection: 0
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
content-security-policy: upgrade-insecure-requests
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
referrer-policy: strict-origin-when-cross-origin
content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https: data:; style-src 'self' 'unsafe-inline' https: data:; font-src 'self' https: data:; img-src 'self' data: https: blob:; connect-src 'self' https: wss: ws:; media-src 'self' https: data:; object-src 'none'; base-uri 'self'; form-action 'self' https:; frame-ancestors 'none'; upgrade-insecure-requests
0.089702

View File

@@ -0,0 +1,20 @@
HTTP/2 200
date: Fri, 27 Mar 2026 20:40:46 GMT
content-type: application/json; charset=utf-8
content-length: 54
vary: Accept-Encoding
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 0
strict-transport-security: max-age=63072000; includeSubDomains; preload
content-security-policy: default-src 'self'; script-src 'self' 'nonce-f7oZ79fkmHF5pFaZFuVUNw=='; style-src 'self' 'nonce-f7oZ79fkmHF5pFaZFuVUNw=='; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests
referrer-policy: strict-origin-when-cross-origin
permissions-policy: geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=()
x-permitted-cross-domain-policies: none
cross-origin-embedder-policy: require-corp
cross-origin-opener-policy: same-origin
cross-origin-resource-policy: same-origin
alt-svc: h3=":443"; ma=86400
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","id":1,"result":"0x8a"}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","id":1,"result":"0x8a"}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","id":1,"result":"0x8a"}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","id":1,"result":"0x8a"}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","id":1,"result":"0x8a"}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","id":1,"result":"0x8a"}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","id":1,"result":"0x8a"}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","id":1,"result":"0x8a"}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","id":1,"result":"0x8a"}

View File

@@ -0,0 +1,6 @@
<html>
<head><title>405 Not Allowed</title></head>
<body>
<center><h1>405 Not Allowed</h1></center>
</body>
</html>

View File

@@ -0,0 +1,19 @@
HTTP/2 200
date: Fri, 27 Mar 2026 20:40:35 GMT
content-type: text/html; charset=utf-8
content-length: 5165
vary: Accept-Encoding
x-dns-prefetch-control: on
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-frame-options: SAMEORIGIN
x-content-type-options: nosniff
x-xss-protection: 0
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
content-security-policy: default-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:
vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Accept-Encoding
cache-control: s-maxage=31536000, stale-while-revalidate
etag: "yc5tqwrxjc3zb"
alt-svc: h3=":443"; ma=86400
content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https: data:; style-src 'self' 'unsafe-inline' https: data:; font-src 'self' https: data:; img-src 'self' data: https: blob:; connect-src 'self' https: wss: ws:; media-src 'self' https: data:; object-src 'none'; base-uri 'self'; form-action 'self' https:; frame-ancestors 'none'; upgrade-insecure-requests

View File

@@ -0,0 +1,20 @@
HTTP/2 200
date: Fri, 27 Mar 2026 20:41:01 GMT
content-type: text/html
content-length: 31
vary: Accept-Encoding
last-modified: Tue, 10 Mar 2026 14:34:29 GMT
alt-svc: h3=":443"; ma=86400
x-xss-protection: 0
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
content-security-policy: upgrade-insecure-requests
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
referrer-policy: strict-origin-when-cross-origin
content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https: data:; style-src 'self' 'unsafe-inline' https: data:; font-src 'self' https: data:; img-src 'self' data: https: blob:; connect-src 'self' https: wss: ws:; media-src 'self' https: data:; object-src 'none'; base-uri 'self'; form-action 'self' https:; frame-ancestors 'none'; upgrade-insecure-requests
0.044836

View File

@@ -0,0 +1,18 @@
HTTP/2 502
date: Fri, 27 Mar 2026 20:41:00 GMT
content-type: text/html
content-length: 122
alt-svc: h3=":443"; ma=86400
x-xss-protection: 0
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
content-security-policy: upgrade-insecure-requests
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
referrer-policy: strict-origin-when-cross-origin
content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https: data:; style-src 'self' 'unsafe-inline' https: data:; font-src 'self' https: data:; img-src 'self' data: https: blob:; connect-src 'self' https: wss: ws:; media-src 'self' https: data:; object-src 'none'; base-uri 'self'; form-action 'self' https:; frame-ancestors 'none'; upgrade-insecure-requests
0.039578

View File

@@ -0,0 +1,14 @@
HTTP/2 200
date: Fri, 27 Mar 2026 20:40:37 GMT
content-type: text/html; charset=utf-8
vary: Accept-Encoding
last-modified: Sat, 28 Feb 2026 16:54:14 GMT
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=APaBHQl3T2EffLK36x8sJc%2BO%2B68g7N88s1dlgFoPrOE0gYbpvsYqQ9HpZDwxv2W6NjikzornPFlO4tUw1QXBFdwKyM8vQ4W%2BCqo%2BgKJE6Dvfy7ZPr%2BzmVSXfQsV03Lb%2BRXoSpJZbTA%3D%3D"}]}
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
cf-cache-status: DYNAMIC
server: cloudflare
cf-ray: 9e3136102ee1b860-LAX
alt-svc: h3=":443"; ma=86400
0.158212

View File

@@ -0,0 +1,20 @@
HTTP/2 200
date: Fri, 27 Mar 2026 20:40:52 GMT
content-type: text/html; charset=utf-8
content-length: 5165
vary: Accept-Encoding
x-dns-prefetch-control: on
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-frame-options: SAMEORIGIN
x-content-type-options: nosniff
x-xss-protection: 0
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), geolocation=()
content-security-policy: default-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:
vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Accept-Encoding
cache-control: s-maxage=31536000, stale-while-revalidate
etag: "yc5tqwrxjc3zb"
alt-svc: h3=":443"; ma=86400
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block

View File

@@ -0,0 +1,18 @@
HTTP/2 502
date: Fri, 27 Mar 2026 20:41:01 GMT
content-type: text/html
content-length: 122
alt-svc: h3=":443"; ma=86400
x-xss-protection: 0
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
content-security-policy: upgrade-insecure-requests
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
referrer-policy: strict-origin-when-cross-origin
content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https: data:; style-src 'self' 'unsafe-inline' https: data:; font-src 'self' https: data:; img-src 'self' data: https: blob:; connect-src 'self' https: wss: ws:; media-src 'self' https: data:; object-src 'none'; base-uri 'self'; form-action 'self' https:; frame-ancestors 'none'; upgrade-insecure-requests
0.037443

View File

@@ -0,0 +1,390 @@
# End-to-End Routing Verification Report
**Date**: 2026-03-27T13:41:09-07:00
**Public IP**: 76.53.10.36
**Profile**: public
**Verifier**: intlc
## All endpoints (38)
| Domain | Type | URL |
|--------|------|-----|
| cacti-alltra.d-bis.org | web | https://cacti-alltra.d-bis.org |
| cacti-hybx.d-bis.org | web | https://cacti-hybx.d-bis.org |
| codespaces.d-bis.org | web | https://codespaces.d-bis.org |
| dapp.d-bis.org | web | https://dapp.d-bis.org |
| dbis-admin.d-bis.org | web | https://dbis-admin.d-bis.org |
| dbis-api-2.d-bis.org | api | https://dbis-api-2.d-bis.org |
| dbis-api.d-bis.org | api | https://dbis-api.d-bis.org |
| dev.d-bis.org | web | https://dev.d-bis.org |
| explorer.d-bis.org | web | https://explorer.d-bis.org |
| gitea.d-bis.org | web | https://gitea.d-bis.org |
| mifos.d-bis.org | web | https://mifos.d-bis.org |
| mim4u.org | web | https://mim4u.org |
| phoenix.sankofa.nexus | web | https://phoenix.sankofa.nexus |
| rpc-alltra-2.d-bis.org | rpc-http | https://rpc-alltra-2.d-bis.org |
| rpc-alltra-3.d-bis.org | rpc-http | https://rpc-alltra-3.d-bis.org |
| rpc-alltra.d-bis.org | rpc-http | https://rpc-alltra.d-bis.org |
| rpc-http-pub.d-bis.org | rpc-http | https://rpc-http-pub.d-bis.org |
| rpc-hybx-2.d-bis.org | rpc-http | https://rpc-hybx-2.d-bis.org |
| rpc-hybx-3.d-bis.org | rpc-http | https://rpc-hybx-3.d-bis.org |
| rpc-hybx.d-bis.org | rpc-http | https://rpc-hybx.d-bis.org |
| rpc-ws-pub.d-bis.org | rpc-ws | https://rpc-ws-pub.d-bis.org |
| rpc.d-bis.org | rpc-http | https://rpc.d-bis.org |
| rpc.defi-oracle.io | rpc-http | https://rpc.defi-oracle.io |
| rpc.public-0138.defi-oracle.io | rpc-http | https://rpc.public-0138.defi-oracle.io |
| rpc2.d-bis.org | rpc-http | https://rpc2.d-bis.org |
| sankofa.nexus | web | https://sankofa.nexus |
| secure.d-bis.org | web | https://secure.d-bis.org |
| secure.mim4u.org | web | https://secure.mim4u.org |
| studio.sankofa.nexus | web | https://studio.sankofa.nexus |
| the-order.sankofa.nexus | web | https://the-order.sankofa.nexus |
| training.mim4u.org | web | https://training.mim4u.org |
| ws.rpc.d-bis.org | rpc-ws | https://ws.rpc.d-bis.org |
| ws.rpc2.d-bis.org | rpc-ws | https://ws.rpc2.d-bis.org |
| wss.defi-oracle.io | rpc-ws | https://wss.defi-oracle.io |
| www.mim4u.org | web | https://www.mim4u.org |
| www.phoenix.sankofa.nexus | web | https://www.phoenix.sankofa.nexus |
| www.sankofa.nexus | web | https://www.sankofa.nexus |
| www.the-order.sankofa.nexus | web | https://www.the-order.sankofa.nexus |
## Summary
- **Total domains tested**: 38
- **DNS tests passed**: 38
- **HTTPS tests passed**: 19
- **Failed tests**: 0
- **Skipped / optional (not configured or unreachable)**: 1
- **Average response time**: 0.07994821739130435s
## Results overview
| Domain | Type | DNS | SSL | HTTPS | RPC |
|--------|------|-----|-----|-------|-----|
| dbis-admin.d-bis.org | web | pass | pass | pass | - |
| rpc-alltra-3.d-bis.org | rpc-http | pass | pass | - | pass |
| mifos.d-bis.org | web | pass | pass | pass | - |
| rpc-hybx-2.d-bis.org | rpc-http | pass | pass | - | pass |
| cacti-hybx.d-bis.org | web | pass | pass | pass | - |
| sankofa.nexus | web | pass | pass | pass | - |
| rpc-alltra.d-bis.org | rpc-http | pass | pass | - | pass |
| rpc-http-pub.d-bis.org | rpc-http | pass | pass | - | pass |
| rpc.public-0138.defi-oracle.io | rpc-http | pass | pass | - | pass |
| studio.sankofa.nexus | web | pass | pass | pass | - |
| dbis-api.d-bis.org | api | pass | pass | pass | - |
| rpc-hybx-3.d-bis.org | rpc-http | pass | pass | - | pass |
| rpc.d-bis.org | rpc-http | pass | pass | - | pass |
| dapp.d-bis.org | web | pass | pass | pass | - |
| www.sankofa.nexus | web | pass | pass | pass | - |
| www.the-order.sankofa.nexus | web | pass | pass | pass | - |
| mim4u.org | web | pass | pass | warn | - |
| ws.rpc.d-bis.org | rpc-ws | pass | pass | - | - |
| phoenix.sankofa.nexus | web | pass | pass | pass | - |
| www.mim4u.org | web | pass | pass | warn | - |
| wss.defi-oracle.io | rpc-ws | pass | pass | - | - |
| the-order.sankofa.nexus | web | pass | pass | pass | - |
| rpc2.d-bis.org | rpc-http | pass | pass | - | pass |
| rpc-ws-pub.d-bis.org | rpc-ws | pass | pass | - | - |
| dev.d-bis.org | web | pass | pass | pass | - |
| rpc-alltra-2.d-bis.org | rpc-http | pass | pass | - | pass |
| www.phoenix.sankofa.nexus | web | pass | pass | pass | - |
| gitea.d-bis.org | web | pass | pass | pass | - |
| secure.mim4u.org | web | pass | pass | warn | - |
| explorer.d-bis.org | web | pass | pass | pass | - |
| training.mim4u.org | web | pass | pass | warn | - |
| dbis-api-2.d-bis.org | api | pass | pass | pass | - |
| secure.d-bis.org | web | pass | pass | pass | - |
| rpc-hybx.d-bis.org | rpc-http | pass | pass | - | pass |
| codespaces.d-bis.org | web | pass | pass | pass | - |
| rpc.defi-oracle.io | rpc-http | pass | pass | - | skip |
| ws.rpc2.d-bis.org | rpc-ws | pass | pass | - | - |
| cacti-alltra.d-bis.org | web | pass | pass | pass | - |
## Test Results by Domain (detail)
### dbis-admin.d-bis.org
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: pass
- Details: See `all_e2e_results.json`
### rpc-alltra-3.d-bis.org
- Type: rpc-http
- DNS: pass
- SSL: pass
- RPC: pass
- Details: See `all_e2e_results.json`
### mifos.d-bis.org
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: pass
- Details: See `all_e2e_results.json`
### rpc-hybx-2.d-bis.org
- Type: rpc-http
- DNS: pass
- SSL: pass
- RPC: pass
- Details: See `all_e2e_results.json`
### cacti-hybx.d-bis.org
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: pass
- Details: See `all_e2e_results.json`
### sankofa.nexus
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: pass
- Details: See `all_e2e_results.json`
### rpc-alltra.d-bis.org
- Type: rpc-http
- DNS: pass
- SSL: pass
- RPC: pass
- Details: See `all_e2e_results.json`
### rpc-http-pub.d-bis.org
- Type: rpc-http
- DNS: pass
- SSL: pass
- RPC: pass
- Details: See `all_e2e_results.json`
### rpc.public-0138.defi-oracle.io
- Type: rpc-http
- DNS: pass
- SSL: pass
- RPC: pass
- Details: See `all_e2e_results.json`
### studio.sankofa.nexus
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: pass
- Details: See `all_e2e_results.json`
### dbis-api.d-bis.org
- Type: api
- DNS: pass
- SSL: pass
- HTTPS: pass
- Details: See `all_e2e_results.json`
### rpc-hybx-3.d-bis.org
- Type: rpc-http
- DNS: pass
- SSL: pass
- RPC: pass
- Details: See `all_e2e_results.json`
### rpc.d-bis.org
- Type: rpc-http
- DNS: pass
- SSL: pass
- RPC: pass
- Details: See `all_e2e_results.json`
### dapp.d-bis.org
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: pass
- Details: See `all_e2e_results.json`
### www.sankofa.nexus
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: pass
- Details: See `all_e2e_results.json`
### www.the-order.sankofa.nexus
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: pass
- Details: See `all_e2e_results.json`
### mim4u.org
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: warn
- Details: See `all_e2e_results.json`
### ws.rpc.d-bis.org
- Type: rpc-ws
- DNS: pass
- SSL: pass
- Details: See `all_e2e_results.json`
### phoenix.sankofa.nexus
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: pass
- Details: See `all_e2e_results.json`
### www.mim4u.org
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: warn
- Details: See `all_e2e_results.json`
### wss.defi-oracle.io
- Type: rpc-ws
- DNS: pass
- SSL: pass
- Details: See `all_e2e_results.json`
### the-order.sankofa.nexus
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: pass
- Details: See `all_e2e_results.json`
### rpc2.d-bis.org
- Type: rpc-http
- DNS: pass
- SSL: pass
- RPC: pass
- Details: See `all_e2e_results.json`
### rpc-ws-pub.d-bis.org
- Type: rpc-ws
- DNS: pass
- SSL: pass
- Details: See `all_e2e_results.json`
### dev.d-bis.org
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: pass
- Details: See `all_e2e_results.json`
### rpc-alltra-2.d-bis.org
- Type: rpc-http
- DNS: pass
- SSL: pass
- RPC: pass
- Details: See `all_e2e_results.json`
### www.phoenix.sankofa.nexus
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: pass
- Details: See `all_e2e_results.json`
### gitea.d-bis.org
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: pass
- Details: See `all_e2e_results.json`
### secure.mim4u.org
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: warn
- Details: See `all_e2e_results.json`
### explorer.d-bis.org
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: pass
- Blockscout API: pass
- Details: See `all_e2e_results.json`
### training.mim4u.org
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: warn
- Details: See `all_e2e_results.json`
### dbis-api-2.d-bis.org
- Type: api
- DNS: pass
- SSL: pass
- HTTPS: pass
- Details: See `all_e2e_results.json`
### secure.d-bis.org
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: pass
- Details: See `all_e2e_results.json`
### rpc-hybx.d-bis.org
- Type: rpc-http
- DNS: pass
- SSL: pass
- RPC: pass
- Details: See `all_e2e_results.json`
### codespaces.d-bis.org
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: pass
- Details: See `all_e2e_results.json`
### rpc.defi-oracle.io
- Type: rpc-http
- DNS: pass
- SSL: pass
- RPC: skip
- Details: See `all_e2e_results.json`
### ws.rpc2.d-bis.org
- Type: rpc-ws
- DNS: pass
- SSL: pass
- Details: See `all_e2e_results.json`
### cacti-alltra.d-bis.org
- Type: web
- DNS: pass
- SSL: pass
- HTTPS: pass
- Details: See `all_e2e_results.json`
## Files Generated
- `all_e2e_results.json` - Complete E2E test results
- `*_https_headers.txt` - HTTP response headers per domain
- `*_rpc_response.txt` - RPC response per domain
- `verification_report.md` - This report
## Notes
- **Optional domains:** Domains in `E2E_OPTIONAL_WHEN_FAIL` (default: many d-bis.org/sankofa/mim4u/rpc) have any fail treated as skip so the run passes when off-LAN or services unreachable. Set `E2E_OPTIONAL_WHEN_FAIL=` (empty) for strict mode.
- WebSocket tests require `wscat` tool: `npm install -g wscat`
- OpenSSL fetch uses `timeout` (`E2E_OPENSSL_TIMEOUT` / `E2E_OPENSSL_X509_TIMEOUT`, defaults 15s / 5s) so `openssl s_client` cannot hang indefinitely
- Internal connectivity tests require access to NPMplus container
- Explorer (explorer.d-bis.org): optional Blockscout API check; use `SKIP_BLOCKSCOUT_API=1` to skip when backend is unreachable (e.g. off-LAN). Fix runbook: docs/03-deployment/BLOCKSCOUT_FIX_RUNBOOK.md
## Next Steps
1. Review test results for each domain
2. Investigate any failed tests
3. Test WebSocket connections for RPC WS domains (if wscat available)
4. Test internal connectivity from NPMplus container
5. Update source-of-truth JSON after verification

View File

@@ -0,0 +1,18 @@
HTTP/2 502
date: Fri, 27 Mar 2026 20:40:46 GMT
content-type: text/html
content-length: 122
alt-svc: h3=":443"; ma=86400
x-xss-protection: 0
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
content-security-policy: upgrade-insecure-requests
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
referrer-policy: strict-origin-when-cross-origin
content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https: data:; style-src 'self' 'unsafe-inline' https: data:; font-src 'self' https: data:; img-src 'self' data: https: blob:; connect-src 'self' https: wss: ws:; media-src 'self' https: data:; object-src 'none'; base-uri 'self'; form-action 'self' https:; frame-ancestors 'none'; upgrade-insecure-requests
0.055618

View File

@@ -0,0 +1,14 @@
HTTP/2 301
date: Fri, 27 Mar 2026 20:40:59 GMT
content-type: text/html
content-length: 134
location: https://phoenix.sankofa.nexus/health
alt-svc: h3=":443"; ma=86400
x-xss-protection: 0
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
content-security-policy: upgrade-insecure-requests
strict-transport-security: max-age=63072000; includeSubDomains; preload
0.071859

View File

@@ -0,0 +1,14 @@
HTTP/2 301
date: Fri, 27 Mar 2026 20:40:39 GMT
content-type: text/html
content-length: 134
location: https://sankofa.nexus/
alt-svc: h3=":443"; ma=86400
x-xss-protection: 0
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
content-security-policy: upgrade-insecure-requests
strict-transport-security: max-age=63072000; includeSubDomains; preload
0.047036

View File

@@ -0,0 +1,8 @@
HTTP/2 301
date: Fri, 27 Mar 2026 20:40:39 GMT
content-type: text/html
content-length: 134
location: https://the-order.sankofa.nexus/
0.043245

View File

@@ -0,0 +1,94 @@
[
{
"domain": "ws.rpc-fireblocks.d-bis.org",
"domain_type": "rpc-ws",
"timestamp": "2026-03-27T13:41:37-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "ws.rpc-fireblocks.d-bis.org",
"issuer": "E8",
"expires": "May 22 21:48:21 2026 GMT"
},
"websocket": {
"status": "pass",
"http_code": "400",
"full_test": true,
"full_test_output": "result"
}
}
},
{
"domain": "rpc-http-prv.d-bis.org",
"domain_type": "rpc-http",
"timestamp": "2026-03-27T13:41:43-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "rpc-http-prv.d-bis.org",
"issuer": "E7",
"expires": "Jun 25 16:00:12 2026 GMT"
},
"rpc_http": {
"status": "pass",
"chain_id": "0x8a"
}
}
},
{
"domain": "rpc-fireblocks.d-bis.org",
"domain_type": "rpc-http",
"timestamp": "2026-03-27T13:41:43-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "rpc-fireblocks.d-bis.org",
"issuer": "E8",
"expires": "May 22 21:47:15 2026 GMT"
},
"rpc_http": {
"status": "pass",
"chain_id": "0x8a"
}
}
},
{
"domain": "rpc-ws-prv.d-bis.org",
"domain_type": "rpc-ws",
"timestamp": "2026-03-27T13:41:44-07:00",
"tests": {
"dns": {
"status": "pass",
"resolved_ip": "76.53.10.36",
"expected_ip": "76.53.10.36"
},
"ssl": {
"status": "pass",
"cn": "rpc-ws-prv.d-bis.org",
"issuer": "E7",
"expires": "Jun 16 06:48:19 2026 GMT"
},
"websocket": {
"status": "pass",
"http_code": "400",
"full_test": true,
"full_test_output": "result"
}
}
}
]

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","id":1,"result":"0x8a"}

View File

@@ -0,0 +1 @@
{"jsonrpc":"2.0","id":1,"result":"0x8a"}

View File

@@ -0,0 +1,85 @@
# End-to-End Routing Verification Report
**Date**: 2026-03-27T13:41:49-07:00
**Public IP**: 76.53.10.36
**Profile**: private
**Verifier**: intlc
## All endpoints (4)
| Domain | Type | URL |
|--------|------|-----|
| rpc-fireblocks.d-bis.org | rpc-http | https://rpc-fireblocks.d-bis.org |
| rpc-http-prv.d-bis.org | rpc-http | https://rpc-http-prv.d-bis.org |
| rpc-ws-prv.d-bis.org | rpc-ws | https://rpc-ws-prv.d-bis.org |
| ws.rpc-fireblocks.d-bis.org | rpc-ws | https://ws.rpc-fireblocks.d-bis.org |
## Summary
- **Total domains tested**: 4
- **DNS tests passed**: 4
- **HTTPS tests passed**: 0
- **Failed tests**: 0
- **Skipped / optional (not configured or unreachable)**: 0
- **Average response time**: 0s
## Results overview
| Domain | Type | DNS | SSL | HTTPS | RPC |
|--------|------|-----|-----|-------|-----|
| ws.rpc-fireblocks.d-bis.org | rpc-ws | pass | pass | - | - |
| rpc-http-prv.d-bis.org | rpc-http | pass | pass | - | pass |
| rpc-fireblocks.d-bis.org | rpc-http | pass | pass | - | pass |
| rpc-ws-prv.d-bis.org | rpc-ws | pass | pass | - | - |
## Test Results by Domain (detail)
### ws.rpc-fireblocks.d-bis.org
- Type: rpc-ws
- DNS: pass
- SSL: pass
- Details: See `all_e2e_results.json`
### rpc-http-prv.d-bis.org
- Type: rpc-http
- DNS: pass
- SSL: pass
- RPC: pass
- Details: See `all_e2e_results.json`
### rpc-fireblocks.d-bis.org
- Type: rpc-http
- DNS: pass
- SSL: pass
- RPC: pass
- Details: See `all_e2e_results.json`
### rpc-ws-prv.d-bis.org
- Type: rpc-ws
- DNS: pass
- SSL: pass
- Details: See `all_e2e_results.json`
## Files Generated
- `all_e2e_results.json` - Complete E2E test results
- `*_https_headers.txt` - HTTP response headers per domain
- `*_rpc_response.txt` - RPC response per domain
- `verification_report.md` - This report
## Notes
- **Optional domains:** Domains in `E2E_OPTIONAL_WHEN_FAIL` (default: many d-bis.org/sankofa/mim4u/rpc) have any fail treated as skip so the run passes when off-LAN or services unreachable. Set `E2E_OPTIONAL_WHEN_FAIL=` (empty) for strict mode.
- WebSocket tests require `wscat` tool: `npm install -g wscat`
- OpenSSL fetch uses `timeout` (`E2E_OPENSSL_TIMEOUT` / `E2E_OPENSSL_X509_TIMEOUT`, defaults 15s / 5s) so `openssl s_client` cannot hang indefinitely
- Internal connectivity tests require access to NPMplus container
- Explorer (explorer.d-bis.org): optional Blockscout API check; use `SKIP_BLOCKSCOUT_API=1` to skip when backend is unreachable (e.g. off-LAN). Fix runbook: docs/03-deployment/BLOCKSCOUT_FIX_RUNBOOK.md
## Next Steps
1. Review test results for each domain
2. Investigate any failed tests
3. Test WebSocket connections for RPC WS domains (if wscat available)
4. Test internal connectivity from NPMplus container
5. Update source-of-truth JSON after verification

View File

@@ -1,6 +1,6 @@
# E2E Success Runbook: Cloudflare Domains
**Last Updated:** 2026-02-05
**Last Updated:** 2026-03-27
**Status:** Active
**Purpose:** Achieve and verify complete end-to-end success for all public endpoints reachable via Cloudflare DNS (and optionally Fastly). All domains must pass DNS, SSL, and HTTP/RPC/WebSocket tests.
@@ -38,7 +38,7 @@ The verification script covers all public domains that require access from Cloud
| mim4u.org, www, secure, training | web | 192.168.11.37:80 |
| sankofa.nexus, www | web | 192.168.11.51:3000 |
| phoenix.sankofa.nexus, www | web | 192.168.11.50:4000 |
| the-order.sankofa.nexus | web | TBD |
| the-order.sankofa.nexus, www.the-order.sankofa.nexus | web | NPM → `192.168.11.39:80` (10210 HAProxy → `192.168.11.51:3000`); www → 301 apex |
| studio.sankofa.nexus | web | 192.168.11.72:8000 |
| rpc.public-0138.defi-oracle.io | rpc-http | 192.168.11.240:443 |
| rpc.defi-oracle.io | rpc-http | 192.168.11.221:8545 |

View File

@@ -1,10 +1,12 @@
# Gaps, Placeholders, and Recommendations — Consolidated
**Last Updated:** 2026-03-02
**Last Updated:** 2026-03-27
**Purpose:** Single reference for all identified gaps, placeholders, and actionable recommendations across the repository.
**Related:** [REQUIRED_FIXES_UPDATES_GAPS.md](REQUIRED_FIXES_UPDATES_GAPS.md) | [00-meta/GAPS_STATUS.md](00-meta/GAPS_STATUS.md) | [PLACEHOLDERS_AND_TBD.md](PLACEHOLDERS_AND_TBD.md) | [NOT_IMPLEMENTED_FULL_SCOPE](00-meta/NOT_IMPLEMENTED_FULL_SCOPE.md) | [ALL_RECOMMENDATIONS_AND_IMPROVEMENTS_LIST.md](00-meta/ALL_RECOMMENDATIONS_AND_IMPROVEMENTS_LIST.md) | [04-configuration/VERIFICATION_GAPS_AND_TODOS.md](04-configuration/VERIFICATION_GAPS_AND_TODOS.md). **Where to update when completed:** [00-meta/BLITZKRIEG_SOURCE_DOCUMENT_INDEX.md](00-meta/BLITZKRIEG_SOURCE_DOCUMENT_INDEX.md).
**Updates (2026-03-27):** Sankofa / The Order NPM routing documented as **live** (NPM → 10210 `192.168.11.39:80` → portal `:3000`). See [ALL_VMIDS_ENDPOINTS.md](04-configuration/ALL_VMIDS_ENDPOINTS.md), [SANKOFA_CUTOVER_PLAN.md](04-configuration/SANKOFA_CUTOVER_PLAN.md) v1.1. Section 2.1 below updated accordingly.
**Updates (2026-03-02):** All in-repo actionable gaps from REQUIRED_FIXES (§§16), DETAILED_GAPS, and VERIFICATION_GAPS addressed or documented. See [00-meta/GAPS_STATUS.md](00-meta/GAPS_STATUS.md). Fixes: verify-all-systems Explorer/Wallet timeout 25s; nginx order documented; runbook .env production note added.
**Updates (2026-02-05):** API keys in token-aggregation and root `.env.example` replaced with placeholders. `docs/TODO.md` and `smom-dbis-138/docs/TODO.md` created; smom-dbis-138 status-report links to `../tasks/TODO.md` fixed. RPC_ENDPOINTS_MASTER Sankofa section updated (sankofa.nexus → 7801/.51:3000, phoenix → 7800/.50:4000; the-order TBD). dbis_core nostro-vostro emergency hotline and example URLs set to "To be configured".
@@ -29,12 +31,12 @@
## 2. Configuration and DNS placeholders
### 2.1 Sankofa / The Order (TBD)
### 2.1 Sankofa / The Order (routing — **done 2026-03**)
| Item | Location | Recommendation |
|------|----------|----------------|
| `the-order.sankofa.nexus` | [ALL_VMIDS_ENDPOINTS.md](04-configuration/ALL_VMIDS_ENDPOINTS.md), [RPC_ENDPOINTS_MASTER.md](04-configuration/RPC_ENDPOINTS_MASTER.md) | Marked TBD / not yet configured. Once The Order portal is deployed, add NPMplus proxy host and document IP:port in RPC_ENDPOINTS_MASTER and ALL_VMIDS_ENDPOINTS. |
| Sankofa cutover plan | [SANKOFA_CUTOVER_PLAN.md](04-configuration/SANKOFA_CUTOVER_PLAN.md) | Replace `<TARGET_IP>`, `<TARGET_PORT>`, and table TBDs with actual Sankofa service IPs/ports when deployed. |
| Item | Location | Status / recommendation |
|------|----------|-------------------------|
| `the-order.sankofa.nexus` (+ `www`) | [ALL_VMIDS_ENDPOINTS.md](04-configuration/ALL_VMIDS_ENDPOINTS.md), [RPC_ENDPOINTS_MASTER.md](04-configuration/RPC_ENDPOINTS_MASTER.md) | **Live:** NPM → `192.168.11.39:80` (VMID 10210 HAProxy) → `192.168.11.51:3000`. Provision: `scripts/deployment/provision-order-haproxy-10210.sh`. |
| Sankofa cutover plan | [SANKOFA_CUTOVER_PLAN.md](04-configuration/SANKOFA_CUTOVER_PLAN.md) | **Updated v1.1 (2026-03-27):** live backend tables + historical procedure. Replace any remaining `<TARGET_*>` in copy-paste API examples if you reuse them for new hosts. |
### 2.2 sankofa.nexus / phoenix.sankofa.nexus routing (authoritative)

View File

@@ -62,6 +62,7 @@ Documents are archived when:
- **05-network-superseded/** — CLOUDFLARE_TUNNEL_ROUTING_ARCHITECTURE, CENTRAL_NGINX_ROUTING_SETUP (use CLOUDFLARE_ROUTING_MASTER and RPC_ENDPOINTS_MASTER instead).
- **00-meta-pruned/** — 27 one-off status/completion/planning/script-audit docs (batch 1: 10; batch 2: 17). Use NEXT_STEPS_OPERATOR, REMAINING_WORK_DETAILED_STEPS, OPERATIONAL_RUNBOOKS.
- **verification-evidence-old/** — Pruned 2026-02-08: verification run folders before 2026-02-06 (72 folders). Current runs remain in docs/04-configuration/verification-evidence/.
- **deployment-reports/** — Deployment/cutover snapshots (e.g. 2026-01). **Obsolete for routing:** see [deployment-reports/README.md](deployment-reports/README.md) and live docs above.
## Accessing Archived Documents
@@ -75,5 +76,5 @@ If an archived document needs to be restored, move it back to the main `docs/` d
**2026-02-20:** Batch 4 — 12 one-off/dated 00-meta docs → 00-meta-pruned. Batch 5 — CONTINUE_AND_COMPLETE, FULL_PARALLEL_RUN_LOG → 00-meta-pruned. ALL_TASKS_COMPLETE → root-status-reports. **Root cleanup:** 40+ status/temp/screenshot files from project root → [root-cleanup-20260220/](root-cleanup-20260220/README.md).
**Last Updated:** 2026-02-20
**Last Updated:** 2026-03-27

View File

@@ -0,0 +1,21 @@
# Archived deployment reports (historical)
Markdown files in this folder are **time-stamped snapshots** (mostly **2026-01**). They may still describe:
- `the-order.sankofa.nexus` as **TBD** or pointing at **192.168.11.140** (Blockscout)
- Sankofa/Phoenix as “not deployed” or on temporary backends
**Do not use these tables for operations.**
**Current source of truth**
- [ALL_VMIDS_ENDPOINTS.md](../../04-configuration/ALL_VMIDS_ENDPOINTS.md)
- [RPC_ENDPOINTS_MASTER.md](../../04-configuration/RPC_ENDPOINTS_MASTER.md)
- [SANKOFA_CUTOVER_PLAN.md](../../04-configuration/SANKOFA_CUTOVER_PLAN.md) (v1.1+)
- NPM fleet script: `scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh`
**The Order (summary):** NPM → `192.168.11.39:80` (VMID **10210** HAProxy) → portal `192.168.11.51:3000`.
---
**Last Updated:** 2026-03-27

View File

@@ -91,7 +91,7 @@ This document lists all tasks that were mentioned or identified during the conta
- [ ] Set up dashboards and alerts
#### Infrastructure Services (4 containers)
- **CT 10210** (order-haproxy) - HAProxy needs installation
- **CT 10210** (order-haproxy) **HAProxy installed 2026-03-27** (`config/haproxy/order-haproxy-10210.cfg.template`, `scripts/deployment/provision-order-haproxy-10210.sh`; unprivileged CT may need one-time host `chown -R 100000:100000` on mounted rootfs if apt fails)
- **CT 10230** (order-vault) - Vault needs installation
- **CT 5200** (cacti-1) - Cacti needs installation
- **CT 6000** (fabric-1) - Hyperledger Fabric needs installation
@@ -174,7 +174,7 @@ This document lists all tasks that were mentioned or identified during the conta
**Tasks:**
- [ ] Configure Order services to connect to PostgreSQL (192.168.11.44) and Redis (192.168.11.38)
- [ ] Configure DBIS services to connect to PostgreSQL (192.168.11.105) and Redis (192.168.11.120)
- [ ] Configure DBIS services to connect to PostgreSQL (192.168.11.105) and Redis (192.168.11.125)
- [ ] Configure frontend services to connect to API services
- [ ] Configure monitoring services to scrape targets
- [ ] Configure HAProxy backends

View File

@@ -121,7 +121,7 @@ echo "$ACTIVE_CERTS" | while IFS='|' read -r cert_id domain_names; do
done
# Check for duplicates in sankofa.nexus domains
SANKOFA_DOMAINS="sankofa.nexus,www.sankofa.nexus,phoenix.sankofa.nexus,www.phoenix.sankofa.nexus,the-order.sankofa.nexus"
SANKOFA_DOMAINS="sankofa.nexus,www.sankofa.nexus,phoenix.sankofa.nexus,www.phoenix.sankofa.nexus,the-order.sankofa.nexus,www.the-order.sankofa.nexus"
SANKOFA_CERTS=$(echo "$CERT_JSON" | jq -r ".[] | select(.is_deleted == 0) | select(.domain_names | tostring | test(\"sankofa.nexus\")) | .id" 2>/dev/null || echo "")
if [ -n "$SANKOFA_CERTS" ]; then

View File

@@ -0,0 +1,78 @@
#!/usr/bin/env bash
# Install HAProxy in LXC 10210 (order-haproxy) and proxy :80 → Sankofa/Order portal (Next.js).
# Requires SSH to Proxmox host that runs CT 10210 (default: r630-01). See config/ip-addresses.conf.
# Usage: ./scripts/deployment/provision-order-haproxy-10210.sh [--dry-run]
#
# One-time repair (unprivileged CT with host uid 0 on disk → "nobody" inside, apt broken): on Proxmox host,
# pct stop 10210 && pct mount 10210 && chown -R 100000:100000 /var/lib/lxc/10210/rootfs && pct unmount 10210 && pct start 10210
# (Default Proxmox idmap: container root = 100000 on host.)
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"
DRY_RUN=false
for a in "$@"; do [[ "$a" == "--dry-run" ]] && DRY_RUN=true; done
PROXMOX="${PROXMOX_ORDER_HAPROXY_NODE:-${PROXMOX_HOST_R630_01:-192.168.11.11}}"
VMID="${ORDER_HAPROXY_VMID:-10210}"
BACKEND_HOST="${ORDER_HAPROXY_BACKEND_HOST:-${IP_SANKOFA_PORTAL:-192.168.11.51}}"
BACKEND_PORT="${ORDER_HAPROXY_BACKEND_PORT:-${SANKOFA_PORTAL_PORT:-3000}}"
TEMPLATE="$PROJECT_ROOT/config/haproxy/order-haproxy-10210.cfg.template"
if [[ ! -r "$TEMPLATE" ]]; then
echo "❌ Missing template: $TEMPLATE"
exit 1
fi
CFG=$(sed -e "s/__BACKEND_HOST__/${BACKEND_HOST}/g" -e "s/__BACKEND_PORT__/${BACKEND_PORT}/g" "$TEMPLATE")
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Provision order-haproxy (CT $VMID on $PROXMOX)"
echo " Backend: http://${BACKEND_HOST}:${BACKEND_PORT}"
echo " Dry-run: $DRY_RUN"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
if [[ "$DRY_RUN" == true ]]; then
echo "$CFG"
exit 0
fi
remote_run() {
ssh -o BatchMode=yes -o ConnectTimeout=15 -o StrictHostKeyChecking=accept-new \
"${PROXMOX_SSH_USER:-root}@$PROXMOX" "$@"
}
if ! remote_run "pct status $VMID" 2>/dev/null | grep -q running; then
echo "❌ CT $VMID is not running on $PROXMOX"
exit 1
fi
remote_run "pct exec $VMID -- bash -c '
set -e
export DEBIAN_FRONTEND=noninteractive
if ! dpkg -s haproxy >/dev/null 2>&1; then
apt-get update -qq
apt-get install -y -qq haproxy
fi
'"
echo "$CFG" | remote_run "pct exec $VMID -- bash -c 'cat > /etc/haproxy/haproxy.cfg'"
remote_run "pct exec $VMID -- bash -c '
set -e
haproxy -c -f /etc/haproxy/haproxy.cfg
systemctl enable haproxy
systemctl restart haproxy
sleep 1
systemctl is-active --quiet haproxy
echo OK: haproxy active
command -v ss >/dev/null && ss -lntp | grep -E \":80|:443\" || true
'"
IP_ORDER="${IP_ORDER_HAPROXY:-192.168.11.39}"
echo ""
echo "✅ Done. From LAN: curl -sS -o /dev/null -w '%{http_code}\\n' http://${IP_ORDER}:80/"
echo " Then NPM: THE_ORDER_UPSTREAM_IP=${IP_ORDER} THE_ORDER_UPSTREAM_PORT=80 bash scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh"

View File

@@ -0,0 +1,46 @@
#!/usr/bin/env bash
# Ensure CT 7801 (or VMID) has NEXTAUTH_URL (public NPM host) and NEXTAUTH_SECRET.
# Does not print secret values. Safe to run after every portal sync.
#
# Env: PROXMOX_HOST, SANKOFA_PORTAL_VMID, SANKOFA_PORTAL_CT_DIR, SANKOFA_PORTAL_NEXTAUTH_URL
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
PROXMOX_HOST="${PROXMOX_HOST:-${PROXMOX_HOST_R630_01:-192.168.11.11}}"
VMID="${SANKOFA_PORTAL_VMID:-7801}"
CT_APP_DIR="${SANKOFA_PORTAL_CT_DIR:-/opt/sankofa-portal}"
SERVICE_NAME="${SANKOFA_PORTAL_SERVICE:-sankofa-portal}"
NEXTAUTH_PUBLIC_URL="${SANKOFA_PORTAL_NEXTAUTH_URL:-https://sankofa.nexus}"
SSH_OPTS="-o BatchMode=yes -o ConnectTimeout=15 -o StrictHostKeyChecking=accept-new"
ssh $SSH_OPTS "root@${PROXMOX_HOST}" "pct exec ${VMID} -- bash -s" <<EOF
set -euo pipefail
mkdir -p "${CT_APP_DIR}"
cd "${CT_APP_DIR}"
# .env.local (preferred for secrets / overrides)
ENV_LOCAL=".env.local"
touch "\$ENV_LOCAL"
if grep -q '^NEXTAUTH_URL=' "\$ENV_LOCAL" 2>/dev/null; then
sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=${NEXTAUTH_PUBLIC_URL}|" "\$ENV_LOCAL"
else
printf '%s\n' "NEXTAUTH_URL=${NEXTAUTH_PUBLIC_URL}" >> "\$ENV_LOCAL"
fi
if ! grep -q '^NEXTAUTH_SECRET=' "\$ENV_LOCAL" 2>/dev/null; then
printf '%s\n' "NEXTAUTH_SECRET=\$(openssl rand -hex 32)" >> "\$ENV_LOCAL"
fi
# .env on CT often ships with LAN NEXTAUTH_URL; Next merges both — align to public URL.
if [[ -f .env ]] && grep -q '^NEXTAUTH_URL=' .env 2>/dev/null; then
sed -i "s|^NEXTAUTH_URL=.*|NEXTAUTH_URL=${NEXTAUTH_PUBLIC_URL}|" .env
fi
EOF
ssh $SSH_OPTS "root@${PROXMOX_HOST}" "pct exec ${VMID} -- systemctl restart ${SERVICE_NAME}"
ssh $SSH_OPTS "root@${PROXMOX_HOST}" "pct exec ${VMID} -- systemctl is-active ${SERVICE_NAME}"
echo "NextAuth env ensured on CT ${VMID} (NEXTAUTH_URL=${NEXTAUTH_PUBLIC_URL}; secret added only if missing). Service restarted."

View File

@@ -0,0 +1,110 @@
#!/usr/bin/env bash
# Sync Sankofa Next.js portal source to LXC 7801, install deps, production build, restart systemd.
# Prerequisites: SSH root@PROXMOX_HOST; portal tree at SANKOFA_PORTAL_SRC (default: sibling ../Sankofa/portal).
#
# Usage:
# ./scripts/deployment/sync-sankofa-portal-7801.sh [--dry-run]
# Env:
# PROXMOX_HOST (default 192.168.11.11), SANKOFA_PORTAL_VMID (7801), SANKOFA_PORTAL_SRC, IP_SANKOFA_PORTAL (for post-check only)
# SANKOFA_PORTAL_NEXTAUTH_URL (default https://sankofa.nexus) — applied on CT after build
#
# See: docs/03-deployment/PUBLIC_SECTOR_LIVE_DEPLOYMENT_CHECKLIST.md (Phoenix CT 7801)
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
PROXMOX_HOST="${PROXMOX_HOST:-${PROXMOX_HOST_R630_01:-192.168.11.11}}"
VMID="${SANKOFA_PORTAL_VMID:-7801}"
CT_APP_DIR="${SANKOFA_PORTAL_CT_DIR:-/opt/sankofa-portal}"
SERVICE_NAME="${SANKOFA_PORTAL_SERVICE:-sankofa-portal}"
SSH_OPTS="-o BatchMode=yes -o ConnectTimeout=15 -o StrictHostKeyChecking=accept-new"
DEFAULT_SRC="${PROJECT_ROOT}/../Sankofa/portal"
if [[ -d "$DEFAULT_SRC" ]]; then
SANKOFA_PORTAL_SRC="${SANKOFA_PORTAL_SRC:-$DEFAULT_SRC}"
else
SANKOFA_PORTAL_SRC="${SANKOFA_PORTAL_SRC:-}"
fi
DRY_RUN=false
[[ "${1:-}" == "--dry-run" ]] && DRY_RUN=true
echo "=== Sync Sankofa portal → CT ${VMID} (${CT_APP_DIR}) ==="
echo "Proxmox: ${PROXMOX_HOST}"
echo "Source: ${SANKOFA_PORTAL_SRC:-<unset>}"
echo ""
if [[ -z "$SANKOFA_PORTAL_SRC" || ! -d "$SANKOFA_PORTAL_SRC" ]]; then
echo "ERROR: Set SANKOFA_PORTAL_SRC to the portal directory (clone of Sankofa/portal)."
echo "Example: SANKOFA_PORTAL_SRC=/path/to/Sankofa/portal $0"
exit 1
fi
if ! command -v tar >/dev/null; then
echo "ERROR: tar required"
exit 1
fi
TMP_TGZ="${TMPDIR:-/tmp}/sankofa-portal-sync-$$.tgz"
REMOTE_TGZ="/tmp/sankofa-portal-sync-$$.tgz"
CT_TGZ="/tmp/sankofa-portal-sync.tgz"
cleanup() { rm -f "$TMP_TGZ"; }
trap cleanup EXIT
if $DRY_RUN; then
echo "[DRY-RUN] tar (exclude node_modules,.next,.git) → $TMP_TGZ"
echo "[DRY-RUN] scp → root@${PROXMOX_HOST}:${REMOTE_TGZ}"
echo "[DRY-RUN] ssh pct push ${VMID} … && pct exec ${VMID} systemctl stop ${SERVICE_NAME}"
echo "[DRY-RUN] pct exec: tar xf into ${CT_APP_DIR}; pnpm install; pnpm build; systemctl start ${SERVICE_NAME}"
exit 0
fi
echo "📦 Archiving portal (excluding node_modules, .next, .git, .env / .env.local)…"
tar czf "$TMP_TGZ" \
--exclude=node_modules \
--exclude=.next \
--exclude=.git \
--exclude=.env.local \
--exclude=.env \
-C "$SANKOFA_PORTAL_SRC" .
echo "📤 Copy to Proxmox host…"
scp $SSH_OPTS "$TMP_TGZ" "root@${PROXMOX_HOST}:${REMOTE_TGZ}"
echo "📥 Push into CT ${VMID} and build…"
ssh $SSH_OPTS "root@${PROXMOX_HOST}" bash -s <<REMOTE_EOF
set -euo pipefail
pct push ${VMID} ${REMOTE_TGZ} ${CT_TGZ}
rm -f ${REMOTE_TGZ}
pct exec ${VMID} -- systemctl stop ${SERVICE_NAME} || true
pct exec ${VMID} -- bash -lc 'set -euo pipefail
mkdir -p ${CT_APP_DIR}
cd ${CT_APP_DIR}
tar xzf ${CT_TGZ}
rm -f ${CT_TGZ}
command -v pnpm >/dev/null || { echo "ERROR: pnpm missing in CT"; exit 1; }
pnpm install
pnpm build
'
pct exec ${VMID} -- systemctl start ${SERVICE_NAME}
pct exec ${VMID} -- systemctl is-active ${SERVICE_NAME}
REMOTE_EOF
echo ""
echo "🔐 Ensuring NextAuth URL/secret on CT (see sankofa-portal-ensure-nextauth-on-ct.sh)…"
SANKOFA_PORTAL_NEXTAUTH_URL="${SANKOFA_PORTAL_NEXTAUTH_URL:-https://sankofa.nexus}"
export SANKOFA_PORTAL_VMID SANKOFA_PORTAL_CT_DIR SANKOFA_PORTAL_SERVICE SANKOFA_PORTAL_NEXTAUTH_URL PROXMOX_HOST
bash "${SCRIPT_DIR}/sankofa-portal-ensure-nextauth-on-ct.sh"
echo ""
echo "✅ Done. Verify:"
echo " curl -sS http://${IP_SANKOFA_PORTAL:-192.168.11.51}:3000/ | head -c 120"
echo " curl -sSI https://sankofa.nexus/api/auth/signin | head -n 15"
echo " https://sankofa.nexus/ (via NPM)"
echo ""
echo "Override public auth URL: SANKOFA_PORTAL_NEXTAUTH_URL=https://portal.sankofa.nexus $0"

View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
# TsunamiSwap VM 5010 — inventory check + example qm lines (always informational).
# Ref: docs/00-meta/OPERATOR_READY_CHECKLIST.md section 5c.
#
# Usage: ./scripts/deployment/tsunamiswap-vm-5010-provision.sh
# Env: PROXMOX_HOST (default 192.168.11.11), TSUNAMI_VMID (5010)
#
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
PROXMOX_HOST="${PROXMOX_HOST:-${PROXMOX_HOST_R630_01:-192.168.11.11}}"
VMID="${TSUNAMI_VMID:-5010}"
SSH_OPTS="-o BatchMode=yes -o ConnectTimeout=15 -o StrictHostKeyChecking=accept-new"
echo "=== TsunamiSwap VM ${VMID} on ${PROXMOX_HOST} ==="
if ssh $SSH_OPTS "root@${PROXMOX_HOST}" "qm status ${VMID} 2>/dev/null" | grep -q .; then
echo "Status: VMID ${VMID} exists."
ssh $SSH_OPTS "root@${PROXMOX_HOST}" "qm status ${VMID}"
exit 0
fi
echo "Status: VMID ${VMID} not found (still to provision)."
echo "Checklist target: r630-01, 8 vCPU, 16 GB RAM, ~160 GB, IP e.g. 192.168.11.91."
echo "Create with your Proxmox template/ISO, then run setup/deploy scripts if available."
exit 0

View File

@@ -0,0 +1,62 @@
#!/usr/bin/env bash
# List or remove old E2E report dirs under docs/04-configuration/verification-evidence/e2e-verification-*
# Default: dry-run only. Deletes dirs older than KEEP_DAYS (default 45). Never deletes the two latest by mtime.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
EVIDENCE="$PROJECT_ROOT/docs/04-configuration/verification-evidence"
DRY_RUN=true
for a in "$@"; do
[[ "$a" == "--apply" ]] && DRY_RUN=false
done
KEEP_DAYS="${KEEP_DAYS:-45}"
MIN_KEEP="${MIN_KEEP:-2}"
if [[ ! -d "$EVIDENCE" ]]; then
echo "No directory: $EVIDENCE"
exit 1
fi
mapfile -t ALL < <(find "$EVIDENCE" -maxdepth 1 -type d -name 'e2e-verification-*' -printf '%T@ %p\n' 2>/dev/null | sort -n | awk '{print $2}')
if [[ ${#ALL[@]} -eq 0 ]]; then
echo "No e2e-verification-* directories under $EVIDENCE"
exit 0
fi
# Newest MIN_KEEP paths (never prune)
declare -A PROTECT
for ((i = ${#ALL[@]} - MIN_KEEP; i < ${#ALL[@]}; i++)); do
[[ $i -ge 0 ]] || continue
PROTECT["${ALL[$i]}"]=1
done
now=$(date +%s)
cutoff=$((now - KEEP_DAYS * 86400))
removed=0
checked=0
for dir in "${ALL[@]}"; do
[[ -n "${PROTECT[$dir]:-}" ]] && continue
mt=$(stat -c %Y "$dir" 2>/dev/null || echo 0)
(( checked++ )) || true
if (( mt < cutoff )); then
if [[ "$DRY_RUN" == true ]]; then
echo "Would remove (older than ${KEEP_DAYS}d): $dir"
else
rm -rf "$dir"
echo "Removed: $dir"
fi
(( removed++ )) || true
fi
done
if [[ "$DRY_RUN" == true ]]; then
echo ""
echo "Dry-run. Protected newest $MIN_KEEP dir(s). Set KEEP_DAYS=$KEEP_DAYS."
echo "To delete: KEEP_DAYS=$KEEP_DAYS bash $0 --apply"
else
echo "Done. Removed $removed director(y/ies); checked $checked (excluding protected)."
fi

View File

@@ -69,9 +69,8 @@ const DOMAINS = [
// www.* domains that redirect to parent domains
const REDIRECT_DOMAINS = [
// REMOVED: Sankofa redirects - services not deployed
// { domain: 'www.sankofa.nexus', redirectTo: 'sankofa.nexus' },
// { domain: 'www.phoenix.sankofa.nexus', redirectTo: 'phoenix.sankofa.nexus' },
// Sankofa www → apex: use scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh (301 via proxy host advanced_config).
// Do not add duplicate NPM "Redirection Host" rows for www.sankofa / www.phoenix here while those names are proxy hosts with LE certs.
{ domain: 'www.mim4u.org', redirectTo: 'mim4u.org' },
];

View File

@@ -3,21 +3,17 @@
# Auth failures: only a short error message is printed by default. For a redacted JSON snippet set NPM_DEBUG_AUTH=1.
set -euo pipefail
# Load IP configuration
# Repo root (…/proxmox) — same as second block below; load IPs once from the right path
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
# Update existing NPMplus proxy hosts via API with correct VMIDs and IPs
# This script updates existing proxy hosts, not creates new ones.
# PUT payload includes only forward_* / websocket / block_exploits — existing certificate_id and ssl_forced are preserved by NPMplus.
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
# Preserve NPM credentials from environment so "export NPM_PASSWORD=...; ./script" works
_orig_npm_url="${NPM_URL:-}"
_orig_npm_email="${NPM_EMAIL:-}"
@@ -58,11 +54,12 @@ echo ""
# NPMplus API can stall indefinitely without --max-time (override e.g. NPM_CURL_MAX_TIME=300)
NPM_CURL_MAX_TIME="${NPM_CURL_MAX_TIME:-120}"
curl_npm() { curl -s -k --connect-timeout 10 --max-time "$NPM_CURL_MAX_TIME" "$@"; }
# -L: port 81 often 301s HTTP→HTTPS; POST /api/tokens without -L returns 400 "Payload is undefined"
curl_npm() { curl -s -k -L --connect-timeout 10 --max-time "$NPM_CURL_MAX_TIME" "$@"; }
# Connection check (NPMplus is on LAN 192.168.11.x). Try HTTP if HTTPS fails; try alternate IP .166/.167 if unreachable.
echo "🔐 Authenticating to NPMplus..."
try_connect() { curl -s -k -o /dev/null --connect-timeout 5 --max-time 15 "$1" 2>/dev/null; }
try_connect() { curl -s -k -L -o /dev/null --connect-timeout 5 --max-time 15 "$1" 2>/dev/null; }
if ! try_connect "$NPM_URL/"; then
# Try HTTP instead of HTTPS (NPM admin often listens on HTTP only on port 81)
http_url="${NPM_URL/https:/http:}"
@@ -73,7 +70,7 @@ if ! try_connect "$NPM_URL/"; then
alt_url=""
if [[ "$NPM_URL" == *"${IP_NPMPLUS_ETH0}"* ]]; then
alt_url="https://${IP_NPMPLUS}:81"
elif [[ "$NPM_URL" == *"${IP_NPMPLUS}"* ]] || [[ "$NPM_URL" == *"${IP_NPMPLUS_ETH1}"* ]]; then
elif [[ "$NPM_URL" == *"${IP_NPMPLUS}"* ]] || [[ -n "${IP_NPMPLUS_ETH1:-}" && "$NPM_URL" == *"${IP_NPMPLUS_ETH1}"* ]]; then
alt_url="https://${IP_NPMPLUS_ETH0}:81"
fi
connected=""
@@ -134,13 +131,46 @@ resolve_proxy_host_id() {
.id' 2>/dev/null | head -n1
}
# www → apex redirect: only https://hostname[:port] (no path/query); rejects characters that could break nginx advanced_config.
validate_canonical_https_redirect() {
local url="$1"
local ctx="${2:-canonical_https}"
if [[ "$url" != https://* ]]; then
echo "$ctx: canonical_https must start with https:// (got: $url)"
return 1
fi
if [[ "$url" == *$'\n'* || "$url" == *$'\r'* || "$url" == *' '* || "$url" == *';'* || "$url" == *'$'* || "$url" == *'`'* ]]; then
echo "$ctx: canonical_https contains forbidden characters (no spaces, semicolons, dollar, backticks)"
return 1
fi
local rest="${url#https://}"
if [[ "$rest" == */* ]]; then
echo "$ctx: canonical_https must not include a path (got: $url)"
return 1
fi
if ! [[ "$rest" =~ ^[a-zA-Z0-9._-]+(:[0-9]{1,5})?$ ]]; then
echo "$ctx: canonical_https must be https://hostname or https://hostname:port (got: $url)"
return 1
fi
return 0
}
# Function to add proxy host (POST) when domain does not exist
# Optional 6th arg: canonical HTTPS apex for www-style hosts (sets advanced_config 301 → apex$request_uri)
add_proxy_host() {
local domain=$1
local forward_host=$2
local forward_port=$3
local websocket=$4
local block_exploits=${5:-false}
local canonical_https="${6:-}"
local adv_line=""
if [ -n "$canonical_https" ] && ! 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;"
fi
local payload
payload=$(jq -n \
--arg domain "$domain" \
@@ -148,6 +178,7 @@ add_proxy_host() {
--argjson port "$forward_port" \
--argjson ws "$websocket" \
--argjson block_exploits "$([ "$block_exploits" = "true" ] && echo true || echo false)" \
--arg adv "$adv_line" \
'{
domain_names: [$domain],
forward_scheme: "http",
@@ -157,7 +188,7 @@ add_proxy_host() {
block_exploits: $block_exploits,
certificate_id: null,
ssl_forced: false
}' 2>/dev/null)
} + (if $adv != "" then {advanced_config: $adv} else {} end)' 2>/dev/null)
if [ -z "$payload" ]; then
echo " ❌ Failed to build payload for $domain"
return 1
@@ -170,7 +201,11 @@ add_proxy_host() {
local id
id=$(echo "$resp" | jq -r '.id // empty' 2>/dev/null)
if [ -n "$id" ] && [ "$id" != "null" ]; then
echo " ✅ Added: $domain -> http://${forward_host}:${forward_port} (WebSocket: $websocket)"
if [ -n "$canonical_https" ]; then
echo " ✅ Added: $domain -> http://${forward_host}:${forward_port} (WebSocket: $websocket) + 301 → ${canonical_https}\$request_uri"
else
echo " ✅ Added: $domain -> http://${forward_host}:${forward_port} (WebSocket: $websocket)"
fi
return 0
else
local err
@@ -180,7 +215,7 @@ add_proxy_host() {
echo " ↪ Host likely exists; refreshing list and attempting PUT update..."
PROXY_HOSTS_JSON=$(curl_npm -X GET "$NPM_URL/api/nginx/proxy-hosts" \
-H "Authorization: Bearer $TOKEN")
if update_proxy_host "$domain" "http://${forward_host}:${forward_port}" "$websocket" "$block_exploits"; then
if update_proxy_host "$domain" "http://${forward_host}:${forward_port}" "$websocket" "$block_exploits" "$canonical_https"; then
echo " ✅ Updated after duplicate-create error: $domain"
return 0
fi
@@ -191,12 +226,17 @@ add_proxy_host() {
# Function to update proxy host
# block_exploits: set false for RPC hosts (JSON-RPC uses POST to /; block_exploits can cause 405)
# Optional 5th arg: canonical HTTPS URL (no path) — sets advanced_config to 301 redirect (www → apex)
update_proxy_host() {
local domain=$1
local target=$2
local websocket=$3
local block_exploits=${4:-true}
local canonical_https="${5:-}"
if [ -n "$canonical_https" ] && ! validate_canonical_https_redirect "$canonical_https" "update_proxy_host($domain)"; then
return 1
fi
# Parse target URL
local scheme=$(echo "$target" | sed -E 's|^([^:]+):.*|\1|')
local hostname=$(echo "$target" | sed -E 's|^[^/]+//([^:]+):.*|\1|')
@@ -208,6 +248,17 @@ update_proxy_host() {
hostname=$(echo "$target" | sed -E 's|^https://([^:]+):.*|\1|')
port=$(echo "$target" | sed -E 's|^https://[^:]+:([0-9]+).*|\1|' || echo "443")
fi
# Reject bad parses (e.g. https://:443 when forward IP env is empty) — NPM returns errors without .id and jq message is empty.
if [[ -z "$hostname" || "$hostname" == *"://"* || "$hostname" == *"/"* ]]; then
echo " ❌ Invalid forward target for $domain (check env / ip-addresses.conf): $target → host=[$hostname]"
return 1
fi
port="${port//[^0-9]/}"
if [[ -z "$port" || "$port" -lt 1 || "$port" -gt 65535 ]]; then
echo " ❌ Invalid forward port for $domain: $target (parsed port=$port)"
return 1
fi
# Get host ID (case-insensitive); refresh once if missing (stale list / race with other writers)
HOST_ID=$(resolve_proxy_host_id "$domain" "$PROXY_HOSTS_JSON")
@@ -228,19 +279,24 @@ update_proxy_host() {
# block_exploits must be false for RPC so POST to / is allowed (JSON-RPC); explicit false fixes 405
local be_json="false"
[ "$block_exploits" = "true" ] && be_json="true"
local adv_line=""
if [ -n "$canonical_https" ]; then
adv_line="return 301 ${canonical_https}\$request_uri;"
fi
UPDATE_PAYLOAD=$(jq -n \
--arg scheme "$scheme" \
--arg hostname "$hostname" \
--argjson port "$(echo "$port" | sed 's/[^0-9]//g' || echo "80")" \
--argjson websocket "$websocket" \
--argjson block_exploits "$be_json" \
--arg adv "$adv_line" \
'{
forward_scheme: $scheme,
forward_host: $hostname,
forward_port: $port,
allow_websocket_upgrade: $websocket,
block_exploits: $block_exploits
}' 2>/dev/null || echo "")
} + (if $adv != "" then {advanced_config: $adv} else {} end)' 2>/dev/null || echo "")
UPDATE_RESPONSE=$(curl_npm -X PUT "$NPM_URL/api/nginx/proxy-hosts/$HOST_ID" \
-H "Authorization: Bearer $TOKEN" \
@@ -250,10 +306,16 @@ update_proxy_host() {
UPDATE_ID=$(echo "$UPDATE_RESPONSE" | jq -r '.id // empty' 2>/dev/null || echo "")
if [ -n "$UPDATE_ID" ] && [ "$UPDATE_ID" != "null" ]; then
echo " ✅ Updated: $scheme://$hostname:$port (WebSocket: $websocket)"
if [ -n "$canonical_https" ]; then
echo " ✅ Updated: $scheme://$hostname:$port (WebSocket: $websocket) + 301 → ${canonical_https}\$request_uri"
else
echo " ✅ Updated: $scheme://$hostname:$port (WebSocket: $websocket)"
fi
return 0
else
ERROR=$(echo "$UPDATE_RESPONSE" | jq -r '.error.message // .error // "Unknown error"' 2>/dev/null || echo "$UPDATE_RESPONSE")
ERROR=$(echo "$UPDATE_RESPONSE" | jq -r '.error.message // .message // .error // empty' 2>/dev/null || echo "")
[ -z "$ERROR" ] && ERROR=$(echo "$UPDATE_RESPONSE" | head -c 400 | tr -d '\r\n')
[ -z "$ERROR" ] && ERROR="(empty API response — timeout or connection error; try NPM_CURL_MAX_TIME=300)"
echo " ❌ Failed: $ERROR"
return 1
fi
@@ -280,7 +342,9 @@ update_proxy_host "wss.tw-core.d-bis.org" "http://${RPC_THIRDWEB_ADMIN_CORE}:854
# Catch-all for foo.tw-core.d-bis.org → Besu HTTP JSON-RPC :8545 (exact rpc./wss. hosts above take precedence for nginx server_name)
update_proxy_host '*.tw-core.d-bis.org' "http://${RPC_THIRDWEB_ADMIN_CORE}:8545" true false && updated_count=$((updated_count + 1)) || { add_proxy_host '*.tw-core.d-bis.org' "${RPC_THIRDWEB_ADMIN_CORE}" 8545 true false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
# RPC Core-2 (Nathan) is on the THIRD NPMplus (192.168.11.169) — use add-rpc-core-2-npmplus-proxy.sh and update-npmplus-alltra-hybx-proxy-hosts.sh
update_proxy_host "rpc.public-0138.defi-oracle.io" "https://${RPC_THIRDWEB_PRIMARY}:443" true false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
# ThirdWeb / public-0138 edge (VMID 2400 nginx HTTPS) — default IP must match ALL_VMIDS_ENDPOINTS if env is unset
RPC_THIRDWEB_PRIMARY="${RPC_THIRDWEB_PRIMARY:-192.168.11.240}"
update_proxy_host "rpc.public-0138.defi-oracle.io" "https://${RPC_THIRDWEB_PRIMARY}:443" true false && updated_count=$((updated_count + 1)) || { sleep 2; echo " ↪ Retry rpc.public-0138.defi-oracle.io after transient NPM/API error..."; update_proxy_host "rpc.public-0138.defi-oracle.io" "https://${RPC_THIRDWEB_PRIMARY}:443" true false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1)); }
# rpc.defi-oracle.io / wss.defi-oracle.io → same backend as rpc-http-pub / rpc-ws-pub (VMID 2201)
update_proxy_host "rpc.defi-oracle.io" "http://${RPC_PUBLIC_1}:8545" true false && updated_count=$((updated_count + 1)) || { add_proxy_host "rpc.defi-oracle.io" "${RPC_PUBLIC_1}" 8545 true false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
update_proxy_host "wss.defi-oracle.io" "http://${RPC_PUBLIC_1}:8546" true false && updated_count=$((updated_count + 1)) || { add_proxy_host "wss.defi-oracle.io" "${RPC_PUBLIC_1}" 8546 true false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
@@ -309,6 +373,36 @@ update_proxy_host "dbis.xom-dev.phoenix.sankofa.nexus" "http://${IP_GOV_PORTALS_
update_proxy_host "iccc.xom-dev.phoenix.sankofa.nexus" "http://${IP_GOV_PORTALS_DEV}:3002" false && updated_count=$((updated_count + 1)) || { add_proxy_host "iccc.xom-dev.phoenix.sankofa.nexus" "${IP_GOV_PORTALS_DEV}" 3002 false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
update_proxy_host "omnl.xom-dev.phoenix.sankofa.nexus" "http://${IP_GOV_PORTALS_DEV}:3003" false && updated_count=$((updated_count + 1)) || { add_proxy_host "omnl.xom-dev.phoenix.sankofa.nexus" "${IP_GOV_PORTALS_DEV}" 3003 false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
update_proxy_host "xom.xom-dev.phoenix.sankofa.nexus" "http://${IP_GOV_PORTALS_DEV}:3004" false && updated_count=$((updated_count + 1)) || { add_proxy_host "xom.xom-dev.phoenix.sankofa.nexus" "${IP_GOV_PORTALS_DEV}" 3004 false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
# Sankofa portal (Next.js CT 7801) and Phoenix API (Fastify CT 7800) — not Blockscout / SolaceScanScout (that is explorer.d-bis.org / IP_BLOCKSCOUT:80)
# Public URL policy: https://sankofa.nexus = sovereign technology utility (portal); https://phoenix.sankofa.nexus = Phoenix division (API host; marketing site may share hostname later).
# www.sankofa.nexus → 301 https://sankofa.nexus$request_uri; www.phoenix → phoenix; www.the-order → the-order (NPM advanced_config).
IP_SANKOFA_PORTAL="${IP_SANKOFA_PORTAL:-${IP_SERVICE_51:-192.168.11.51}}"
IP_SANKOFA_PHOENIX_API="${IP_SANKOFA_PHOENIX_API:-${IP_SERVICE_50:-192.168.11.50}}"
SANKOFA_PORTAL_PORT="${SANKOFA_PORTAL_PORT:-3000}"
SANKOFA_PHOENIX_API_PORT="${SANKOFA_PHOENIX_API_PORT:-4000}"
update_proxy_host "sankofa.nexus" "http://${IP_SANKOFA_PORTAL}:${SANKOFA_PORTAL_PORT}" false false && updated_count=$((updated_count + 1)) || { add_proxy_host "sankofa.nexus" "${IP_SANKOFA_PORTAL}" "${SANKOFA_PORTAL_PORT}" false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
update_proxy_host "www.sankofa.nexus" "http://${IP_SANKOFA_PORTAL}:${SANKOFA_PORTAL_PORT}" false false "https://sankofa.nexus" && updated_count=$((updated_count + 1)) || { add_proxy_host "www.sankofa.nexus" "${IP_SANKOFA_PORTAL}" "${SANKOFA_PORTAL_PORT}" false false "https://sankofa.nexus" && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
update_proxy_host "phoenix.sankofa.nexus" "http://${IP_SANKOFA_PHOENIX_API}:${SANKOFA_PHOENIX_API_PORT}" false false && updated_count=$((updated_count + 1)) || { add_proxy_host "phoenix.sankofa.nexus" "${IP_SANKOFA_PHOENIX_API}" "${SANKOFA_PHOENIX_API_PORT}" false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
update_proxy_host "www.phoenix.sankofa.nexus" "http://${IP_SANKOFA_PHOENIX_API}:${SANKOFA_PHOENIX_API_PORT}" false false "https://phoenix.sankofa.nexus" && updated_count=$((updated_count + 1)) || { add_proxy_host "www.phoenix.sankofa.nexus" "${IP_SANKOFA_PHOENIX_API}" "${SANKOFA_PHOENIX_API_PORT}" false false "https://phoenix.sankofa.nexus" && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
# Keycloak (CT 7802) — portal SSO; NPM must forward X-Forwarded-* (Keycloak KC_PROXY_HEADERS=xforwarded on upstream)
IP_KEYCLOAK="${IP_KEYCLOAK:-192.168.11.52}"
update_proxy_host "keycloak.sankofa.nexus" "http://${IP_KEYCLOAK}:8080" false false && updated_count=$((updated_count + 1)) || { add_proxy_host "keycloak.sankofa.nexus" "${IP_KEYCLOAK}" 8080 false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
# the-order.sankofa.nexus — public hostname for the Sovereign Military Order of Malta (OSJ) management portal (secure auth).
# Application source (operator workstation): repo the_order at ~/projects/the_order (e.g. /home/intlc/projects/the_order).
# Default upstream: VMID 10210 order-haproxy @ IP_ORDER_HAPROXY:80 (provision: scripts/deployment/provision-order-haproxy-10210.sh).
# If 10210 is down: THE_ORDER_UPSTREAM_IP=${IP_SANKOFA_PORTAL} THE_ORDER_UPSTREAM_PORT=${SANKOFA_PORTAL_PORT} (direct portal 7801).
# www.the-order.sankofa.nexus → 301 https://the-order.sankofa.nexus$request_uri (same pattern as www.sankofa / www.phoenix).
IP_ORDER_HAPROXY="${IP_ORDER_HAPROXY:-192.168.11.39}"
THE_ORDER_UPSTREAM_IP="${THE_ORDER_UPSTREAM_IP:-${IP_ORDER_HAPROXY}}"
THE_ORDER_UPSTREAM_PORT="${THE_ORDER_UPSTREAM_PORT:-80}"
# block_exploits false — same policy as sankofa.nexus portal (Next/API-friendly; avoid 405 on some POST paths)
update_proxy_host "the-order.sankofa.nexus" "http://${THE_ORDER_UPSTREAM_IP}:${THE_ORDER_UPSTREAM_PORT}" false false && updated_count=$((updated_count + 1)) || { add_proxy_host "the-order.sankofa.nexus" "${THE_ORDER_UPSTREAM_IP}" "${THE_ORDER_UPSTREAM_PORT}" false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
update_proxy_host "www.the-order.sankofa.nexus" "http://${THE_ORDER_UPSTREAM_IP}:${THE_ORDER_UPSTREAM_PORT}" false false "https://the-order.sankofa.nexus" && updated_count=$((updated_count + 1)) || { add_proxy_host "www.the-order.sankofa.nexus" "${THE_ORDER_UPSTREAM_IP}" "${THE_ORDER_UPSTREAM_PORT}" false false "https://the-order.sankofa.nexus" && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
# Sankofa Studio (FusionAI) — VMID 7805; UI at /studio/ on same origin (port 8000). Prefer IP_SANKOFA_STUDIO from ip-addresses.conf / .env
IP_SANKOFA_STUDIO="${IP_SANKOFA_STUDIO:-192.168.11.72}"
SANKOFA_STUDIO_PORT="${SANKOFA_STUDIO_PORT:-8000}"
# block_exploits false — studio UI/API may POST; align with portal policy (avoid spurious 405 from NPM WAF)
update_proxy_host "studio.sankofa.nexus" "http://${IP_SANKOFA_STUDIO}:${SANKOFA_STUDIO_PORT}" false false && updated_count=$((updated_count + 1)) || { add_proxy_host "studio.sankofa.nexus" "${IP_SANKOFA_STUDIO}" "${SANKOFA_STUDIO_PORT}" false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1))
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

View File

@@ -3,6 +3,16 @@
# Sets all records to DNS only mode (gray cloud) for direct NAT routing
# Supports multiple zones: sankofa.nexus, d-bis.org, mim4u.org, defi-oracle.io
# UDM Pro port forwarding: 76.53.10.36:80/443 → ${IP_NPMPLUS:-${IP_NPMPLUS:-192.168.11.167}}:80/443 (NPMplus)
#
# WARNING: For each hostname, existing CNAME records are deleted before an A record is created.
# By default all configured zones are processed. Use --zone-only to limit scope.
#
# Usage:
# ./scripts/update-all-dns-to-public-ip.sh
# ./scripts/update-all-dns-to-public-ip.sh --dry-run
# ./scripts/update-all-dns-to-public-ip.sh --zone-only=sankofa.nexus
# ./scripts/update-all-dns-to-public-ip.sh --dry-run --zone-only=d-bis.org
# Env (optional): CLOUDFLARE_DNS_DRY_RUN=1, DNS_ZONE_ONLY=sankofa.nexus (same as flags)
set -euo pipefail
@@ -11,6 +21,22 @@ 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
# --help before .env (so operators can read usage without credentials)
for _arg in "$@"; do
if [[ "$_arg" == "--help" || "$_arg" == "-h" ]]; then
cat <<'EOF'
Cloudflare DNS → PUBLIC_IP (A records, DNS-only / gray cloud).
Options:
--dry-run Log intended changes only; no Cloudflare API calls.
--zone-only=ZONE ZONE one of: sankofa.nexus | d-bis.org | mim4u.org | defi-oracle.io
-h, --help This message.
Requires repo .env with Cloudflare auth and zone IDs (see script header).
EOF
exit 0
fi
done
# Colors
RED='\033[0;31m'
@@ -63,6 +89,23 @@ ZONE_D_BIS_ORG="${CLOUDFLARE_ZONE_ID_D_BIS_ORG:-${CLOUDFLARE_ZONE_ID:-}}"
ZONE_MIM4U_ORG="${CLOUDFLARE_ZONE_ID_MIM4U_ORG:-}"
ZONE_DEFI_ORACLE_IO="${CLOUDFLARE_ZONE_ID_DEFI_ORACLE_IO:-}"
# CLI / env: dry-run and single-zone scope
CLOUDFLARE_DNS_DRY_RUN="${CLOUDFLARE_DNS_DRY_RUN:-0}"
DNS_ZONE_ONLY="${DNS_ZONE_ONLY:-}"
parse_dns_update_cli_args() {
for arg in "$@"; do
case "$arg" in
--dry-run) CLOUDFLARE_DNS_DRY_RUN=1 ;;
--zone-only=*) DNS_ZONE_ONLY="${arg#*=}" ;;
esac
done
}
parse_dns_update_cli_args "$@"
if [ "$CLOUDFLARE_DNS_DRY_RUN" = "1" ]; then
log_warn "DRY-RUN: no Cloudflare list/create/update/delete API calls will be made."
fi
# Function to make Cloudflare API request
cf_api_request() {
local method="$1"
@@ -152,6 +195,11 @@ create_or_update_dns_record() {
fi
log_info "Processing: $full_name$ip (proxied: $proxied)"
if [ "$CLOUDFLARE_DNS_DRY_RUN" = "1" ]; then
log_success "[dry-run] Would remove CNAME(s) on $full_name if any, then upsert A → $ip (proxied=$proxied)"
return 0
fi
# Check for existing CNAME records (must delete before creating A record)
local all_records=$(get_all_dns_records "$zone_id" "$full_name")
@@ -256,28 +304,46 @@ main() {
echo ""
log_info "Public IP: $PUBLIC_IP"
log_info "Proxy Mode: DNS Only (gray cloud)"
if [ -n "$DNS_ZONE_ONLY" ]; then
log_info "Zone filter: only $DNS_ZONE_ONLY"
fi
echo ""
local total_failures=0
local run_sankofa=1 run_dbis=1 run_mim4u=1 run_defi=1
if [ -n "$DNS_ZONE_ONLY" ]; then
run_sankofa=0 run_dbis=0 run_mim4u=0 run_defi=0
case "$DNS_ZONE_ONLY" in
sankofa.nexus) run_sankofa=1 ;;
d-bis.org) run_dbis=1 ;;
mim4u.org) run_mim4u=1 ;;
defi-oracle.io) run_defi=1 ;;
*)
log_error "Unknown --zone-only=$DNS_ZONE_ONLY (expected: sankofa.nexus | d-bis.org | mim4u.org | defi-oracle.io)"
return 2
;;
esac
fi
# sankofa.nexus domain records
if [ -n "$ZONE_SANKOFA_NEXUS" ]; then
if [ "$run_sankofa" = 1 ] && [ -n "$ZONE_SANKOFA_NEXUS" ]; then
SANKOFA_RECORDS=(
"@" # sankofa.nexus
"www" # www.sankofa.nexus
"phoenix" # phoenix.sankofa.nexus
"www.phoenix" # www.phoenix.sankofa.nexus
"the-order" # the-order.sankofa.nexus
"www.the-order" # www.the-order.sankofa.nexus
)
if ! process_zone "$ZONE_SANKOFA_NEXUS" "sankofa.nexus" "${SANKOFA_RECORDS[@]}"; then
((total_failures++))
fi
else
elif [ "$run_sankofa" = 1 ]; then
log_warn "Skipping sankofa.nexus (no zone ID configured)"
fi
# d-bis.org domain records
if [ -n "$ZONE_D_BIS_ORG" ]; then
if [ "$run_dbis" = 1 ] && [ -n "$ZONE_D_BIS_ORG" ]; then
DBIS_RECORDS=(
"rpc-http-pub" # rpc-http-pub.d-bis.org
"rpc-ws-pub" # rpc-ws-pub.d-bis.org
@@ -296,12 +362,12 @@ main() {
if ! process_zone "$ZONE_D_BIS_ORG" "d-bis.org" "${DBIS_RECORDS[@]}"; then
((total_failures++))
fi
else
elif [ "$run_dbis" = 1 ]; then
log_warn "Skipping d-bis.org (no zone ID configured)"
fi
# mim4u.org domain records
if [ -n "$ZONE_MIM4U_ORG" ]; then
if [ "$run_mim4u" = 1 ] && [ -n "$ZONE_MIM4U_ORG" ]; then
MIM4U_RECORDS=(
"@" # mim4u.org
"www" # www.mim4u.org
@@ -311,12 +377,12 @@ main() {
if ! process_zone "$ZONE_MIM4U_ORG" "mim4u.org" "${MIM4U_RECORDS[@]}"; then
((total_failures++))
fi
else
elif [ "$run_mim4u" = 1 ]; then
log_warn "Skipping mim4u.org (no zone ID configured)"
fi
# defi-oracle.io domain records
if [ -n "$ZONE_DEFI_ORACLE_IO" ]; then
if [ "$run_defi" = 1 ] && [ -n "$ZONE_DEFI_ORACLE_IO" ]; then
DEFI_ORACLE_RECORDS=(
"explorer" # explorer.defi-oracle.io (Blockscout - same as explorer.d-bis.org)
"rpc.public-0138" # rpc.public-0138.defi-oracle.io
@@ -326,7 +392,7 @@ main() {
if ! process_zone "$ZONE_DEFI_ORACLE_IO" "defi-oracle.io" "${DEFI_ORACLE_RECORDS[@]}"; then
((total_failures++))
fi
else
elif [ "$run_defi" = 1 ]; then
log_warn "Skipping defi-oracle.io (no zone ID configured)"
fi
@@ -353,5 +419,5 @@ main() {
return $total_failures
}
# Run main function
main "$@"
# Run (CLI already parsed above)
main

View File

@@ -1,34 +1,52 @@
#!/usr/bin/env bash
set -euo pipefail
# Load IP configuration
# Update Sankofa NPMplus proxy hosts (portal + Phoenix API + the-order) via API by numeric host ID.
# Prefer for production: scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh (domain-based, full fleet).
# NPM proxy host IDs below match backup backup-20260325_183932 (36, 7, 59); override with SANKOFA_NPM_ID_* if your DB differs.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
# shellcheck source=/dev/null
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
# Update Sankofa NPMplus proxy hosts via API
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
# Load environment variables
if [ -f "$PROJECT_ROOT/.env" ]; then
export $(cat "$PROJECT_ROOT/.env" | grep -v '^#' | xargs)
set -a
# shellcheck source=/dev/null
source "$PROJECT_ROOT/.env"
set +a
fi
NPM_URL="${NPM_URL:-https://${IP_NPMPLUS}:81}"
NPM_EMAIL="${NPM_EMAIL:-nsatoshi2007@hotmail.com}"
NPM_PASSWORD="${NPM_PASSWORD:-}"
NPM_CURL_MAX_TIME="${NPM_CURL_MAX_TIME:-180}"
# Sankofa proxy host mappings
IP_SANKOFA_PORTAL="${IP_SANKOFA_PORTAL:-${IP_SERVICE_51:-192.168.11.51}}"
IP_SANKOFA_PHOENIX_API="${IP_SANKOFA_PHOENIX_API:-${IP_SERVICE_50:-192.168.11.50}}"
SANKOFA_PORTAL_PORT="${SANKOFA_PORTAL_PORT:-3000}"
SANKOFA_PHOENIX_API_PORT="${SANKOFA_PHOENIX_API_PORT:-4000}"
IP_ORDER_HAPROXY="${IP_ORDER_HAPROXY:-192.168.11.39}"
THE_ORDER_UPSTREAM_IP="${THE_ORDER_UPSTREAM_IP:-${IP_ORDER_HAPROXY}}"
THE_ORDER_UPSTREAM_PORT="${THE_ORDER_UPSTREAM_PORT:-80}"
# NPM proxy host IDs: sankofa=3, www.sankofa=4, phoenix=5, www.phoenix=6; the-order=7, www.the-order=59 (typical; verify in NPM UI)
SANKOFA_NPM_ID_ROOT="${SANKOFA_NPM_ID_ROOT:-3}"
SANKOFA_NPM_ID_WWW="${SANKOFA_NPM_ID_WWW:-4}"
SANKOFA_NPM_ID_PHOENIX="${SANKOFA_NPM_ID_PHOENIX:-5}"
SANKOFA_NPM_ID_WWW_PHOENIX="${SANKOFA_NPM_ID_WWW_PHOENIX:-6}"
SANKOFA_NPM_ID_THE_ORDER="${SANKOFA_NPM_ID_THE_ORDER:-7}"
SANKOFA_NPM_ID_WWW_THE_ORDER="${SANKOFA_NPM_ID_WWW_THE_ORDER:-59}"
# Optional 4th field: canonical HTTPS apex — NPM advanced_config 301 (www → apex). Matches update-npmplus-proxy-hosts-api.sh.
declare -A PROXY_HOSTS=(
["21"]="sankofa.nexus|${IP_SERVICE_51:-${IP_SERVICE_51:-${IP_SERVICE_51:-${IP_SERVICE_51:-${IP_SERVICE_51:-${IP_SERVICE_51:-192.168.11.51}}}}}}|3000"
["22"]="www.sankofa.nexus|${IP_SERVICE_51:-${IP_SERVICE_51:-${IP_SERVICE_51:-${IP_SERVICE_51:-${IP_SERVICE_51:-${IP_SERVICE_51:-192.168.11.51}}}}}}|3000"
["23"]="phoenix.sankofa.nexus|${IP_SERVICE_50:-${IP_SERVICE_50:-${IP_SERVICE_50:-${IP_SERVICE_50:-${IP_SERVICE_50:-${IP_SERVICE_50:-192.168.11.50}}}}}}|4000"
["24"]="www.phoenix.sankofa.nexus|${IP_SERVICE_50:-${IP_SERVICE_50:-${IP_SERVICE_50:-${IP_SERVICE_50:-${IP_SERVICE_50:-${IP_SERVICE_50:-192.168.11.50}}}}}}|4000"
["$SANKOFA_NPM_ID_ROOT"]="sankofa.nexus|${IP_SANKOFA_PORTAL}|${SANKOFA_PORTAL_PORT}|"
["$SANKOFA_NPM_ID_WWW"]="www.sankofa.nexus|${IP_SANKOFA_PORTAL}|${SANKOFA_PORTAL_PORT}|https://sankofa.nexus"
["$SANKOFA_NPM_ID_PHOENIX"]="phoenix.sankofa.nexus|${IP_SANKOFA_PHOENIX_API}|${SANKOFA_PHOENIX_API_PORT}|"
["$SANKOFA_NPM_ID_WWW_PHOENIX"]="www.phoenix.sankofa.nexus|${IP_SANKOFA_PHOENIX_API}|${SANKOFA_PHOENIX_API_PORT}|https://phoenix.sankofa.nexus"
["$SANKOFA_NPM_ID_THE_ORDER"]="the-order.sankofa.nexus|${THE_ORDER_UPSTREAM_IP}|${THE_ORDER_UPSTREAM_PORT}|"
["$SANKOFA_NPM_ID_WWW_THE_ORDER"]="www.the-order.sankofa.nexus|${THE_ORDER_UPSTREAM_IP}|${THE_ORDER_UPSTREAM_PORT}|https://the-order.sankofa.nexus"
)
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@@ -38,7 +56,7 @@ echo ""
# Authenticate
echo "🔐 Authenticating to NPMplus..."
TOKEN_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/tokens" \
TOKEN_RESPONSE=$(curl -s -k --connect-timeout 15 --max-time "$NPM_CURL_MAX_TIME" -X POST "$NPM_URL/api/tokens" \
-H "Content-Type: application/json" \
-d "{\"identity\":\"$NPM_EMAIL\",\"secret\":\"$NPM_PASSWORD\"}")
@@ -58,11 +76,12 @@ update_proxy_host() {
local domain=$2
local target_ip=$3
local target_port=$4
local canonical_https="${5:-}"
echo "📝 Updating Proxy Host $host_id: $domain$target_ip:$target_port"
# Get current proxy host
CURRENT_HOST=$(curl -s -k -X GET "$NPM_URL/api/nginx/proxy-hosts/$host_id" \
CURRENT_HOST=$(curl -s -k --connect-timeout 15 --max-time "$NPM_CURL_MAX_TIME" -X GET "$NPM_URL/api/nginx/proxy-hosts/$host_id" \
-H "Authorization: Bearer $TOKEN" 2>/dev/null || echo "{}")
if [ "$(echo "$CURRENT_HOST" | jq -r '.id // empty')" = "" ]; then
@@ -70,11 +89,28 @@ update_proxy_host() {
return 1
fi
# Update proxy host
UPDATE_PAYLOAD=$(echo "$CURRENT_HOST" | jq --arg ip "$target_ip" --arg port "$target_port" \
'.forward_host = $ip | .forward_port = ($port | tonumber)')
# NPMplus rejects full-document PUT (e.g. locations: null) — send only allowed forward fields.
local scheme="http"
local adv_line=""
if [ -n "$canonical_https" ]; then
adv_line="return 301 ${canonical_https}\$request_uri;"
fi
UPDATE_PAYLOAD=$(jq -n \
--arg scheme "$scheme" \
--arg hostname "$target_ip" \
--argjson port "$(echo "$target_port" | sed 's/[^0-9]//g')" \
--argjson websocket false \
--argjson block_exploits false \
--arg adv "$adv_line" \
'{
forward_scheme: $scheme,
forward_host: $hostname,
forward_port: $port,
allow_websocket_upgrade: $websocket,
block_exploits: $block_exploits
} + (if $adv != "" then {advanced_config: $adv} else {} end)')
RESPONSE=$(curl -s -k -X PUT "$NPM_URL/api/nginx/proxy-hosts/$host_id" \
RESPONSE=$(curl -s -k --connect-timeout 15 --max-time "${NPM_CURL_MAX_TIME:-120}" -X PUT "$NPM_URL/api/nginx/proxy-hosts/$host_id" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "$UPDATE_PAYLOAD")
@@ -87,6 +123,9 @@ update_proxy_host() {
else
echo "❌ Failed to update proxy host $host_id"
echo "$RESPONSE" | jq '.' 2>/dev/null || echo "$RESPONSE"
if echo "$RESPONSE" | jq -e '.error.code == 403' >/dev/null 2>&1; then
echo " (403 often means NPM user lacks permission to mutate proxy hosts; check UI role or use an admin identity.)"
fi
return 1
fi
}
@@ -96,9 +135,9 @@ SUCCESS=0
FAILED=0
for host_id in "${!PROXY_HOSTS[@]}"; do
IFS='|' read -r domain target_ip target_port <<< "${PROXY_HOSTS[$host_id]}"
IFS='|' read -r domain target_ip target_port canonical_https _ <<< "${PROXY_HOSTS[$host_id]}"
if update_proxy_host "$host_id" "$domain" "$target_ip" "$target_port"; then
if update_proxy_host "$host_id" "$domain" "$target_ip" "$target_port" "$canonical_https"; then
((SUCCESS++))
else
((FAILED++))

View File

@@ -55,6 +55,7 @@ declare -A DOMAIN_ZONES=(
["phoenix.sankofa.nexus"]="sankofa.nexus"
["www.phoenix.sankofa.nexus"]="sankofa.nexus"
["the-order.sankofa.nexus"]="sankofa.nexus"
["www.the-order.sankofa.nexus"]="sankofa.nexus"
["studio.sankofa.nexus"]="sankofa.nexus"
["rpc.public-0138.defi-oracle.io"]="defi-oracle.io"
)

View File

@@ -34,6 +34,9 @@ PUBLIC_IP_FOURTH="${PUBLIC_IP_FOURTH:-76.53.10.40}"
ACCEPT_ANY_DNS="${ACCEPT_ANY_DNS:-0}"
# Use system resolver (e.g. /etc/hosts) instead of dig @8.8.8.8 — set when running from LAN with generate-e2e-hosts.sh entries
E2E_USE_SYSTEM_RESOLVER="${E2E_USE_SYSTEM_RESOLVER:-0}"
# openssl s_client has no built-in connect timeout; wrap to avoid hangs (private/wss hosts).
E2E_OPENSSL_TIMEOUT="${E2E_OPENSSL_TIMEOUT:-15}"
E2E_OPENSSL_X509_TIMEOUT="${E2E_OPENSSL_X509_TIMEOUT:-5}"
if [ "$E2E_USE_SYSTEM_RESOLVER" = "1" ]; then
ACCEPT_ANY_DNS=1
log_info "E2E_USE_SYSTEM_RESOLVER=1: using getent (respects /etc/hosts); ACCEPT_ANY_DNS=1"
@@ -77,7 +80,8 @@ declare -A DOMAIN_TYPES_ALL=(
["www.sankofa.nexus"]="web"
["phoenix.sankofa.nexus"]="web"
["www.phoenix.sankofa.nexus"]="web"
["the-order.sankofa.nexus"]="web"
["the-order.sankofa.nexus"]="web" # OSJ portal (secure auth); app: ~/projects/the_order
["www.the-order.sankofa.nexus"]="web" # 301 → https://the-order.sankofa.nexus
["studio.sankofa.nexus"]="web"
["rpc.public-0138.defi-oracle.io"]="rpc-http"
["rpc.defi-oracle.io"]="rpc-http"
@@ -162,11 +166,15 @@ else
fi
# Domains that are optional when any test fails (off-LAN, 502, unreachable); fail → skip so run passes.
_PUB_OPTIONAL_WHEN_FAIL="dapp.d-bis.org mifos.d-bis.org explorer.d-bis.org dbis-admin.d-bis.org dbis-api.d-bis.org dbis-api-2.d-bis.org secure.d-bis.org sankofa.nexus www.sankofa.nexus phoenix.sankofa.nexus www.phoenix.sankofa.nexus the-order.sankofa.nexus www.the-order.sankofa.nexus studio.sankofa.nexus mim4u.org www.mim4u.org secure.mim4u.org training.mim4u.org rpc-http-pub.d-bis.org rpc.d-bis.org rpc2.d-bis.org rpc.public-0138.defi-oracle.io rpc.defi-oracle.io ws.rpc.d-bis.org ws.rpc2.d-bis.org"
_PRIV_OPTIONAL_WHEN_FAIL="rpc-http-prv.d-bis.org rpc-ws-prv.d-bis.org rpc-fireblocks.d-bis.org ws.rpc-fireblocks.d-bis.org"
if [[ -z "${E2E_OPTIONAL_WHEN_FAIL:-}" ]]; then
if [[ "$PROFILE" == "private" ]]; then
E2E_OPTIONAL_WHEN_FAIL="rpc-http-prv.d-bis.org rpc-ws-prv.d-bis.org rpc-fireblocks.d-bis.org ws.rpc-fireblocks.d-bis.org"
E2E_OPTIONAL_WHEN_FAIL="$_PRIV_OPTIONAL_WHEN_FAIL"
elif [[ "$PROFILE" == "all" ]]; then
E2E_OPTIONAL_WHEN_FAIL="$_PRIV_OPTIONAL_WHEN_FAIL $_PUB_OPTIONAL_WHEN_FAIL"
else
E2E_OPTIONAL_WHEN_FAIL="dapp.d-bis.org mifos.d-bis.org explorer.d-bis.org dbis-admin.d-bis.org dbis-api.d-bis.org dbis-api-2.d-bis.org secure.d-bis.org sankofa.nexus www.sankofa.nexus phoenix.sankofa.nexus www.phoenix.sankofa.nexus the-order.sankofa.nexus studio.sankofa.nexus mim4u.org www.mim4u.org secure.mim4u.org training.mim4u.org rpc-http-pub.d-bis.org rpc.d-bis.org rpc2.d-bis.org rpc.public-0138.defi-oracle.io rpc.defi-oracle.io ws.rpc.d-bis.org ws.rpc2.d-bis.org"
E2E_OPTIONAL_WHEN_FAIL="$_PUB_OPTIONAL_WHEN_FAIL"
fi
else
E2E_OPTIONAL_WHEN_FAIL="${E2E_OPTIONAL_WHEN_FAIL}"
@@ -178,6 +186,36 @@ declare -A EXPECTED_IP=(
["dev.d-bis.org"]="$PUBLIC_IP_FOURTH"
["codespaces.d-bis.org"]="$PUBLIC_IP_FOURTH"
)
# HTTPS check path (default "/"). API-first hosts may 404 on /; see docs/02-architecture/EXPECTED_WEB_CONTENT.md
declare -A E2E_HTTPS_PATH=(
["phoenix.sankofa.nexus"]="/health"
["www.phoenix.sankofa.nexus"]="/health"
["studio.sankofa.nexus"]="/studio/"
)
# Expected apex URL for NPM www → canonical 301/308 (Location must use this host; path from E2E_HTTPS_PATH must appear when set)
declare -A E2E_WWW_CANONICAL_BASE=(
["www.sankofa.nexus"]="https://sankofa.nexus"
["www.phoenix.sankofa.nexus"]="https://phoenix.sankofa.nexus"
["www.the-order.sankofa.nexus"]="https://the-order.sankofa.nexus"
)
# Returns 0 if Location URL matches expected canonical apex (and HTTPS path suffix when non-empty).
e2e_www_redirect_location_ok() {
local loc_val="$1" base="$2" path="${3:-}"
local loc_lc base_lc
loc_lc=$(printf '%s' "$loc_val" | tr '[:upper:]' '[:lower:]')
base_lc=$(printf '%s' "$base" | tr '[:upper:]' '[:lower:]')
if [[ "$loc_lc" != "$base_lc" && "$loc_lc" != "$base_lc/"* ]]; then
return 1
fi
if [ -n "$path" ] && [ "$path" != "/" ]; then
local p_lc
p_lc=$(printf '%s' "$path" | tr '[:upper:]' '[:lower:]')
[[ "$loc_lc" == *"$p_lc"* ]] || return 1
fi
return 0
}
# --list-endpoints: print selected profile endpoints and exit (no tests)
if [[ "$LIST_ENDPOINTS" == "1" ]]; then
@@ -257,7 +295,7 @@ test_domain() {
if [ "$domain_type" != "unknown" ]; then
log_info "Test 2: SSL Certificate"
cert_info=$(echo | openssl s_client -connect "$domain:443" -servername "$domain" 2>/dev/null | openssl x509 -noout -subject -issuer -dates -ext subjectAltName 2>/dev/null || echo "")
cert_info=$( (echo | timeout "$E2E_OPENSSL_TIMEOUT" openssl s_client -connect "$domain:443" -servername "$domain" 2>/dev/null) | timeout "$E2E_OPENSSL_X509_TIMEOUT" openssl x509 -noout -subject -issuer -dates -ext subjectAltName 2>/dev/null || echo "")
if [ -n "$cert_info" ]; then
cert_cn=$(echo "$cert_info" | grep "subject=" | sed -E 's/.*CN\s*=\s*([^,]*).*/\1/' | sed 's/^ *//;s/ *$//' || echo "")
@@ -301,10 +339,12 @@ test_domain() {
# Test 3: HTTPS Request
if [ "$domain_type" = "web" ] || [ "$domain_type" = "api" ]; then
log_info "Test 3: HTTPS Request"
https_path="${E2E_HTTPS_PATH[$domain]:-}"
https_url="https://${domain}${https_path}"
log_info "Test 3: HTTPS Request (${https_url})"
START_TIME=$(date +%s.%N)
http_response=$(curl -s -I -k --connect-timeout 10 -w "\n%{time_total}" "https://$domain" 2>&1 || echo "")
http_response=$(curl -s -I -k --connect-timeout 10 -w "\n%{time_total}" "$https_url" 2>&1 || echo "")
END_TIME=$(date +%s.%N)
RESPONSE_TIME=$(echo "$END_TIME - $START_TIME" | bc 2>/dev/null || echo "0")
@@ -315,8 +355,39 @@ test_domain() {
echo "$headers" > "$OUTPUT_DIR/${domain//./_}_https_headers.txt"
if [ -n "$http_code" ]; then
if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 400 ]; then
log_success "HTTPS: $domain returned HTTP $http_code (Time: ${time_total}s)"
# NPM canonical www → apex (advanced_config return 301/308)
local _e2e_canonical_www_redirect=""
local location_hdr=""
case "$domain" in
www.sankofa.nexus|www.phoenix.sankofa.nexus|www.the-order.sankofa.nexus)
if [ "$http_code" = "301" ] || [ "$http_code" = "308" ]; then
_e2e_canonical_www_redirect=1
fi
;;
esac
if [ -n "$_e2e_canonical_www_redirect" ]; then
location_hdr=$(echo "$headers" | grep -iE '^[Ll]ocation:' | head -1 | tr -d '\r' || echo "")
loc_val=$(printf '%s' "$location_hdr" | sed -E 's/^[Ll][Oo][Cc][Aa][Tt][Ii][Oo][Nn]:[[:space:]]*//' | sed 's/[[:space:]]*$//')
expected_base="${E2E_WWW_CANONICAL_BASE[$domain]:-}"
if [ -z "$loc_val" ]; then
log_warn "HTTPS: $domain returned HTTP $http_code but no Location header${https_path:+ (${https_url})}"
result=$(echo "$result" | jq --arg code "$http_code" --arg time "$time_total" \
'.tests.https = {"status": "warn", "http_code": ($code | tonumber), "response_time_seconds": ($time | tonumber), "note": "missing Location on redirect"}')
elif [ -z "$expected_base" ]; then
log_warn "HTTPS: $domain redirect pass (no E2E_WWW_CANONICAL_BASE entry)"
result=$(echo "$result" | jq --arg code "$http_code" --arg time "$time_total" --arg loc "$location_hdr" \
'.tests.https = {"status": "pass", "http_code": ($code | tonumber), "response_time_seconds": ($time | tonumber), "canonical_redirect": true, "location_header": $loc}')
elif ! e2e_www_redirect_location_ok "$loc_val" "$expected_base" "$https_path"; then
log_error "HTTPS: $domain Location mismatch (got \"$loc_val\", expected prefix \"$expected_base\" with path \"${https_path:-/}\")"
result=$(echo "$result" | jq --arg code "$http_code" --arg time "$time_total" --arg loc "$loc_val" --arg exp "$expected_base" --arg pth "${https_path:-}" \
'.tests.https = {"status": "fail", "http_code": ($code | tonumber), "response_time_seconds": ($time | tonumber), "reason": "location_mismatch", "location": $loc, "expected_prefix": $exp, "expected_path_suffix": $pth}')
else
log_success "HTTPS: $domain returned HTTP $http_code (canonical redirect → $loc_val)${https_path:+ at ${https_url}}"
result=$(echo "$result" | jq --arg code "$http_code" --arg time "$time_total" --arg loc "$location_hdr" \
'.tests.https = {"status": "pass", "http_code": ($code | tonumber), "response_time_seconds": ($time | tonumber), "canonical_redirect": true, "location_header": $loc}')
fi
elif [ "$http_code" -ge 200 ] && [ "$http_code" -lt 400 ]; then
log_success "HTTPS: $domain returned HTTP $http_code (Time: ${time_total}s)${https_path:+ at ${https_path}}"
# Check security headers
hsts=$(echo "$headers" | grep -i "strict-transport-security" || echo "")
@@ -330,12 +401,12 @@ test_domain() {
--argjson hsts "$HAS_HSTS" --argjson csp "$HAS_CSP" --argjson xfo "$HAS_XFO" \
'.tests.https = {"status": "pass", "http_code": ($code | tonumber), "response_time_seconds": ($time | tonumber), "has_hsts": $hsts, "has_csp": $csp, "has_xfo": $xfo}')
else
log_warn "HTTPS: $domain returned HTTP $http_code (Time: ${time_total}s)"
log_warn "HTTPS: $domain returned HTTP $http_code (Time: ${time_total}s)${https_path:+ (${https_url})}"
result=$(echo "$result" | jq --arg code "$http_code" --arg time "$time_total" \
'.tests.https = {"status": "warn", "http_code": ($code | tonumber), "response_time_seconds": ($time | tonumber)}')
fi
else
log_error "HTTPS: Failed to connect to $domain"
log_error "HTTPS: Failed to connect to ${https_url}"
result=$(echo "$result" | jq --arg time "$time_total" '.tests.https = {"status": "fail", "response_time_seconds": ($time | tonumber)}')
fi
# Optional: Blockscout API check for explorer.d-bis.org (does not affect E2E pass/fail)
@@ -401,13 +472,21 @@ test_domain() {
# Check if wscat is available for full test
if command -v wscat >/dev/null 2>&1; then
log_info " Attempting full WebSocket test with wscat..."
WS_FULL_TEST=$(timeout 3 wscat -c "wss://$domain" -x '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' 2>&1 || echo "")
# -n: no TLS verify (aligns with curl -k); -w: seconds to wait for JSON-RPC response
WS_FULL_TEST=""
WS_FULL_EXIT=0
if ! WS_FULL_TEST=$(timeout 15 wscat -n -c "wss://$domain" -x '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' -w 5 2>&1); then
WS_FULL_EXIT=$?
fi
if echo "$WS_FULL_TEST" | grep -q "result"; then
log_success "WebSocket: Full test passed"
result=$(echo "$result" | jq --arg code "$WS_RESULT" '.tests.websocket = {"status": "pass", "http_code": $code, "full_test": true}')
result=$(echo "$result" | jq --arg code "$WS_RESULT" '.tests.websocket = {"status": "pass", "http_code": $code, "full_test": true, "full_test_output": "result"}')
elif [ "$WS_FULL_EXIT" -eq 0 ]; then
log_success "WebSocket: Full test connected cleanly"
result=$(echo "$result" | jq --arg code "$WS_RESULT" '.tests.websocket = {"status": "pass", "http_code": $code, "full_test": true, "note": "wscat exited successfully without printable RPC output"}')
else
log_warn "WebSocket: Connection established but RPC test failed"
result=$(echo "$result" | jq --arg code "$WS_RESULT" '.tests.websocket = {"status": "warning", "http_code": $code, "full_test": false}')
result=$(echo "$result" | jq --arg code "$WS_RESULT" --arg exit_code "$WS_FULL_EXIT" '.tests.websocket = {"status": "warning", "http_code": $code, "full_test": false, "exit_code": $exit_code}')
fi
else
log_warn "WebSocket: Basic test (Code: $WS_RESULT) - Install wscat for full test: npm install -g wscat"
@@ -558,6 +637,7 @@ cat >> "$REPORT_FILE" <<EOF
- **Optional domains:** Domains in \`E2E_OPTIONAL_WHEN_FAIL\` (default: many d-bis.org/sankofa/mim4u/rpc) have any fail treated as skip so the run passes when off-LAN or services unreachable. Set \`E2E_OPTIONAL_WHEN_FAIL=\` (empty) for strict mode.
- WebSocket tests require \`wscat\` tool: \`npm install -g wscat\`
- OpenSSL fetch uses \`timeout\` (\`E2E_OPENSSL_TIMEOUT\` / \`E2E_OPENSSL_X509_TIMEOUT\`, defaults 15s / 5s) so \`openssl s_client\` cannot hang indefinitely
- Internal connectivity tests require access to NPMplus container
- Explorer (explorer.d-bis.org): optional Blockscout API check; use \`SKIP_BLOCKSCOUT_API=1\` to skip when backend is unreachable (e.g. off-LAN). Fix runbook: docs/03-deployment/BLOCKSCOUT_FIX_RUNBOOK.md