summaryrefslogtreecommitdiff
path: root/scripts/systemd/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/systemd/README.md')
-rw-r--r--scripts/systemd/README.md72
1 files changed, 72 insertions, 0 deletions
diff --git a/scripts/systemd/README.md b/scripts/systemd/README.md
new file mode 100644
index 0000000..7e3fdaa
--- /dev/null
+++ b/scripts/systemd/README.md
@@ -0,0 +1,72 @@
+# fund-lab production deployment (systemd --user)
+
+Loopback-only services behind the existing `cloudflared` tunnel. The tunnel
+ingress already maps `fund.somhairle.bid -> http://127.0.0.1:8098`.
+
+## Topology
+
+| Component | Listen | Unit / mechanism |
+|-----------|--------|------------------|
+| API (`FundLab.Api.dll`, Release publish) | `127.0.0.1:5080` | `fundlab-api.service` |
+| Web gateway (nginx: static `dist/` + `/api`,`/health` proxy) | `127.0.0.1:5176` (frontend) and `127.0.0.1:8098` (tunnel origin) | `fundlab-gateway.service` |
+| PostgreSQL 16 (real data dir, docker named volume) | `127.0.0.1:55435` | docker container `fundlab-pg` (`--restart unless-stopped`) |
+
+Public request path: `cloudflared` -> `127.0.0.1:8098` (gateway) -> static
+`src/FundLab.Web/dist` for `/`, and reverse-proxy to the API for `/api/*` and
+`/health`.
+
+### Port note (necessary deviation)
+
+The tunnel origin is `8098`, but a single origin must serve **both** the
+frontend (`/`) and the API (`/api`, `/health`). The API therefore listens on
+`127.0.0.1:5080` and the nginx gateway owns `8098` (and `5176`). `curl
+http://127.0.0.1:8098/health` still returns the API health payload because the
+gateway proxies it.
+
+## Files
+
+- `fundlab-api.service`, `fundlab-gateway.service` — systemd user units.
+- `nginx-fundlab.conf` — gateway config (high ports, unprivileged user; temp
+ dirs under `var/fund-lab/`).
+- Runtime env/secrets: `.env.deploy` at the repo root (git-ignored via
+ `.env.*`; contains `FUND_LAB_DATABASE_URL`, `FUND_LAB_AUTH_TOKEN`,
+ `ASPNETCORE_URLS`, `FUND_LAB_AKSHARE_PYTHON`). Never commit it.
+- Logs: `var/fund-lab/{api,gateway,nginx-*.log}` (git-ignored via `var/`).
+
+## Build
+
+```sh
+# API (Release; FS3511 warning suppressed only for publish)
+dotnet publish src/FundLab.Api/FundLab.Api.fsproj -c Release \
+ -p:TreatWarningsAsErrors=false -o src/FundLab.Api/publish
+
+# Frontend -> src/FundLab.Web/dist
+cd src/FundLab.Web
+PATH="$PWD/../../.tools/node-v22.23.2/bin:$PATH" npm run build
+```
+
+## Install / run
+
+```sh
+systemctl --user link "$PWD/scripts/systemd/fundlab-api.service"
+systemctl --user link "$PWD/scripts/systemd/fundlab-gateway.service"
+systemctl --user daemon-reload
+systemctl --user enable --now fundlab-api.service fundlab-gateway.service
+```
+
+`loginctl` linger is already enabled for this user, so the units start on boot.
+
+## Verify
+
+```sh
+curl -sS http://127.0.0.1:5080/health
+curl -sS http://127.0.0.1:5176/ # frontend HTML
+curl -sS http://127.0.0.1:8098/health
+curl -sS https://fund.somhairle.bid/health
+curl -sS https://fund.somhairle.bid/ # frontend HTML (not Somhairle's Dream)
+curl -sS -H "Authorization: Bearer $FUND_LAB_AUTH_TOKEN" \
+ https://fund.somhairle.bid/api/portfolio/summary
+```
+
+Auth is a static Bearer token (`FUND_LAB_AUTH_TOKEN`); there is no `/login`
+endpoint. `/health` is anonymous; everything under `/api` requires the token.