diff --git a/.env.master.example b/.env.master.example index bfd72f36..c948b0fc 100644 --- a/.env.master.example +++ b/.env.master.example @@ -95,6 +95,15 @@ NPM_URL_MIFOS= # SPA: default runtime base is {origin}/token-aggregation (nginx on 2410 proxies to Blockscout). Override only if needed: # In info-defi-oracle-138/.env.local (not this file): VITE_TOKEN_AGGREGATION_API_BASE=https://explorer.d-bis.org/token-aggregation +# --- mev.defi-oracle.io (MEV Control GUI on nginx LXC 2410 by default) --- +# MEV_ADMIN_API_HOST=192.168.11.11 # LAN host reachable from CT; mev-admin-api listen address +# MEV_ADMIN_API_PORT=9090 +# MEV_DEFI_ORACLE_WEB_VMID=2410 +# MEV_DEFI_ORACLE_UPSTREAM_IP= # NPM: forward_host override (default IP_INFO_DEFI_ORACLE_WEB) +# MEV_DEFI_ORACLE_UPSTREAM_PORT=80 +# MEV_DEFI_ORACLE_EDGE_MODE=auto # Cloudflare DNS script (same as info: auto|tunnel|public_ip) +# MEV_DEFI_ORACLE_PUBLIC_IP= # A-record mode WAN IP if not using tunnel + # --- Keycloak Admin API (optional) --- # For scripts/deployment/keycloak-sankofa-ensure-client-redirects.sh — merge portal/admin redirect URIs. # KEYCLOAK_URL=https://keycloak.sankofa.nexus diff --git a/AGENTS.md b/AGENTS.md index e4f28cce..03a075eb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,6 +14,7 @@ Orchestration for Proxmox VE, Chain 138 (`smom-dbis-138/`), explorers, NPMplus, | Chain 138 PMM swap quote (CLI) | `bash scripts/verify/pmm-swap-quote-chain138.sh --token-in … --amount-in …` — on-chain `querySellBase`/`querySellQuote` + suggested `minOut` for `DODOPMMIntegration.swapExactIn` (REST `/quote` is xy=k only). | | **DeFi economics toolkit** (flash/gas buckets, path gate, dry-run exec, live gas quotes, multi-leg strategies) | `pnpm run economics:test`; `pnpm run economics:validate` (parse + optional `check-jsonschema` on smoke/template); `pnpm exec economics-toolkit calc|path-check|gas-quote|gas-budget|prepare-swap|exec`; `pnpm exec economics-toolkit strategy kinds|template|validate|eval|optimize|optimize-multi|optimize-random|optimize-descent|enrich|runbook|exec-plan`; live refresh: `bash scripts/economics/refresh-strategy-from-live.sh [--apply] `; examples `config/strategy-bounds.example.json`, `config/strategy-optimize-dims.example.json`; template `packages/economics-toolkit/config/strategy-template.json`, smoke `strategy-smoke.json`, schema `strategy.schema.json`; allowlist `packages/economics-toolkit/config/executor-allowlist.example.json`; `gas-networks.json`; flow tables `packages/economics-toolkit/docs/FLOW_INPUTS_OUTPUTS_TABLE.md`; CI `.github/workflows/economics-toolkit.yml`. | | Chain 138 info site (`info.defi-oracle.io`) | Dedicated nginx LXC (default VMID **2410** / `IP_INFO_DEFI_ORACLE_WEB`): `provision-info-defi-oracle-web-lxc.sh` then `sync-info-defi-oracle-to-vmid2400.sh` (sync asserts `/token-aggregation` proxy); NPM fleet `scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh`; Cloudflare DNS `scripts/cloudflare/set-info-defi-oracle-dns-to-vmid2400-tunnel.sh`; cache `pnpm run cloudflare:purge-info-defi-oracle-cache`; runbook `docs/04-configuration/INFO_DEFI_ORACLE_IO_DEPLOYMENT.md`; `pnpm run verify:info-defi-oracle-public` (SPA routes including `/governance`, `/ecosystem`, `/documentation`, `/solacenet`, `llms.txt`, `agent-hints.json`, **same-origin** token-aggregation JSON; `INFO_SITE_BASE=…` optional); CI `info-defi-oracle-138.yml` (build) and `verify-info-defi-oracle-public.yml` (weekly + manual smoke); optional `pnpm run audit:info-defi-oracle-site` (`pnpm exec playwright install chromium`) | +| **MEV Control GUI** (`mev.defi-oracle.io`) | Same nginx LXC as info by default: `scripts/deployment/sync-mev-control-gui-defi-oracle.sh` (builds `MEV_Bot/mev-platform/gui`, installs `/api` proxy to `MEV_ADMIN_API_HOST`:`MEV_ADMIN_API_PORT`); NPM + DNS via `update-npmplus-proxy-hosts-api.sh` and `scripts/cloudflare/set-mev-defi-oracle-dns.sh`; runbook `docs/04-configuration/MEV_CONTROL_DEFI_ORACLE_IO_DEPLOYMENT.md` | | **omdnl.org** (static landing) | Nginx LXC VMID **10203** / `IP_OMDNL_ORG_WEB` (default 192.168.11.222): `scripts/deployment/provision-omdnl-org-web-lxc.sh` → `sync-omdnl-org-static-to-ct.sh`; Cloudflare `configure-omdnl-org-dns.sh` (`CLOUDFLARE_ZONE_ID_OMDNL_ORG`, `PUBLIC_IP`); NPM `upsert-omdnl-org-proxy-host.sh`; content in `sites/omdnl-org/public/`. | | **SolaceNet + gateway rails** (dbis_core) | Hub map: `docs/04-configuration/SOLACENET_PUBLIC_HUB.md`. Backlog: `dbis_core/docs/solacenet/REMAINING_TASKS_FULL_LIST.md`. Gap IDs: `dbis_core/docs/solacenet/PROTOCOL_GAPS_CHECKLIST.md`. **Delta audit** (missing wiring, naming drift, CI): `dbis_core/docs/solacenet/AUDIT_GAPS_INCONSISTENCIES_MISSING.md`. Enforce rails runbook: `dbis_core/docs/solacenet/SOLACENET_GATEWAY_RAILS_ENFORCE_RUNBOOK.md`. Tests: `cd dbis_core && npm run test:gateway` (unit + HTTP integration). **Provider seed:** `cd dbis_core && npm run seed:gateway-provider` (needs `DATABASE_URL`). **Smoke (auth):** `bash scripts/verify/check-dbis-core-gateway-rails.sh`. **Outbox worker:** `cd dbis_core && npm run worker:gateway-outbox` (`DATABASE_URL`). CI: `.github/workflows/dbis-core-gateway-ci.yml`. API: `GET/POST /api/v1/gateway/rails*` (optional `SOLACENET_GATEWAY_RAILS_ENFORCE`) — `dbis_core/src/core/gateway/routes/gateway.routes.ts`. | | cXAUC/cXAUT unit | 1 full token = 1 troy oz Au — `docs/11-references/EXPLORER_TOKEN_LIST_CROSSCHECK.md` (section 5.1) | diff --git a/config/ip-addresses.conf b/config/ip-addresses.conf index bca5bd5a..340a2090 100644 --- a/config/ip-addresses.conf +++ b/config/ip-addresses.conf @@ -84,6 +84,14 @@ IP_BESU_RPC_PRIVATE_1="${IP_BESU_RPC_PRIVATE_1:-${RPC_PRIVATE_1}}" IP_INFO_DEFI_ORACLE_WEB="${IP_INFO_DEFI_ORACLE_WEB:-192.168.11.218}" INFO_DEFI_ORACLE_WEB_VMID="${INFO_DEFI_ORACLE_WEB_VMID:-2410}" +# MEV Control GUI — https://mev.defi-oracle.io (static on same LXC as info by default; /api → mev-admin-api). +MEV_DEFI_ORACLE_WEB_VMID="${MEV_DEFI_ORACLE_WEB_VMID:-${INFO_DEFI_ORACLE_WEB_VMID:-2410}}" +MEV_DEFI_ORACLE_WEB_ROOT="${MEV_DEFI_ORACLE_WEB_ROOT:-/var/www/mev.defi-oracle.io/html}" +MEV_DEFI_ORACLE_NGINX_SITE="${MEV_DEFI_ORACLE_NGINX_SITE:-/etc/nginx/sites-available/mev-defi-oracle}" +# LAN host running mev-admin-api (must be reachable from the nginx CT). Override in .env. +MEV_ADMIN_API_HOST="${MEV_ADMIN_API_HOST:-192.168.11.11}" +MEV_ADMIN_API_PORT="${MEV_ADMIN_API_PORT:-9090}" + # Static landing https://omdnl.org (nginx LXC). Provision: scripts/deployment/provision-omdnl-org-web-lxc.sh IP_OMDNL_ORG_WEB="${IP_OMDNL_ORG_WEB:-192.168.11.222}" OMDNL_ORG_WEB_VMID="${OMDNL_ORG_WEB_VMID:-10203}" diff --git a/config/nginx/mev-defi-oracle-io.site.conf.template b/config/nginx/mev-defi-oracle-io.site.conf.template new file mode 100644 index 00000000..1ce0944f --- /dev/null +++ b/config/nginx/mev-defi-oracle-io.site.conf.template @@ -0,0 +1,36 @@ +# MEV Control GUI (Vite dist/) — https://mev.defi-oracle.io +# Deploy: scripts/deployment/sync-mev-control-gui-defi-oracle.sh (substitutes __MEV_ADMIN_API_UPSTREAM__) +# Same nginx LXC as info.defi-oracle.io (VMID 2410) by default; distinct server_name + root. +server { + listen 80; + listen [::]:80; + server_name mev.defi-oracle.io www.mev.defi-oracle.io; + + root /var/www/mev.defi-oracle.io/html; + index index.html; + + access_log /var/log/nginx/mev-defi-oracle-access.log; + error_log /var/log/nginx/mev-defi-oracle-error.log; + + location = /health { + access_log off; + add_header Content-Type text/plain; + return 200 "mev-gui-healthy\n"; + } + + # mev-admin-api (Axum). Browser calls same-origin /api/* from the SPA. + location /api/ { + proxy_pass __MEV_ADMIN_API_UPSTREAM__/api/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 300s; + proxy_buffering off; + } + + location / { + try_files $uri $uri/ /index.html; + } +} diff --git a/docs/04-configuration/ALL_VMIDS_ENDPOINTS.md b/docs/04-configuration/ALL_VMIDS_ENDPOINTS.md index 3747c67d..c06b9850 100644 --- a/docs/04-configuration/ALL_VMIDS_ENDPOINTS.md +++ b/docs/04-configuration/ALL_VMIDS_ENDPOINTS.md @@ -151,7 +151,7 @@ All RPC nodes have been migrated to a new VMID structure for better organization | VMID | IP Address | Hostname | Status | Endpoints | Purpose | |------|------------|----------|--------|-----------|---------| -| 2410 | 192.168.11.218 | info-defi-oracle-web | ✅ Running | **HTTP: 80** (nginx) | **info.defi-oracle.io** Vite SPA (incl. `/governance`, `/ecosystem`, `/documentation`, `/disclosures`, `/agents`) + **`/token-aggregation/`** → `IP_BLOCKSCOUT` — `config/nginx/info-defi-oracle-io.site.conf`; `provision-info-defi-oracle-web-lxc.sh` + `sync-info-defi-oracle-to-vmid2400.sh`; NPM upstream `IP_INFO_DEFI_ORACLE_WEB` | +| 2410 | 192.168.11.218 | info-defi-oracle-web | ✅ Running | **HTTP: 80** (nginx) | **info.defi-oracle.io** Vite SPA (incl. `/governance`, `/ecosystem`, `/documentation`, `/disclosures`, `/agents`) + **`/token-aggregation/`** → `IP_BLOCKSCOUT` — `config/nginx/info-defi-oracle-io.site.conf`; `provision-info-defi-oracle-web-lxc.sh` + `sync-info-defi-oracle-to-vmid2400.sh`; **mev.defi-oracle.io** MEV Control GUI + `/api` → mev-admin-api — `config/nginx/mev-defi-oracle-io.site.conf.template` + `sync-mev-control-gui-defi-oracle.sh`; NPM upstream `IP_INFO_DEFI_ORACLE_WEB` (see [MEV_CONTROL_DEFI_ORACLE_IO_DEPLOYMENT.md](MEV_CONTROL_DEFI_ORACLE_IO_DEPLOYMENT.md)) | **Note**: VMID 2400 is the primary ThirdWeb RPC with Nginx and RPC Translator — **do not** host the info SPA there. The 2026-04-02 probe showed all ThirdWeb-side nodes responding normally. diff --git a/docs/04-configuration/MEV_CONTROL_DEFI_ORACLE_IO_DEPLOYMENT.md b/docs/04-configuration/MEV_CONTROL_DEFI_ORACLE_IO_DEPLOYMENT.md new file mode 100644 index 00000000..b5fcf4f9 --- /dev/null +++ b/docs/04-configuration/MEV_CONTROL_DEFI_ORACLE_IO_DEPLOYMENT.md @@ -0,0 +1,87 @@ +# MEV Control GUI — mev.defi-oracle.io + +**Last Updated:** 2026-04-13 +**Document Version:** 1.0 +**Status:** Deployment runbook + +This document describes how to publish the **MEV Control** web app (`MEV_Bot/mev-platform/gui`) at **https://mev.defi-oracle.io** (and **www.mev.defi-oracle.io**), using the same edge pattern as **info.defi-oracle.io**: nginx on LAN, NPMplus on the public edge, optional Cloudflare DNS. + +## Architecture + +| Layer | Role | +|--------|------| +| **Static SPA** | Vite `dist/` on the nginx LXC (default **VMID 2410**, same CT as `info.defi-oracle.io` unless overridden). | +| **`/api/*`** | Nginx `proxy_pass` to **mev-admin-api** (Axum, default port **9090**) on a LAN host reachable from the CT. | +| **NPMplus** | TLS termination; forwards `mev.defi-oracle.io` → `http://IP_INFO_DEFI_ORACLE_WEB:80` (or `MEV_DEFI_ORACLE_UPSTREAM_*`). | +| **Cloudflare** | Optional proxied **A** or **CNAME** (tunnel) for `mev.defi-oracle.io` / `www.mev.defi-oracle.io`. | + +The browser uses **same-origin** `/api` (no CORS split). Set **`MEV_ADMIN_API_HOST`** / **`MEV_ADMIN_API_PORT`** so the nginx CT can reach the machine where `cargo run -p mev-admin-api` (or your unit) listens. + +## Prerequisites + +1. **info** nginx LXC exists and nginx works (VMID **2410** by default): see [INFO_DEFI_ORACLE_IO_DEPLOYMENT.md](INFO_DEFI_ORACLE_IO_DEPLOYMENT.md). +2. **MEV_Bot** submodule present at repo root (`MEV_Bot/mev-platform/gui`). +3. **mev-admin-api** reachable from the CT at `http://${MEV_ADMIN_API_HOST}:${MEV_ADMIN_API_PORT}` (firewall / bind address). +4. Operator **LAN** + SSH to Proxmox; repo `.env` with **NPM_PASSWORD** (and Cloudflare token if using DNS script). + +## Deploy or refresh the GUI + +From **proxmox** repo root (loads paths; override via env): + +```bash +# Optional: export MEV_ADMIN_API_HOST=192.168.11.xx MEV_ADMIN_API_PORT=9090 +bash scripts/deployment/sync-mev-control-gui-defi-oracle.sh --dry-run +bash scripts/deployment/sync-mev-control-gui-defi-oracle.sh +``` + +This builds with `npm ci && npm run build` in `MEV_Bot/mev-platform/gui`, installs files under `/var/www/mev.defi-oracle.io/html`, renders [config/nginx/mev-defi-oracle-io.site.conf.template](../../config/nginx/mev-defi-oracle-io.site.conf.template) with your admin API upstream, enables `sites-enabled/mev-defi-oracle`, and reloads nginx. + +## NPMplus + +Fleet update (creates or updates proxy hosts): + +```bash +bash scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh +``` + +Hosts: **mev.defi-oracle.io**, **www.mev.defi-oracle.io** (apex canonical for www). Upstream defaults match **info** (`IP_INFO_DEFI_ORACLE_WEB`:80). Override with `MEV_DEFI_ORACLE_UPSTREAM_IP` / `MEV_DEFI_ORACLE_UPSTREAM_PORT` if the GUI is served from another LAN IP. + +Request or renew TLS certificates in NPMplus for the new hostnames (same workflow as other `*.defi-oracle.io` hosts). + +## Cloudflare (defi-oracle.io zone) + +Same credentials and zone id as **info** (`CLOUDFLARE_ZONE_ID_DEFI_ORACLE_IO`). Edge mode defaults to **auto** (tunnel if tunnel id exists, else **A** to `PUBLIC_IP`): + +```bash +bash scripts/cloudflare/set-mev-defi-oracle-dns.sh +``` + +Optional: `MEV_DEFI_ORACLE_EDGE_MODE=tunnel|public_ip|auto`, `MEV_DEFI_ORACLE_PUBLIC_IP=…`. + +## Configuration reference + +| Variable | Default (see `config/ip-addresses.conf`) | Purpose | +|----------|--------------------------------------------|---------| +| `MEV_DEFI_ORACLE_WEB_VMID` | `2410` | Target LXC | +| `MEV_DEFI_ORACLE_WEB_ROOT` | `/var/www/mev.defi-oracle.io/html` | Web root | +| `MEV_ADMIN_API_HOST` | `192.168.11.11` | mev-admin-api bind host (from CT) | +| `MEV_ADMIN_API_PORT` | `9090` | mev-admin-api port | +| `MEV_DEFI_ORACLE_UPSTREAM_IP` | `IP_INFO_DEFI_ORACLE_WEB` | NPM forward target | +| `MEV_DEFI_ORACLE_UPSTREAM_PORT` | `80` | NPM forward port | + +## Verification + +```bash +curl -fsS -H 'Host: mev.defi-oracle.io' "http://${IP_INFO_DEFI_ORACLE_WEB:-192.168.11.218}/health" +# expect: mev-gui-healthy + +curl -fsSI "https://mev.defi-oracle.io/" | head -5 +``` + +After TLS is live, open **https://mev.defi-oracle.io/intel** for in-app framing docs; **/login** if `MEV_ADMIN_API_KEY` is enabled on the API. + +## Related + +- [INFO_DEFI_ORACLE_IO_DEPLOYMENT.md](INFO_DEFI_ORACLE_IO_DEPLOYMENT.md) +- [MEV_Bot/README.md](../../MEV_Bot/README.md) +- [MEV_Bot/mev-platform/docs/RUNBOOK_AND_DEPLOYMENT.md](../../MEV_Bot/mev-platform/docs/RUNBOOK_AND_DEPLOYMENT.md) diff --git a/docs/04-configuration/README.md b/docs/04-configuration/README.md index 10dacfd7..96486290 100644 --- a/docs/04-configuration/README.md +++ b/docs/04-configuration/README.md @@ -34,6 +34,7 @@ This directory contains setup and configuration guides. - **[GITEA_PLATFORM_AND_UPGRADE_RUNBOOK.md](GITEA_PLATFORM_AND_UPGRADE_RUNBOOK.md)** — Gitea as org forge (VMID 104), NPMplus, binary upgrades, `scripts/operator/upgrade-gitea-lxc.sh` - **[GITEA_IP_CONFLICT_CHECK.md](GITEA_IP_CONFLICT_CHECK.md)** — Gitea IP (.31) vs other VMIDs; `IP_GITEA_INFRA` notes - **[INFO_DEFI_ORACLE_IO_DEPLOYMENT.md](INFO_DEFI_ORACLE_IO_DEPLOYMENT.md)** - **`info.defi-oracle.io`** Chain 138 hub SPA (incl. `/governance`, `/ecosystem`, `/documentation`, `/solacenet`, `/disclosures`, agents): VMID **2410**, nginx **`/token-aggregation/`** proxy, `sync-info-defi-oracle-to-vmid2400.sh`, NPMplus, Cloudflare DNS (`set-info-defi-oracle-dns-to-vmid2400-tunnel.sh`), `purge-info-defi-oracle-cache.sh`, `pnpm run verify:info-defi-oracle-public`, CI `info-defi-oracle-138.yml` + `verify-info-defi-oracle-public.yml`, optional `pnpm run audit:info-defi-oracle-site` +- **[MEV_CONTROL_DEFI_ORACLE_IO_DEPLOYMENT.md](MEV_CONTROL_DEFI_ORACLE_IO_DEPLOYMENT.md)** — **`mev.defi-oracle.io`** MEV Control GUI (`MEV_Bot/mev-platform/gui`): `sync-mev-control-gui-defi-oracle.sh`, nginx `/api` → mev-admin-api, NPMplus + `set-mev-defi-oracle-dns.sh` - **[SOLACENET_PUBLIC_HUB.md](SOLACENET_PUBLIC_HUB.md)** — Public **SolaceNet** page (`/solacenet`) on the info hub plus `dbis_core/docs/solacenet/` markdown map - **[PROXMOX_LOAD_BALANCING_RUNBOOK.md](PROXMOX_LOAD_BALANCING_RUNBOOK.md)** - Balance Proxmox load: migrate containers from r630-01 to r630-02/ml110; candidates, script, cluster vs backup/restore - **[PROXMOX_ADD_THIRD_FOURTH_R630_DECISION.md](PROXMOX_ADD_THIRD_FOURTH_R630_DECISION.md)** - Add 3rd/4th R630 before migration? r630-03/04 status, HA/Ceph (3–4 nodes), order of operations diff --git a/docs/MASTER_INDEX.md b/docs/MASTER_INDEX.md index 6d8f195b..fdde1130 100644 --- a/docs/MASTER_INDEX.md +++ b/docs/MASTER_INDEX.md @@ -16,7 +16,7 @@ | **Agent / IDE instructions** | [AGENTS.md](../AGENTS.md) (repo root) | | **Local green-path tests** | Root `pnpm test` → [`scripts/verify/run-repo-green-test-path.sh`](../scripts/verify/run-repo-green-test-path.sh) | | **Git submodule hygiene + explorer remotes** | [00-meta/SUBMODULE_HYGIENE.md](00-meta/SUBMODULE_HYGIENE.md) — detached HEAD, push order, Gitea/GitHub, `submodules-clean.sh` | -| **MEV intel (taxonomy, MVP matrix, diagrams + GUI Intel tab)** | [../MEV_Bot/docs/framing/README.md](../MEV_Bot/docs/framing/README.md) — canonical framing in `MEV_Bot`; specs in [MEV_Bot/specs/README.md](../MEV_Bot/specs/README.md); standalone `mev-searcher-pipeline-reference` repo deprecated | +| **MEV intel + public GUI (`mev.defi-oracle.io`)** | Framing: [../MEV_Bot/docs/framing/README.md](../MEV_Bot/docs/framing/README.md); deploy: [04-configuration/MEV_CONTROL_DEFI_ORACLE_IO_DEPLOYMENT.md](04-configuration/MEV_CONTROL_DEFI_ORACLE_IO_DEPLOYMENT.md); specs: [../MEV_Bot/specs/README.md](../MEV_Bot/specs/README.md) | | **What to do next** | [00-meta/NEXT_STEPS_INDEX.md](00-meta/NEXT_STEPS_INDEX.md) — ordered actions, by audience, execution plan | | **Live verification evidence (dated)** | [00-meta/LIVE_VERIFICATION_LOG_2026-03-30.md](00-meta/LIVE_VERIFICATION_LOG_2026-03-30.md) | | **Your personal checklist** | [00-meta/NEXT_STEPS_FOR_YOU.md](00-meta/NEXT_STEPS_FOR_YOU.md) | diff --git a/scripts/cloudflare/set-mev-defi-oracle-dns.sh b/scripts/cloudflare/set-mev-defi-oracle-dns.sh new file mode 100755 index 00000000..4341cac2 --- /dev/null +++ b/scripts/cloudflare/set-mev-defi-oracle-dns.sh @@ -0,0 +1,151 @@ +#!/usr/bin/env bash +# Publish mev.defi-oracle.io and www.mev.defi-oracle.io (same edge mode as info.defi-oracle.io). +# Requires CLOUDFLARE_ZONE_ID_DEFI_ORACLE_IO and Cloudflare credentials (see set-info-defi-oracle-dns-to-vmid2400-tunnel.sh). + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +cd "$PROJECT_ROOT" + +source "$PROJECT_ROOT/config/ip-addresses.conf" 2>/dev/null || true +if [[ -f "$PROJECT_ROOT/.env" ]]; then + set +u + source "$PROJECT_ROOT/.env" 2>/dev/null || true + set -u +fi + +TUNNEL_ID="${VMID2400_TUNNEL_ID:-${CLOUDFLARE_TUNNEL_ID_VMID2400:-26138c21-db00-4a02-95db-ec75c07bda5b}}" +ZONE_ID="${CLOUDFLARE_ZONE_ID_DEFI_ORACLE_IO:-}" +TUNNEL_TARGET="${TUNNEL_ID}.cfargotunnel.com" +EDGE_MODE="${MEV_DEFI_ORACLE_EDGE_MODE:-${INFO_DEFI_ORACLE_EDGE_MODE:-auto}}" +PUBLIC_EDGE_IP="${MEV_DEFI_ORACLE_PUBLIC_IP:-${INFO_DEFI_ORACLE_PUBLIC_IP:-${PUBLIC_IP:-}}}" +ACCOUNT_ID="${CLOUDFLARE_ACCOUNT_ID:-}" +HOSTS=( "mev.defi-oracle.io" "www.mev.defi-oracle.io" ) + +if [[ -z "$ZONE_ID" ]]; then + echo "CLOUDFLARE_ZONE_ID_DEFI_ORACLE_IO is required." >&2 + exit 1 +fi + +cf_api() { + local method="$1" + local endpoint="$2" + local data="${3:-}" + local url="https://api.cloudflare.com/client/v4/zones/${ZONE_ID}${endpoint}" + + if [[ -n "${CLOUDFLARE_API_TOKEN:-}" ]]; then + if [[ -n "$data" ]]; then + curl -s -X "$method" "$url" -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" -H "Content-Type: application/json" --data "$data" + else + curl -s -X "$method" "$url" -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" -H "Content-Type: application/json" + fi + elif [[ -n "${CLOUDFLARE_EMAIL:-}" && -n "${CLOUDFLARE_API_KEY:-}" ]]; then + if [[ -n "$data" ]]; then + curl -s -X "$method" "$url" -H "X-Auth-Email: $CLOUDFLARE_EMAIL" -H "X-Auth-Key: $CLOUDFLARE_API_KEY" -H "Content-Type: application/json" --data "$data" + else + curl -s -X "$method" "$url" -H "X-Auth-Email: $CLOUDFLARE_EMAIL" -H "X-Auth-Key: $CLOUDFLARE_API_KEY" -H "Content-Type: application/json" + fi + else + echo "Cloudflare credentials are required." >&2 + exit 1 + fi +} + +cf_global_api() { + local method="$1" + local url="$2" + if [[ -n "${CLOUDFLARE_API_TOKEN:-}" ]]; then + curl -s -X "$method" "$url" -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" -H "Content-Type: application/json" + elif [[ -n "${CLOUDFLARE_EMAIL:-}" && -n "${CLOUDFLARE_API_KEY:-}" ]]; then + curl -s -X "$method" "$url" -H "X-Auth-Email: $CLOUDFLARE_EMAIL" -H "X-Auth-Key: $CLOUDFLARE_API_KEY" -H "Content-Type: application/json" + else + echo "Cloudflare credentials are required." >&2 + exit 1 + fi +} + +resolve_account_id() { + if [[ -n "$ACCOUNT_ID" ]]; then + printf '%s\n' "$ACCOUNT_ID" + return 0 + fi + local response + response="$(cf_global_api GET "https://api.cloudflare.com/client/v4/accounts")" + ACCOUNT_ID="$(printf '%s\n' "$response" | jq -r '.result[0].id // empty')" + printf '%s\n' "$ACCOUNT_ID" +} + +tunnel_exists() { + local account_id + account_id="$(resolve_account_id)" + [[ -z "$account_id" ]] && return 1 + local response + response="$(cf_global_api GET "https://api.cloudflare.com/client/v4/accounts/${account_id}/cfd_tunnel/${TUNNEL_ID}")" + printf '%s\n' "$response" | jq -e '.success == true' >/dev/null 2>&1 +} + +delete_conflicting_records() { + local name="$1" + local existing + existing="$(cf_api GET "/dns_records?name=${name}")" + printf '%s\n' "$existing" | jq -r '.result[]? | "\(.id) \(.type)"' | while read -r record_id record_type; do + [[ -z "$record_id" ]] && continue + if [[ "$record_type" == "A" || "$record_type" == "AAAA" || "$record_type" == "CNAME" ]]; then + cf_api DELETE "/dns_records/${record_id}" >/dev/null + fi + done +} + +create_cname() { + local name="$1" + local payload + payload="$(jq -n --arg name "$name" --arg content "$TUNNEL_TARGET" '{type:"CNAME",name:$name,content:$content,proxied:true,ttl:1}')" + cf_api POST "/dns_records" "$payload" | jq -e '.success == true' >/dev/null +} + +create_a_record() { + local name="$1" + local payload + payload="$(jq -n --arg name "$name" --arg content "$PUBLIC_EDGE_IP" '{type:"A",name:$name,content:$content,proxied:true,ttl:1}')" + cf_api POST "/dns_records" "$payload" | jq -e '.success == true' >/dev/null +} + +TARGET_MODE="$EDGE_MODE" +if [[ "$TARGET_MODE" == "auto" ]]; then + if tunnel_exists; then + TARGET_MODE="tunnel" + else + TARGET_MODE="public_ip" + fi +fi + +case "$TARGET_MODE" in + tunnel) + echo "Publishing mev.defi-oracle.io hostnames to tunnel ${TUNNEL_TARGET}" + ;; + public_ip|npmplus) + echo "Publishing mev.defi-oracle.io hostnames to public edge ${PUBLIC_EDGE_IP}" + ;; + *) + echo "Unsupported EDGE_MODE=${TARGET_MODE}" >&2 + exit 1 + ;; +esac + +if [[ "$TARGET_MODE" != "tunnel" ]] && [[ -z "$PUBLIC_EDGE_IP" ]]; then + echo "Set PUBLIC_IP (or MEV_DEFI_ORACLE_PUBLIC_IP / INFO_DEFI_ORACLE_PUBLIC_IP) for A-record mode." >&2 + exit 1 +fi + +for host in "${HOSTS[@]}"; do + delete_conflicting_records "$host" + if [[ "$TARGET_MODE" == "tunnel" ]]; then + create_cname "$host" + else + create_a_record "$host" + fi + echo " - ${host}" +done + +echo "Done." diff --git a/scripts/deployment/provision-info-defi-oracle-web-lxc.sh b/scripts/deployment/provision-info-defi-oracle-web-lxc.sh index 6ebb681d..74aad2e9 100755 --- a/scripts/deployment/provision-info-defi-oracle-web-lxc.sh +++ b/scripts/deployment/provision-info-defi-oracle-web-lxc.sh @@ -83,4 +83,5 @@ ssh $SSH_OPTS "root@${PROXMOX_HOST}" "pct exec ${VMID} -- bash -lc \"ln -sf '${S echo "" echo "✅ Dedicated web LXC ${VMID} ready at ${IP_CT}:80" echo " Next: bash scripts/deployment/sync-info-defi-oracle-to-vmid2400.sh" +echo " MEV Control: bash scripts/deployment/sync-mev-control-gui-defi-oracle.sh (mev.defi-oracle.io; set MEV_ADMIN_API_HOST)" echo " NPM: point info.defi-oracle.io → http://${IP_CT}:80 (fleet: update-npmplus-proxy-hosts-api.sh)" diff --git a/scripts/deployment/sync-mev-control-gui-defi-oracle.sh b/scripts/deployment/sync-mev-control-gui-defi-oracle.sh new file mode 100755 index 00000000..b9dc82eb --- /dev/null +++ b/scripts/deployment/sync-mev-control-gui-defi-oracle.sh @@ -0,0 +1,113 @@ +#!/usr/bin/env bash +# Build MEV Control (Vite GUI from MEV_Bot) and sync to the defi-oracle.io nginx LXC. +# +# Default: VMID 2410 (same host as info.defi-oracle.io), /var/www/mev.defi-oracle.io/html +# Nginx proxies /api/* to mev-admin-api (override MEV_ADMIN_API_HOST / MEV_ADMIN_API_PORT). +# +# Usage (repo root, LAN + SSH to Proxmox): +# bash scripts/deployment/sync-mev-control-gui-defi-oracle.sh [--dry-run] +# Then: +# bash scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh +# bash scripts/cloudflare/set-mev-defi-oracle-dns.sh # if using Cloudflare zone defi-oracle.io +# +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +cd "$PROJECT_ROOT" + +source "$PROJECT_ROOT/config/ip-addresses.conf" 2>/dev/null || true +if [[ -f "$PROJECT_ROOT/.env" ]]; then + set +u + # shellcheck source=/dev/null + source "$PROJECT_ROOT/.env" 2>/dev/null || true + set -u +fi +source "$PROJECT_ROOT/config/ip-addresses.conf" 2>/dev/null || true + +PROXMOX_HOST="${PROXMOX_HOST:-${PROXMOX_HOST_R630_01:-192.168.11.11}}" +VMID="${MEV_DEFI_ORACLE_WEB_VMID:-${INFO_DEFI_ORACLE_WEB_VMID:-2410}}" +APP_DIR="${MEV_DEFI_ORACLE_WEB_ROOT:-/var/www/mev.defi-oracle.io/html}" +SITE_AVAILABLE="${MEV_DEFI_ORACLE_NGINX_SITE:-/etc/nginx/sites-available/mev-defi-oracle}" +NGINX_TEMPLATE="${PROJECT_ROOT}/config/nginx/mev-defi-oracle-io.site.conf.template" +MEV_ADMIN_API_HOST="${MEV_ADMIN_API_HOST:-192.168.11.11}" +MEV_ADMIN_API_PORT="${MEV_ADMIN_API_PORT:-9090}" +MEV_ADMIN_UPSTREAM="http://${MEV_ADMIN_API_HOST}:${MEV_ADMIN_API_PORT}" + +GUI_DIR="${PROJECT_ROOT}/MEV_Bot/mev-platform/gui" +SSH_OPTS="-o BatchMode=yes -o ConnectTimeout=15 -o StrictHostKeyChecking=accept-new" +DRY_RUN=false +[[ "${1:-}" == "--dry-run" ]] && DRY_RUN=true + +if [[ ! -d "$GUI_DIR" ]]; then + echo "ERROR: Missing $GUI_DIR (init MEV_Bot submodule: git submodule update --init MEV_Bot)" >&2 + exit 1 +fi +if [[ ! -f "$NGINX_TEMPLATE" ]]; then + echo "ERROR: Missing $NGINX_TEMPLATE" >&2 + exit 1 +fi + +echo "=== Sync MEV Control GUI → mev.defi-oracle.io (VMID ${VMID}) ===" +echo "Proxmox: ${PROXMOX_HOST} Admin API upstream: ${MEV_ADMIN_UPSTREAM}" + +TMP_NGINX="$(mktemp)" +TMP_TGZ="${TMPDIR:-/tmp}/mev-gui-sync-$$.tgz" +REMOTE_TGZ="/tmp/mev-gui-sync-$$.tgz" +REMOTE_NGINX="/tmp/mev-defi-oracle-site-$$.conf" +CT_TGZ="/tmp/mev-gui-sync.tgz" +cleanup() { rm -f "$TMP_NGINX" "$TMP_TGZ"; } +trap cleanup EXIT +sed "s@__MEV_ADMIN_API_UPSTREAM__@${MEV_ADMIN_UPSTREAM}@g" "$NGINX_TEMPLATE" >"$TMP_NGINX" + +if $DRY_RUN; then + echo "[DRY-RUN] npm ci + npm run build in $GUI_DIR" + echo "[DRY-RUN] tar dist -> tgz, scp, pct push ${VMID}, nginx site -> ${SITE_AVAILABLE}" + exit 0 +fi + +if ! command -v npm >/dev/null 2>&1; then + echo "ERROR: npm is required to build the GUI." >&2 + exit 1 +fi + +echo "Building GUI..." +(cd "$GUI_DIR" && npm ci && npm run build) + +echo "Packaging dist/..." +tar czf "$TMP_TGZ" -C "$GUI_DIR/dist" . + +echo "Copying to Proxmox host ${PROXMOX_HOST}..." +scp $SSH_OPTS "$TMP_TGZ" "root@${PROXMOX_HOST}:${REMOTE_TGZ}" +scp $SSH_OPTS "$TMP_NGINX" "root@${PROXMOX_HOST}:${REMOTE_NGINX}" + +echo "Installing into VMID ${VMID}..." +ssh $SSH_OPTS "root@${PROXMOX_HOST}" bash -s "$VMID" "$REMOTE_TGZ" "$CT_TGZ" "$APP_DIR" "$SITE_AVAILABLE" "$REMOTE_NGINX" <<'REMOTE' +set -euo pipefail +VMID="$1" +REMOTE_TGZ="$2" +CT_TGZ="$3" +APP_DIR="$4" +SITE_FILE="$5" +REMOTE_NGINX="$6" + +pct push "$VMID" "$REMOTE_TGZ" "$CT_TGZ" +rm -f "$REMOTE_TGZ" + +pct exec "$VMID" -- bash -lc "mkdir -p '$APP_DIR' && rm -rf '${APP_DIR}'/* && tar xzf '$CT_TGZ' -C '$APP_DIR' && rm -f '$CT_TGZ'" + +pct push "$VMID" "$REMOTE_NGINX" "$SITE_FILE" +rm -f "$REMOTE_NGINX" + +pct exec "$VMID" -- bash -lc "mkdir -p /var/www/mev.defi-oracle.io/html && ln -sf '$SITE_FILE' /etc/nginx/sites-enabled/mev-defi-oracle" +pct exec "$VMID" -- nginx -t +pct exec "$VMID" -- systemctl reload nginx +sleep 1 +pct exec "$VMID" -- curl -fsS -H 'Host: mev.defi-oracle.io' "http://127.0.0.1/health" | grep -q mev-gui-healthy +REMOTE + +echo "" +echo "✅ GUI synced. Next:" +echo " NPM: bash scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh" +echo " DNS: bash scripts/cloudflare/set-mev-defi-oracle-dns.sh" +echo " Ensure mev-admin-api listens on ${MEV_ADMIN_UPSTREAM} (reachable from CT ${VMID})." diff --git a/scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh b/scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh index ffc75baa..e0fcce73 100755 --- a/scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh +++ b/scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh @@ -403,6 +403,11 @@ INFO_DEFI_ORACLE_UPSTREAM_IP="${INFO_DEFI_ORACLE_UPSTREAM_IP:-${IP_INFO_DEFI_ORA INFO_DEFI_ORACLE_UPSTREAM_PORT="${INFO_DEFI_ORACLE_UPSTREAM_PORT:-80}" update_proxy_host "info.defi-oracle.io" "http://${INFO_DEFI_ORACLE_UPSTREAM_IP}:${INFO_DEFI_ORACLE_UPSTREAM_PORT}" false false && updated_count=$((updated_count + 1)) || { add_proxy_host "info.defi-oracle.io" "${INFO_DEFI_ORACLE_UPSTREAM_IP}" "${INFO_DEFI_ORACLE_UPSTREAM_PORT}" false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1)) update_proxy_host "www.info.defi-oracle.io" "http://${INFO_DEFI_ORACLE_UPSTREAM_IP}:${INFO_DEFI_ORACLE_UPSTREAM_PORT}" false false "https://info.defi-oracle.io" && updated_count=$((updated_count + 1)) || { add_proxy_host "www.info.defi-oracle.io" "${INFO_DEFI_ORACLE_UPSTREAM_IP}" "${INFO_DEFI_ORACLE_UPSTREAM_PORT}" false false "https://info.defi-oracle.io" && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1)) +# mev.defi-oracle.io — MEV Control GUI on same nginx LXC as info (default VMID 2410); nginx proxies /api to MEV_ADMIN_API_*. +MEV_DEFI_ORACLE_UPSTREAM_IP="${MEV_DEFI_ORACLE_UPSTREAM_IP:-${IP_INFO_DEFI_ORACLE_WEB:-192.168.11.218}}" +MEV_DEFI_ORACLE_UPSTREAM_PORT="${MEV_DEFI_ORACLE_UPSTREAM_PORT:-80}" +update_proxy_host "mev.defi-oracle.io" "http://${MEV_DEFI_ORACLE_UPSTREAM_IP}:${MEV_DEFI_ORACLE_UPSTREAM_PORT}" false false && updated_count=$((updated_count + 1)) || { add_proxy_host "mev.defi-oracle.io" "${MEV_DEFI_ORACLE_UPSTREAM_IP}" "${MEV_DEFI_ORACLE_UPSTREAM_PORT}" false false && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1)) +update_proxy_host "www.mev.defi-oracle.io" "http://${MEV_DEFI_ORACLE_UPSTREAM_IP}:${MEV_DEFI_ORACLE_UPSTREAM_PORT}" false false "https://mev.defi-oracle.io" && updated_count=$((updated_count + 1)) || { add_proxy_host "www.mev.defi-oracle.io" "${MEV_DEFI_ORACLE_UPSTREAM_IP}" "${MEV_DEFI_ORACLE_UPSTREAM_PORT}" false false "https://mev.defi-oracle.io" && updated_count=$((updated_count + 1)); } || failed_count=$((failed_count + 1)) # Optional relay health publication for off-LAN monitors like Promod. # Set CCIP_RELAY_MAINNET_CW_PUBLIC_HOST in .env to publish the mainnet-cw health # endpoint through NPMplus without exposing a raw UDM Pro port-forward.