Files
curriculum-project-hub/hub/deploy/README.md
T

63 lines
2.6 KiB
Markdown

# Hub service installation
The initial production target is a supported Linux host with systemd,
PostgreSQL, Node.js 20 or newer, `pg_isready`, `runuser`, `setpriv`, bubblewrap,
`socat` and `cph`. The Hub runs as the dedicated non-login `cph-hub` user; do not
create or run the unit as root.
Build or deploy the Hub under `/srv/curriculum-project-hub`, then run:
```sh
sudo BASE=/srv/curriculum-project-hub \
HUB_DIR=/srv/curriculum-project-hub/hub \
bash /srv/curriculum-project-hub/hub/deploy/install_service.sh
```
On a clean host the first invocation creates
`/srv/curriculum-project-hub/.secrets/platform.env` with every supported
production key and exits with status 78. Fill every required blank, set
`CPH_BIN` to an executable compatible `cph`, keep the file mode at `0600`, and
run the same command again. No systemd unit is installed until configuration,
paths, Node, bubblewrap, `socat`, `cph --version`, PostgreSQL connectivity and directory
ownership all pass preflight.
The deployment path also runs `npm run audit:production` from the locked clean
install before building or restarting the service. A current high or critical
production advisory therefore blocks deployment instead of becoming a warning
buried in CI output.
An existing service account is accepted only when its primary group, home and
non-login shell match the requested configuration and it has no supplementary
groups. After provisioning, the installer executes path-access, built Hub,
Prisma, an authenticated database query, `cph`, `socat` and bubblewrap namespace probes
as that account with `no_new_privs` set. Inaccessible parents, UID-specific
database/network policy, or a host that forbids unprivileged user namespaces
therefore fail before unit installation.
The default persistent layout is deliberately outside every source/release
tree:
```text
/var/lib/cph-hub/home
/var/lib/cph-hub/state
/var/lib/cph-hub/workspaces
/var/cache/cph-hub
```
Custom paths are supported with `SERVICE_HOME`, `STATE_DIR`, `CACHE_DIR` and
`WORKSPACE_ROOT`, but all must be absolute. The installer rejects any persistent
path that is equal to, above, or below `BASE`; this keeps rsync, release
switching, rollback and pruning unable to traverse customer workspaces. Set the
same custom workspace in `HUB_PROJECT_WORKSPACE_ROOT` inside `platform.env`.
After a successful installation:
```sh
sudo systemctl start cph-hub.service
sudo systemctl status cph-hub.service
```
`HOST` and `PORT` in `platform.env` are passed to the real HTTP listener. The
default `127.0.0.1:8788` expects a local TLS reverse proxy; the public OAuth URL
must be an HTTPS `HUB_PUBLIC_BASE_URL`.