fix(deploy): split ingress to oolon, expose api on nikola interface

The per-site nginx ingress for rob.tn lives on oolon (the host the
external router forwards 443 traffic to), not on nikola. Adjust the
topology so:

- web (static ui + nginx) → oolon.hanzalova.internal
- api binds 0.0.0.0:42424 on nikola.kosherinata.internal so oolon
  can reverse-proxy across the WG mesh
- new firewalld service moments-api opens 42424 in the default zone
  on nikola
- oolon labels port 42424 http_port_t so httpd_t may name_connect
  outbound to it (httpd_can_network_connect was already set)
- nginx ssl_certificate switched to oolon's host cert; upstream
  rewritten to nikola.kosherinata.internal:42424

Plaintext between oolon and nikola for now — the WG mesh provides
the encryption layer and the data is already public. Documented
the deferral so a future move to per-hop mTLS is obvious.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-03 20:20:07 +03:00
parent 110b523fd0
commit 52b7d0be9b
6 changed files with 52 additions and 22 deletions

View File

@@ -47,15 +47,17 @@ Migrations live in `crates/moments-data/migrations/` and run automatically on wo
Topology:
| Component | Host | Notes |
| --------- | --------------------------------- | --------------------------------------------- |
| api | `nikola.kosherinata.internal` | binds `127.0.0.1:42424`, fronted by local nginx |
| worker | `frootmig.kosherinata.internal` | no listening port; pollers only |
| web | `nikola.kosherinata.internal` | static `ui/dist/` under `/var/www/moments` |
| db | `magrathea.kosherinata.internal` | postgres mTLS, passwordless |
| Component | Host | Notes |
| --------- | --------------------------------- | ------------------------------------------------------------------ |
| api | `nikola.kosherinata.internal` | binds `0.0.0.0:42424`; firewalld service `moments-api` |
| worker | `frootmig.kosherinata.internal` | no listening port; pollers only |
| web | `oolon.hanzalova.internal` | per-site nginx ingress for rob.tn; `/api/*` → nikola across the WG |
| db | `magrathea.kosherinata.internal` | postgres mTLS, passwordless |
Postgres roles `moments_rw` and `moments_ro` must exist on the primary, with `pg_ident.conf` mappings in place for `nikola.kosherinata.internal``moments_ro` and `frootmig.kosherinata.internal``moments_rw`. See `asset/sql/bootstrap-moments.sql` and `asset/postgres/ident.conf.tmpl`.
Inter-host traffic over the WG mesh: oolon's nginx connects to `http://nikola.kosherinata.internal:42424` in plaintext. The mesh provides the encryption layer; per-hop TLS for an internal HTTP read-only API on already-public data is deferred. If that changes, swap the api binary to rustls + the host cert pair, and update the nginx upstream to `https://`.
Secrets resolved by `deploy.sh` via `pass`:
- `github.com/grenade/admin-token` — GitHub PAT for events + search APIs (worker only).