From 425d92a1376a546f0befa09f2abe5d9730ae3907 Mon Sep 17 00:00:00 2001 From: William Mantly Date: Tue, 14 Jul 2026 00:53:17 -0400 Subject: [PATCH] setup.sh: register SSO + proxy hostnames as Host records in the proxy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The proxy routes every hostname it serves purely off a Host record (ops/nginx_conf/proxy.conf has no default/self route — targetinfo.lua does a Redis lookup per request, full stop). Nothing created these for the SSO's own UI or the proxy's own management UI, so on a fresh install https:// and https:// both 404 despite setup.sh's summary claiming they're "fronted by the proxy under TLS". Add a step after the proxy is healthy that runs a short script inside the proxy container calling its Host model directly (no HTTP API call, since no authenticated session exists yet at this point in the run): - -> sso-manager:3001 (the Docker service) - -> 127.0.0.1:3000 (the proxy's own management app) Both created with sso_enabled: false — each app already gates its own login, and SSO-gating the SSO's own login page would be circular. Idempotent: skips a host that already exists. --- README.md | 7 +++++- docs/architecture.md | 12 ++++++++++ docs/quickstart.md | 5 +++- setup.sh | 56 +++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 75 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 426c1e1..b6f3f97 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,12 @@ operator-owned and `setup.env` is ignored. - registers the proxy as an OIDC client in the SSO and **writes the generated client id + secret back into `./config/proxy-secrets.js`**. 4. Builds + starts the proxy container, waits for it to be healthy. -5. Prints your first admin login + the public URLs. +5. Registers `` and `` as Host records in the proxy + (directly via its Host model, inside the proxy container) — the proxy + routes every hostname it serves off a Host record, including its own + management UI and the SSO's UI, so without this step those two URLs + would 404. Idempotent; skips a host that already exists. +6. Prints your first admin login + the public URLs. ### Configuration — `./config/` (no `.env` files) diff --git a/docs/architecture.md b/docs/architecture.md index 4cb1685..1e80100 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -104,6 +104,18 @@ inputs from the bind-mounted `./config/sso-secrets.js` + `./config/proxy-secrets 6. **Build + start the proxy**, wait for `/health`. The proxy entrypoint symlinks `./config/proxy-secrets.js` to `/app/conf/secrets.js`, so `@simpleworkjs/conf` (≥1.1.0) reads the OAuth creds + LDAP bind creds from the file. +7. **Register `` and `` as Host records in the proxy** — + `setup.sh` runs a short script inside the proxy container that calls its + Host model directly (`Host.create({host, ip, targetPort, ...})`), rather + than the proxy's own HTTP API, since no authenticated session exists yet at + this point in the run. The proxy routes every hostname purely off a Host + record (`ops/nginx_conf/proxy.conf` has no default/self route), so without + this step neither URL resolves to anything. `` targets + `sso-manager:3001` (the Docker service), `` targets + `127.0.0.1:3000` (the proxy's own management app, same container). Both + are created with `sso_enabled: false` — each app already gates its own + login, and SSO-gating the SSO's own login page would be circular. Skips a + host that already exists, so re-running `setup.sh` is a no-op here. `setup.sh` then prints the first-admin login + the public URLs. diff --git a/docs/quickstart.md b/docs/quickstart.md index dca9539..8cfe453 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -89,7 +89,10 @@ What happens: service account, your first admin, and the proxy's OAuth client, and writes the generated client id + secret into `./config/proxy-secrets.js`. 4. Builds + starts **proxy**, waits for `/health`. -5. Prints your first-admin login + the public URLs. +5. Registers `` and `` as Host records in the proxy — + every hostname the proxy serves, including its own UI and the SSO's, + needs one of these or it 404s. Idempotent. +6. Prints your first-admin login + the public URLs. The first run builds two Docker images (a few minutes). Subsequent runs are fast. diff --git a/setup.sh b/setup.sh index 0854c7a..40edf01 100755 --- a/setup.sh +++ b/setup.sh @@ -12,7 +12,8 @@ # state before rebuild, (re)starts the SSO Manager, runs the bootstrap (which # converges the LDAP service account / first admin / OAuth client to the ./config # values and writes the generated OAuth client creds into proxy-secrets.js), -# then starts the proxy. +# then starts the proxy and registers the SSO's + proxy's own hostnames as +# Host records in it (otherwise the proxy has no route for either). # # What it does, in order: # 1. Update the git submodules to the latest of their tracked remote branch @@ -35,7 +36,11 @@ # writes the OAuth client creds into ./config/proxy-secrets.js; prints # CLIENT_ID / CLIENT_SECRET / ALREADY_CONFIGURED on stdout. # 6. docker compose up -d --build proxy; wait for /health. -# 7. Print the first-admin login + the public URLs. +# 7. Register and as Host records in the proxy (via +# `docker compose exec proxy node`, calling the proxy's Host model +# directly) so the proxy actually routes those hostnames somewhere — +# nothing else creates them. Idempotent; skips a host that already exists. +# 8. Print the first-admin login + the public URLs. # # Requires: git, docker + docker compose (v1 standalone or v2 plugin). @@ -548,7 +553,52 @@ for i in $(seq 1 60); do sleep 2 done -# ── 7. Summary ─────────────────────────────────────────────────────────────── +# ── 7. Register the SSO + proxy UIs as Host records in the proxy ────────────── +# The proxy routes EVERY hostname it serves — including its own management UI +# and the SSO's UI — off a Host record (ops/nginx_conf/proxy.conf has no +# default/self route; targetinfo.lua does a lookup for every request, full +# stop). Nothing else creates these two, so without this step https:// +# and https:// 404 on first run. sso_enabled is left false on both: +# each app gates its own login already, and SSO-gating the SSO's own login page +# would be circular. Idempotent — skips a host that already exists. +info "Registering ${SSO_HOST} and ${PROXY_HOST} with the proxy..." +HOSTS_OUT=$("${COMPOSE[@]}" exec -T proxy node < ' + ip + ':' + targetPort); + } +} + +(async () => { + try { + await ensureHost($(js_str "$SSO_HOST"), 'sso-manager', 3001); + await ensureHost($(js_str "$PROXY_HOST"), '127.0.0.1', 3000); + process.exit(0); + } catch (error) { + console.error('ERROR', error.message); + process.exit(1); + } +})(); +NODEEOF +) || die "Registering hosts with the proxy failed:\n${HOSTS_OUT}" +echo "$HOSTS_OUT" | sed 's/^/[setup] /' + +# ── 8. Summary ─────────────────────────────────────────────────────────────── echo info "\033[1;32mDone. Your SSO + proxy stack is up.\033[0m" echo