backend/api/rest/server.go:
- NewServer() now delegates to loadJWTSecret(), which:
- Rejects JWT_SECRET < 32 bytes (log.Fatal).
- Requires JWT_SECRET when APP_ENV=production or GO_ENV=production.
- Generates a 32-byte crypto/rand ephemeral secret in dev only.
- Treats rand.Read failure as fatal (removes the prior time-based
fallback that was deterministic and forgeable).
- Default Content-Security-Policy rewritten:
- Drops 'unsafe-inline' and 'unsafe-eval'.
- Drops private CIDRs (192.168.11.221:854[5|6]).
- Adds frame-ancestors 'none', base-uri 'self', form-action 'self'.
- CSP_HEADER is required in production; fatal if unset there.
backend/api/rest/server_security_test.go (new):
- Covers the three loadJWTSecret() paths (valid, whitespace-trimmed,
ephemeral in dev).
- Covers isProductionEnv() across APP_ENV / GO_ENV combinations.
- Asserts defaultDevCSP contains no unsafe directives or private CIDRs
and includes the frame-ancestors / base-uri / form-action directives.
scripts/*.sh:
- Removed '***REDACTED-LEGACY-PW***' default value from SSH_PASSWORD / NEW_PASSWORD in
7 helper scripts. Each script now fails with exit 2 and points to
docs/SECURITY.md if the password isn't supplied via env or argv.
EXECUTE_DEPLOYMENT.sh, EXECUTE_NOW.sh:
- Replaced hardcoded DB_PASSWORD='***REDACTED-LEGACY-PW***' with a ':?' guard that
aborts with a clear error if DB_PASSWORD (and, for EXECUTE_DEPLOYMENT,
RPC_URL) is not exported. Other env vars keep sensible non-secret
defaults via ${VAR:-default}.
README.md:
- Removed the hardcoded Database Password / RPC URL lines. Replaced with
an env-variable reference table pointing at docs/SECURITY.md and
docs/DATABASE_CONNECTION_GUIDE.md.
docs/DEPLOYMENT.md:
- Replaced 'PASSWORD: SSH password (default: ***REDACTED-LEGACY-PW***)' with a
required-no-default contract and a link to docs/SECURITY.md.
docs/SECURITY.md (new):
- Full secret inventory keyed to the env variable name and the file that
consumes it.
- Five-step rotation checklist covering the Postgres role, the Proxmox
VM SSH password, JWT_SECRET, vendor API keys, and a gitleaks-based
history audit.
- Explicit note that merging secret-scrub PRs does NOT invalidate
already-leaked credentials; rotation is the operator's responsibility.
Verification:
- go build ./... + go vet ./... pass clean.
- Targeted tests (LoadJWTSecret*, IsProduction*, DefaultDevCSP*) pass.
Advances completion criterion 2 (Secrets & config hardened). Residual
leakage from START_HERE.md / LETSENCRYPT_CONFIGURATION_GUIDE.md is
handled by PR #2 (doc consolidation), which deletes those files.
118 lines
4.3 KiB
Markdown
118 lines
4.3 KiB
Markdown
# Deployment Guide
|
|
|
|
## Production Deployment
|
|
|
|
### Prerequisites
|
|
|
|
- SSH access to production server (192.168.11.140)
|
|
- Password for root user
|
|
- `sshpass` installed (or use SSH keys)
|
|
|
|
### Quick Deploy
|
|
|
|
For the current frontend, use the Next standalone deploy path:
|
|
|
|
```bash
|
|
# From explorer-monorepo root
|
|
./scripts/deploy-next-frontend-to-vmid5000.sh
|
|
```
|
|
|
|
This builds `frontend/`, uploads the standalone bundle, installs the
|
|
`solacescanscout-frontend.service` unit, and starts the frontend on
|
|
`127.0.0.1:3000` inside VMID 5000.
|
|
|
|
Nginx should keep the existing explorer API routes and proxy `/` plus `/_next/`
|
|
to the frontend service. Use
|
|
[nginx-next-frontend-proxy.conf](/home/intlc/projects/proxmox/explorer-monorepo/deployment/common/nginx-next-frontend-proxy.conf)
|
|
inside the explorer server block after `/api`, `/api/config/*`, `/explorer-api/*`,
|
|
`/token-aggregation/api/v1/*`, `/snap/`, and `/health`.
|
|
|
|
### Legacy Static Deploy
|
|
|
|
The historical static SPA deploy path is deprecated. The old scripts
|
|
`./scripts/deploy.sh` and `./scripts/deploy-frontend-to-vmid5000.sh` now fail
|
|
fast with a deprecation message and intentionally point operators back to the
|
|
canonical Next.js deploy path.
|
|
|
|
### Manual Deploy
|
|
|
|
```bash
|
|
# Canonical Next deployment:
|
|
./scripts/deploy-next-frontend-to-vmid5000.sh
|
|
|
|
# Compatibility assets only:
|
|
# frontend/public/index.html
|
|
# frontend/public/explorer-spa.js
|
|
```
|
|
|
|
### Environment Variables
|
|
|
|
The canonical Next deployment script uses its own VM/host defaults and deploy
|
|
workflow. Prefer reviewing `scripts/deploy-next-frontend-to-vmid5000.sh`
|
|
directly instead of relying on the older static script env contract below.
|
|
|
|
Historical static-script environment variables:
|
|
|
|
- `IP`: Production server IP (required; no default)
|
|
- `DOMAIN`: Domain name (required; no default)
|
|
- `SSH_PASSWORD`: SSH password (required; no default; previous
|
|
hardcoded default has been removed — see
|
|
[SECURITY.md](SECURITY.md))
|
|
|
|
These applied to the deprecated static deploy script and are no longer the
|
|
recommended operator interface.
|
|
|
|
## Mission-control and Track 4 runtime wiring
|
|
|
|
If you are deploying the Go explorer API with the mission-control additions enabled, set these backend env vars as well:
|
|
|
|
- `RPC_URL` - Chain 138 RPC for Track 1 and mission-control status/SSE data
|
|
- `TOKEN_AGGREGATION_BASE_URL` - used by `GET /api/v1/mission-control/liquidity/token/{address}/pools`
|
|
- `BLOCKSCOUT_INTERNAL_URL` - used by `GET /api/v1/mission-control/bridge/trace`
|
|
- `EXPLORER_PUBLIC_BASE` - public base URL returned in bridge trace links
|
|
- `CCIP_RELAY_HEALTH_URL` - optional relay probe URL, for example `http://192.168.11.11:9860/healthz`
|
|
- `CCIP_RELAY_HEALTH_URLS` - optional comma-separated named relay probes, for example `mainnet=http://192.168.11.11:9860/healthz,bsc=http://192.168.11.11:9861/healthz,avax=http://192.168.11.11:9862/healthz`
|
|
- `MISSION_CONTROL_CCIP_JSON` - optional JSON-file fallback for relay health snapshots
|
|
- `OPERATOR_SCRIPTS_ROOT` - root directory for Track 4 script execution
|
|
- `OPERATOR_SCRIPT_ALLOWLIST` - comma-separated allowlist for `POST /api/v1/track4/operator/run-script`
|
|
- `OPERATOR_SCRIPT_TIMEOUT_SEC` - optional per-script timeout in seconds
|
|
|
|
For nginx, include [nginx-mission-control-sse.conf](/home/intlc/projects/proxmox/explorer-monorepo/deployment/common/nginx-mission-control-sse.conf) inside the same server block that proxies `/explorer-api/`, and update the `proxy_pass` target if your Go API is not listening on `127.0.0.1:8080`.
|
|
|
|
### Quick verification
|
|
|
|
```bash
|
|
curl -N https://explorer.d-bis.org/explorer-api/v1/mission-control/stream
|
|
curl "https://explorer.d-bis.org/explorer-api/v1/mission-control/bridge/trace?tx=0x..."
|
|
curl "https://explorer.d-bis.org/explorer-api/v1/mission-control/liquidity/token/0x93E66202A11B1772E55407B32B44e5Cd8eda7f22/pools"
|
|
# Optional relay probe from the explorer host:
|
|
curl http://192.168.11.11:9860/healthz
|
|
```
|
|
|
|
## Rollback
|
|
|
|
If deployment fails, rollback to previous version:
|
|
|
|
```bash
|
|
ssh root@192.168.11.140
|
|
ls -1dt /opt/solacescanscout/frontend/releases/* | head
|
|
```
|
|
|
|
For the Next standalone path, restart the previous release by repointing
|
|
`/opt/solacescanscout/frontend/current` to the prior release and restarting
|
|
`solacescanscout-frontend`.
|
|
|
|
## Testing
|
|
|
|
After deployment, test the explorer:
|
|
|
|
```bash
|
|
./scripts/test.sh
|
|
```
|
|
|
|
Or manually:
|
|
|
|
```bash
|
|
curl -k -I https://explorer.d-bis.org/
|
|
```
|