From e34fac45d43c9f35eec85d9b98130351ecc868bd Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Mon, 28 Sep 2026 18:44:39 +0000 Subject: [PATCH] Cloud container: DEV_SERVER=off runs a tenant without the Plugin Studio dev server No Vite, no pull loop and no Rudder: /cdn, PocketBase, the admin router and the sign-in stay, and / redirects to /cdn/. The default stays on, so running containers are unchanged. Off without OIDC_ISSUER refuses to start, because /pb and /admin would then have nothing in front of them. Replayed onto development after the public Studio mode landed. Off together with ACCESS=public is refused too, because the public Studio is the dev server itself. PULL_INTERVAL=0 still means no pulls, whatever DEV_SERVER says. The setting is in the cloud README's table. --- deployment/cloud/README.md | 1 + deployment/cloud/admin.mjs | 2 ++ deployment/cloud/entry.sh | 34 +++++++++++++++++++++++++++++----- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/deployment/cloud/README.md b/deployment/cloud/README.md index 26c53713a..38cd4425e 100644 --- a/deployment/cloud/README.md +++ b/deployment/cloud/README.md @@ -25,6 +25,7 @@ and the hot-reload websocket. Only people in the allowed groups get in. | `PULL_INTERVAL` | no (`15`) | seconds between pulls; `0` never pulls (for a checkout mounted from your machine: a pull resets it hard) | | `GIT_TOKEN` | private repos | a read token for the clone and pulls | | `PORT` | no (`5173`) | the port the container serves on | +| `DEV_SERVER` | no (`on`) | `off` runs a tenant without the Plugin Studio dev server: no Vite, no pulls, no Rudder; `/` redirects to `/cdn/`. Needs the sign-in (`OIDC_ISSUER`); refused with `ACCESS=public` | | `HMR_CLIENT_PORT`, `HMR_PROTOCOL` | behind HTTPS | `443` and `wss`, so browsers reach the hot-reload websocket | ## Where it runs diff --git a/deployment/cloud/admin.mjs b/deployment/cloud/admin.mjs index 204bfeed9..dd1db9c67 100644 --- a/deployment/cloud/admin.mjs +++ b/deployment/cloud/admin.mjs @@ -165,6 +165,8 @@ Bun.serve({ async fetch(req) { const url = new URL(req.url) const p = url.pathname + // DEV_SERVER=off: there is no Plugin Studio at /, so send people to the public build. + if (p === '/' && env.DEV_SERVER === 'off') return Response.redirect(new URL('/cdn/', url), 302) if (p.startsWith('/cdn/')) { const f = normalize(join(CDN, decodeURIComponent(p.slice(5)))) if (!f.startsWith(CDN)) return text('bad path', 400) diff --git a/deployment/cloud/entry.sh b/deployment/cloud/entry.sh index 4debc036c..2b0aaef05 100755 --- a/deployment/cloud/entry.sh +++ b/deployment/cloud/entry.sh @@ -3,16 +3,28 @@ # 1. install, 2. pull BRANCH every PULL_INTERVAL s (Vite hot-reloads what changed; 0 = never pull), # 3. serve: Vite alone; behind an OIDC sign-in when OIDC_ISSUER is set; or, with ACCESS=public, the Studio # open to everyone and the admin parts behind ADMIN_USER/ADMIN_PASSWORD. +# DEV_SERVER=off (default on) runs a tenant WITHOUT the Plugin Studio dev server: no Vite, no pull loop, no +# Rudder. It keeps /cdn, PocketBase, the admin router and the sign-in, and / redirects to /cdn/. Vite is +# most of the container's memory, so an app-user tenant is a fraction of a building one. set -u cd /app/repo -BRANCH="${BRANCH:-main}"; PORT="${PORT:-5173}" +BRANCH="${BRANCH:-main}"; PORT="${PORT:-5173}"; DEV_SERVER="${DEV_SERVER:-on}" +case "$DEV_SERVER" in on|off) ;; *) echo "refusing to start: DEV_SERVER must be on or off (got '$DEV_SERVER')" >&2; exit 1;; esac +if [ "$DEV_SERVER" = off ] && [ "${ACCESS:-}" = public ]; then + echo "refusing to start: DEV_SERVER=off and ACCESS=public don't combine (the public Studio IS the dev server)" >&2 + exit 1 +fi +echo "[dev-server] $DEV_SERVER" echo "$(date -u +%FT%TZ) START at $(git rev-parse --short HEAD)" | tee -a /tmp/pull.log bun install --frozen-lockfile || bun install # PULL_INTERVAL=0: never pull, never reset. For a checkout mounted from someone's machine, where the -# loop's `git reset --hard` would wipe their work. +# loop's `git reset --hard` would wipe their work. The loop only feeds Vite, so DEV_SERVER=off has none. +# An if-block (not `[ ] && ( ) &`), so no background job ends at once and trips the `wait -n` at the bottom. if [ "${PULL_INTERVAL:-15}" = 0 ]; then echo "$(date -u +%FT%TZ) PULL_INTERVAL=0: not following $BRANCH; the checkout is left as it is" | tee -a /tmp/pull.log +elif [ "$DEV_SERVER" = off ]; then + echo "$(date -u +%FT%TZ) DEV_SERVER=off: no dev server, so no pull loop" | tee -a /tmp/pull.log else ( while true; do @@ -66,7 +78,9 @@ fi # in the BACKGROUND so the site serves at once: until it finishes, /api/rudder answers "starting", then # the cloud Vite config restarts the dev server once, which starts the engine. /api/rudder stays behind # the sign-in (it is not a public route). About 1 GB resident. -if [ "${RUDDER_ENGINE:-0}" = 1 ]; then +if [ "${RUDDER_ENGINE:-0}" = 1 ] && [ "$DEV_SERVER" = off ]; then + echo "[rudder] skipped: it runs inside the dev server, and DEV_SERVER=off" +elif [ "${RUDDER_ENGINE:-0}" = 1 ]; then if [ -z "${RUDDER_HOME:-}" ]; then if ls /data/rudder/models/*.gguf >/dev/null 2>&1; then RUDDER_HOME=/data/rudder; else RUDDER_HOME=/opt/rudder; fi fi @@ -92,6 +106,11 @@ if [ "${RUDDER_ENGINE:-0}" = 1 ]; then disown fi +if [ -z "${OIDC_ISSUER:-}" ] && [ "$DEV_SERVER" = off ]; then + # Without oauth2-proxy nothing stands in front of /pb and /admin (their admin check trusts its headers). + echo "refusing to start: DEV_SERVER=off serves /pb and /admin, which need the sign-in; set OIDC_ISSUER" >&2 + exit 1 +fi if [ -z "${OIDC_ISSUER:-}" ] && [ "${ACCESS:-}" != public ]; then # Open, like a laptop: no sign-in, no backend. export VITE_HOST=0.0.0.0 VITE_PORT="$PORT" @@ -176,7 +195,12 @@ if [ -n "${PB_OIDC_CLIENT_SECRET:-}" ]; then fi fi -VITE_HOST=127.0.0.1 VITE_PORT=5174 bun x vite --config "$CONFIG" & +if [ "$DEV_SERVER" = on ]; then + VITE_HOST=127.0.0.1 VITE_PORT=5174 bun x vite --config "$CONFIG" & + ROOT=http://127.0.0.1:5174/ +else + ROOT=http://127.0.0.1:5175/ # the admin router: / redirects to /cdn/ +fi oauth2-proxy \ --provider=oidc \ --oidc-issuer-url="$OIDC_ISSUER" \ @@ -188,7 +212,7 @@ oauth2-proxy \ "${ALLOW[@]}" \ --email-domain='*' \ --provider-display-name="${OIDC_DISPLAY_NAME:-your identity provider}" \ - --upstream=http://127.0.0.1:5174/ \ + --upstream="$ROOT" \ --upstream=http://127.0.0.1:5175/cdn/ \ --upstream=http://127.0.0.1:5175/api-prod/ \ --upstream=http://127.0.0.1:5175/pb/ \