docs: production on its own Linux VM, natively (Gitea issue 37)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-27 15:15:18 -06:00
co-authored by Claude Opus 5.5
parent b2f3213e16
commit d9aab10987
4 changed files with 9 additions and 5 deletions
+3 -3
View File
@@ -19,7 +19,7 @@ Both stacks run from the same image as separate compose projects.
| Stack | Compose project | DNS name | Network alias on npm_default | VISUAL |
|---|---|---|---|---|
| Test | `packetstation-test` | `packetstation-test.pescoinc.biz` | `packetstation-test-app` | DEV: `vsql.pesco.com\DEV` / `PESCOINCDEV` |
| Production | `packetstation` | `packetstation.pescoinc.biz` | `packetstation-app` | `vsql` / `PESCOINC`, set explicitly (planned, phase 10) |
| Production | `packetstation` | `packetstation.pescoinc.biz` | `packetstation-app` | `vsql` / `PESCOINC`, set explicitly (planned, phase 10; moves to its own VM, see below) |
- The app publishes no port. It joins `npm_default` as an external network with an explicit alias per stack (`APP_ALIAS`). Plain service names would collide, since both stacks share that network.
- PostgreSQL stays on each stack's own internal `backend` network, never on `npm_default`.
@@ -59,7 +59,7 @@ The PESCO CA chain is mounted into the containers once and referenced by `LDAP_C
## Env files
One folder per stack. The test stack: `/home/spencerm/packetstation/test/`, like the other compose stacks on docker-1 (decided 2026-10-18, Gitea issue 38). It holds `stack.env`, `secrets/`, `ca/pesco-ca.pem` and `backups/`, and its `stack.env` sets `ENV_FILE`, `SECRETS_DIR`, `CA_BUNDLE_FILE` and `BACKUP_DIR` to those paths. The compose files run from the checkout in `/home/spencerm/packetstation/repo/deploy`. The production stack: `/etc/packetstation/prod/` until issue 38 says otherwise. Each folder holds `stack.env` (settings only, no secrets) and `secrets/`. The env file sets `PROJECT_NAME`, `SECRETS_DIR` and `APP_ALIAS`, which the compose files require. `.env.example` in the repo lists every setting.
One folder per stack. The test stack: `/home/spencerm/packetstation/test/`, like the other compose stacks on docker-1 (decided 2026-10-18, Gitea issue 38). It holds `stack.env`, `secrets/`, `ca/pesco-ca.pem` and `backups/`, and its `stack.env` sets `ENV_FILE`, `SECRETS_DIR`, `CA_BUNDLE_FILE` and `BACKUP_DIR` to those paths. The compose files run from the checkout in `/home/spencerm/packetstation/repo/deploy`. Production no longer runs on docker-1: on 2026-10-27 Spencer decided it runs natively on its own Linux VM, without Docker (Gitea issue 37). The production lines in this file describe the old compose plan and are rewritten for the VM in phase 10. Each folder holds `stack.env` (settings only, no secrets) and `secrets/`. The env file sets `PROJECT_NAME`, `SECRETS_DIR` and `APP_ALIAS`, which the compose files require. `.env.example` in the repo lists every setting.
Key settings:
@@ -175,7 +175,7 @@ The test stack on docker-1 lives under /home/spencerm/packetstation/test (stack.
## Known issue: Docker subnet pool on docker-1 (found 2026-10-17)
Docker's default address pool on docker-1 holds fifteen /16 bridge networks (172.17.0.0 to 172.31.0.0). Each compose stack takes one or two (Packet Station takes two: backend and egress), the Gitea runner takes one per job, and the CI e2e stack needs two more. With the test stack up the pool ran out and every e2e job failed within seconds with "all predefined address pools have been fully subnetted". Idle networks of stopped stacks were removed to make room. The lasting fix is a larger pool in /etc/docker/daemon.json, for example `{"default-address-pools":[{"base":"10.200.0.0/16","size":24}]}`, which needs sudo and a Docker restart (a short outage for every stack on the host), or trimming unused compose projects. When the production stack joins, count the networks first: `docker network ls --filter driver=bridge | wc -l`.
Docker's default address pool on docker-1 holds fifteen /16 bridge networks (172.17.0.0 to 172.31.0.0). Each compose stack takes one or two (Packet Station takes two: backend and egress), the Gitea runner takes one per job, and the CI e2e stack needs two more. With the test stack up the pool ran out and every e2e job failed within seconds with "all predefined address pools have been fully subnetted". Idle networks of stopped stacks were removed to make room. The lasting fix is a larger pool in /etc/docker/daemon.json, for example `{"default-address-pools":[{"base":"10.200.0.0/16","size":24}]}`, which needs sudo and a Docker restart (a short outage for every stack on the host), or trimming unused compose projects. Production will not join docker-1 (it moves to its own VM, Gitea issue 37), so the pool only has to fit the test stack, the runner and the CI e2e stack. Count the networks before adding any other stack: `docker network ls --filter driver=bridge | wc -l`.
## Known issue: vsql serves a weak self-signed certificate (found 2026-10-18)
+3 -1
View File
@@ -120,7 +120,7 @@ Each phase ends with passing tests, docs updated (README, CHANGELOG, SECURITY.md
### Phase 10: Regression bench, hardening, go-live (medium)
- Rewrite the 38 scenarios against the new UI with synthetic fixtures; run in Gitea Actions against compose.ci.yml. Policy matrix, merge rules and packet-rule tests already run from phase 2 and 3.
- CSP final pass, dependency scan, build-version banner and reload, DEPLOY.md with the NPM proxy host settings, SECURITY.md rewritten with the ID table, GO-LIVE.md (date, boundary, groups, tablets, URL, M: retirement as read-only archive), PAPER-FALLBACK.md, incident notes.
- Production compose with explicit VISUAL_SERVER and VISUAL_DATABASE; first start is Spencer's approval.
- Production on its own Linux VM, natively, with no Docker (Spencer, 2026-10-27, Gitea issue 37; see "Host layout"). The app and the worker run as systemd services from a venv built from the same `server/requirements.txt` and `server/requirements-pesco.txt` pins as the image, with PostgreSQL 16, ODBC Driver 18 and the PESCO CA installed on the VM. Settings from an env file, secrets as root-owned files read through the same `*_PASSWORD_FILE` settings, VISUAL_SERVER and VISUAL_DATABASE set explicitly; first start is Spencer's approval. NPM on docker-1 proxies `packetstation.pescoinc.biz` to the VM over the LAN. Backups, the doctor and the restore are rewritten for the VM (no `docker exec`). DEPLOY.md gets a production section for the VM; the compose files stay for test and CI.
- Archive location (Gitea issue 7, Spencer 2026-10-27). Spencer creates an NFS share on the QNAP and mounts it on docker-1 (root, steps in DEPLOY.md), with write access for uid 10001. Compose bind-mounts it into the app and the worker at a fixed root, `ARCHIVE_ROOT` (unset turns the feature off). The Admin page gets a File locations section with one setting for now, the archive folder, as a path under `ARCHIVE_ROOT`. The server refuses a path that leaves the root (`..`, absolute paths elsewhere, symlinks out). "Check" writes a probe file, reads it back, removes it and shows the result, and saving runs the same check first. The setting change and every check are audited. `doctor` runs the check too. What is written to the archive and when (for example the sealed data book, its documents and a manifest at filing) is decided on issue 7 before it is built; until then the setting and the check exist and nothing is copied.
- Closes: O3, O4; S4 is IT's pentest, deferred.
@@ -303,3 +303,5 @@ From phase 9 (2026-10-21), for Seth or Spencer to veto:
## Host layout on docker-1
OPS2 (Gitea issue 38): the test stack's files stay under `/home/spencerm/packetstation/test`, like the other compose stacks on docker-1 (gitea, npm, pesco-ncr and the rest live under `/home/spencerm`). Decided by Spencer (IT) on 2026-10-18. The move to `/etc/packetstation/test` is dropped. Whether the production stack follows the same layout is asked on issue 38. Until it is answered, DEPLOY.md keeps `/etc/packetstation/prod`.
Production host (Gitea issue 37): decided by Spencer on 2026-10-27. Production runs on its own Linux VM as native services, not in Docker and not on docker-1. The test stack and CI stay on docker-1 as they are. This replaces the production half of OPS2: the production folder question on issue 38 no longer applies, and the VM's file layout is set in phase 10. The docker-1 address pool (OPS1) now only has to fit the test stack, the Gitea runner and the CI e2e stack. Still open on issue 37: the VM's name and address, its OS (Debian 12 matches the image), who builds it, and how NPM reaches it (HTTP on the LAN or TLS to the VM).