doxa-maps/deployment/cloud/README.md
Doxa Maps 11348632df
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Update from source b03c8d4b
2026-09-27 23:21:43 +00:00

4.8 KiB

Run dx-maps in the cloud: one shared dev server for a team

One container runs the Plugin Studio with hot reload for everyone. It clones the repo, pulls the branch every few seconds, and Vite hot-reloads whatever changed, so every change an agent lands on main shows up in everyone's browser within seconds. No rebuild; bun run build is only for publishing.

With no OIDC settings it runs open, like bun run dev on a laptop. With OIDC settings a sign-in page ("Sign in with your provider") sits in front of everything: the Studio, every map, and the hot-reload websocket. Only people in the allowed groups get in.

Deploy

  1. Build the image from Dockerfile. It's a small bootstrap (Bun, git, and the oauth2-proxy binary); at start it clones the repo and runs entry.sh from it, so the recipe updates with the repo. Paste it into any container host (Coolify's "Dockerfile" build pack, Railway, docker build).
  2. Set the environment below and expose the container's PORT over HTTPS.
  3. Give it about 2 GB of memory (Vite plus the dependency install).
Variable Needed Meaning
REPO_URL yes the dx-maps git URL to clone
BRANCH no (main) the branch to follow
PULL_INTERVAL no (15) seconds between pulls
GIT_TOKEN private repos a read token for the clone and pulls
PORT no (5173) the port the container serves on
HMR_CLIENT_PORT, HMR_PROTOCOL behind HTTPS 443 and wss, so browsers reach the hot-reload websocket

Sign-in (optional)

Set all of these to turn the gate on. Register a confidential client at your OIDC provider with the redirect URL https://<your-host>/oauth2/callback; PKCE (S256) is used as well.

Variable Meaning
OIDC_ISSUER the provider's issuer URL (its /.well-known/openid-configuration must resolve)
OIDC_CLIENT_ID, OIDC_CLIENT_SECRET the registered client
OIDC_REDIRECT_URL https://<your-host>/oauth2/callback
OIDC_ALLOWED_GROUPS comma-separated groups allowed in; required (the server refuses to start without it, because many providers allow open sign-up)
OIDC_DISPLAY_NAME the name on the button, e.g. "Sign in with Acme"
OIDC_GROUPS_CLAIM the token claim holding groups (default groups)
OIDC_COOKIE_SECRET 32 characters; keeps people signed in across restarts (random if unset)

Secrets reach oauth2-proxy through its environment, never its command line.

Backend and production (v1, experimental)

With the sign-in on, the container also runs PocketBase and can publish a production build:

Route Who What
/ signed-in the dev server (Plugin Studio, hot reload)
/pb/ signed-in (its /_/ dashboard: OIDC_ADMIN_GROUPS only) PocketBase dev
/api-prod/api/ public PocketBase prod's API; its dashboard is never exposed
/cdn/dx-maps/ public the last published build: manifest.json at a stable URL, CORS open for embeds
POST /admin/build · GET /admin/status OIDC_ADMIN_GROUPS only build and publish the pulled commit

A build runs one at a time (a second gets 409), on a snapshot of the pulled commit, with Node's heap capped. It removes everything in public-exclusions.txt before building, checks the output again afterwards, and refuses to publish if anything excluded is still there. Only then does it swap the new build in.

Variable Meaning
OIDC_ADMIN_GROUPS comma-separated groups allowed to build and to open PocketBase's dashboard
PB_SUPERUSER_EMAIL, PB_SUPERUSER_PASSWORD PocketBase's superuser, set on start in both instances
PUBLIC_API_BASE the public API URL written into the build's runtime-config.js (e.g. https://<host>/api-prod)
BUILD_MAX_OLD_SPACE_MB Node heap cap for a build (default 1536)
RUDDER_ENGINE 1 runs Rudder's voice-to-text engine here, fed by the browser's microphone (about 1 GB more; its runtime and model, ~742 MB, are baked into the image at /opt/rudder, and /data/rudder wins when it holds a model). The site serves at once; Rudder shows "starting" until its engine is built, then the dev server restarts once to start it. Give the container at least 2 vCPUs, or transcription falls behind speech
RUDDER_ALLOW_HOST every public host the engine accepts, comma-separated (it refuses others, so list each domain the container answers on); defaults to Coolify's COOLIFY_FQDN, else the host in OIDC_REDIRECT_URL

Mount a persistent volume at /data (PocketBase data and published builds). Memory measured on the running container: about 0.45 GB idle, up to about 1.5 GB more during a build, so give it 2.5 GB (3.5 GB with RUDDER_ENGINE=1).