web: shared MCMS cache + systemd/clone-to-run deploy + NPM docs
Caching (reduce MCMS API load with multiple operators): - web/cache.js: in-memory TTL cache with single-flight, keyed by MCMS host. Concurrent identical bulk reads collapse into ONE upstream fetch; everyone on the same MCMS shares the snapshot. - Wired into the bulk reads only (ONU/OLT config+state lists, controllers, firmware). Per-ONU read-modify-write and the FEC pre-flight stay live. - Writes (delete / per-ONU + bulk upgrade / flood change / firmware upload) invalidate the affected datasets for that host, so changes show on the next load instead of waiting out the TTL. - PFW_CACHE_TTL_SECONDS (default 60, 0 disables). Authenticated _cacheStats / _cacheClear endpoints for ops. Deploy (Debian 13 LXC, clone-to-run) in web/deploy/: - pon-fleet-web.service (runs as unprivileged ponfw, hardened, repo read-only, no disk writes), pon-fleet-web.env.example, update.sh (git pull + npm install --omit=dev + restart; uses install not ci since package-lock.json is gitignored). - README: full LXC setup, Nginx Proxy Manager proxy-host + access-list notes. Streams already send X-Accel-Buffering: no so NPM/nginx don't buffer the NDJSON progress. Verified: node --check; cache unit-tested (single-flight, TTL hit/expiry, fresh, invalidate, key isolation, disable — 9/9); server boots and reports the cache TTL; _cacheStats gated to logged-in sessions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
96b0264179
commit
6ee1d37a79
7 changed files with 309 additions and 35 deletions
|
|
@ -42,38 +42,96 @@ cookie jar) per session.
|
|||
| Var | Default | Meaning |
|
||||
|---|---|---|
|
||||
| `PORT` | `8080` | listen port |
|
||||
| `HOST` | `127.0.0.1` | bind address — keep on localhost behind a proxy |
|
||||
| `HOST` | `127.0.0.1` | bind address — `0.0.0.0` if the proxy is on another host |
|
||||
| `PFW_CACHE_TTL_SECONDS` | `60` | shared upstream cache TTL; `0` disables (see Caching) |
|
||||
| `PFW_IDLE_MINUTES` | `30` | idle-session expiry (logs the MCMS session out) |
|
||||
| `PFW_SECURE_COOKIE` | off | force the `Secure` cookie flag (else inferred from `X-Forwarded-Proto: https`) |
|
||||
| `PFW_VERBOSE` | off | verbose MCMS request logging (very noisy with many users) |
|
||||
|
||||
## Reverse proxy
|
||||
## Caching (fewer MCMS requests)
|
||||
|
||||
Terminate TLS at the proxy and forward to `127.0.0.1:8080`. **Disable
|
||||
response buffering** so the NDJSON progress streams (bulk delete, FEC
|
||||
pre-flight, flood change, …) arrive live.
|
||||
The server keeps a small in-memory cache so multiple operators don't each
|
||||
hammer MCMS. The heavy bulk **reads** — ONU configs, ONU states, OLT states,
|
||||
OLT configs, controller configs, firmware inventory — are cached with a TTL
|
||||
(`PFW_CACHE_TTL_SECONDS`, default 60s) and **keyed by MCMS host**, so:
|
||||
|
||||
Caddy:
|
||||
- Everyone pointed at the same MCMS shares one snapshot. Ten operators
|
||||
loading the fleet within a minute trigger **one** upstream fetch, not ten.
|
||||
- A **single-flight** guard means even simultaneous cold loads collapse into
|
||||
one upstream request (the rest await it).
|
||||
- Different MCMS hosts never share, and the dashboard's light path reuses the
|
||||
same OLT-STATE snapshot the fleet view already fetched.
|
||||
|
||||
```
|
||||
mcms-tools.example.net {
|
||||
reverse_proxy 127.0.0.1:8080 {
|
||||
flush_interval -1 # don't buffer streamed responses
|
||||
}
|
||||
}
|
||||
What is **not** cached (always live, by design):
|
||||
|
||||
- Per-ONU `getOnuConfig` used right before a firmware PUT (read-modify-write
|
||||
must see the current bank state).
|
||||
- The FEC pre-flight and verify per-ONU `getOnuState` (operators want the
|
||||
reading at decision time).
|
||||
|
||||
**Writes invalidate** the affected datasets for that MCMS host, so a delete /
|
||||
firmware push / flood-mode change is reflected on the next load instead of
|
||||
waiting out the TTL. Tune the TTL up to cut MCMS load further, or set
|
||||
`PFW_CACHE_TTL_SECONDS=0` to disable caching entirely. `POST /api/_cacheStats`
|
||||
(authenticated) shows hits/misses/coalesced; `POST /api/_cacheClear` drops the
|
||||
caller's MCMS-host snapshots.
|
||||
|
||||
## Deploy on a Debian 13 LXC (clone-to-run)
|
||||
|
||||
Files in `web/deploy/`: a systemd unit, an env template, and `update.sh`.
|
||||
|
||||
```bash
|
||||
# --- as root on the LXC, once ---
|
||||
apt update && apt install -y nodejs npm git # Node 18+; or use NodeSource
|
||||
adduser --system --group --no-create-home ponfw
|
||||
|
||||
git clone ssh://forgejo@int.git.vanvikinternet.no/Svorka/ponfw.git /opt/ponfw
|
||||
cd /opt/ponfw
|
||||
npm install --omit=dev --no-audit --no-fund # installs tough-cookie, skips Electron
|
||||
|
||||
install -m 0644 web/deploy/pon-fleet-web.service /etc/systemd/system/
|
||||
install -m 0640 web/deploy/pon-fleet-web.env.example /etc/pon-fleet-web.env
|
||||
$EDITOR /etc/pon-fleet-web.env # set HOST / PFW_SECURE_COOKIE etc.
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now pon-fleet-web
|
||||
systemctl status pon-fleet-web
|
||||
journalctl -u pon-fleet-web -f # logs
|
||||
```
|
||||
|
||||
nginx:
|
||||
The repo lives at `/opt/ponfw` (root-owned, read-only to the service); the
|
||||
service runs as the unprivileged `ponfw` user and writes nothing to disk.
|
||||
|
||||
```nginx
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8080;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_buffering off; # stream NDJSON progress live
|
||||
proxy_read_timeout 300s; # bulk ops can run a while
|
||||
}
|
||||
**To update:** just re-pull and restart —
|
||||
|
||||
```bash
|
||||
sudo /opt/ponfw/web/deploy/update.sh # git pull + npm install + restart
|
||||
```
|
||||
|
||||
## Behind Nginx Proxy Manager
|
||||
|
||||
Point an NPM **Proxy Host** at the server:
|
||||
|
||||
- Forward Hostname/IP: the LXC's address · Forward Port: `8080`
|
||||
- Scheme: `http` (NPM terminates TLS; request an SSL cert in NPM)
|
||||
- Enable **Block Common Exploits**; add your **Access List** for auth/IP
|
||||
allow-listing (this is your access control — the app itself has no user
|
||||
directory beyond MCMS login).
|
||||
- **Websockets Support** on is harmless. The progress streams (bulk delete,
|
||||
FEC pre-flight, flood change) are plain NDJSON over HTTP and already send
|
||||
`X-Accel-Buffering: no`, which nginx/NPM honour, so they stream live with
|
||||
no extra config. If you ever see progress arrive only at the end, add to
|
||||
the host's **Advanced** tab:
|
||||
|
||||
```nginx
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 300s;
|
||||
```
|
||||
|
||||
If NPM runs on a different host than this LXC, set `HOST=0.0.0.0` in
|
||||
`/etc/pon-fleet-web.env` and restrict reachability to the NPM host via the
|
||||
LXC firewall + the NPM access list.
|
||||
|
||||
## Security notes
|
||||
|
||||
- The server holds each logged-in user's **live MCMS session cookie in
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue