Skip to content

Setting Up the Server

jann edited this page Sep 6, 2026 · 5 revisions

Setting Up the Server

The server is the web UI plus everything behind it: the Test Repository, reports and session replay, schedules, notifications and MCP. Run it on one machine for your team.

The stack

plum server start runs a Docker Compose stack:

Service Port What it is
postgres (internal) PostgreSQL 16, data in a named Docker volume
backend 3001 Express + Socket.io API. Runs prisma migrate deploy on boot, then starts.
frontend 3002 The SvelteKit UI, built and served by @sveltejs/adapter-node.

All three use restart: unless-stopped, so the server comes back after a reboot. The database is never touched by plum server commands — only the containers restart.

plum server start

The wizard asks:

  1. Where are you setting up Plum? Local machine or Production / server.
  2. Use the default ports (3001 / 3002)? If yes, anything already on those ports is stopped first (the database is unaffected). If no, you pick custom ports.
  3. (Production only) Public URL or IP of the backend, and of the UI.

Settings are saved to .plum-server.json in the instance folder, so a later plum server start skips the questions.

The API and the UI cannot share an origin

The API mounts its routers at bare paths (/auth, /reports, …) and the socket path is /socket.io. A single origin serving both has no way to tell them apart. plum server start refuses an api/ui pair with the same origin, or with mismatched schemes. Keep them on separate ports (the default) or separate hostnames.

Related commands

Command Effect
plum server start Configure (first run) and start the stack
plum server restart Rebuild images and restart, no prompts. Run this after pulling backend or schema changes.
plum server stop Stop the containers. Data is preserved.
plum server reconfig Re-enter the settings without starting

Flags for scripted setup: --backend-port, --frontend-port, --api-url, --ui-url. --framework also still works, but only as the pre-selected default offered when creating a later project (Settings → Project); it has no effect on your first project, which is chosen on the setup page itself.

Production behind a reverse proxy

Point two hostnames (or a hostname + a port) at the two containers, e.g.

  • plum.example.com → frontend:3002
  • api.plum.example.com → backend:3001

and answer the production URL prompts with those. A minimal Nginx block per host:

location / {
    proxy_pass http://127.0.0.1:3002;   # or :3001 for the API host
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";   # needed on the API host for socket.io
}

The socket transport falls back to long-polling, so live logs still work behind a proxy that does not forward the WebSocket upgrade — but forwarding it is better.

PLUM_ALLOWED_ORIGINS

If the UI is served from an origin the backend doesn't already know, set PLUM_ALLOWED_ORIGINS (comma-separated) in the environment. Compose passes it through to the backend container for both CORS and the socket handshake.

PLUM_OAUTH_REDIRECT_URI

For Google sign-in, plum server passes your API URL to the backend (PLUM_API_URL) and the redirect URI is <API URL>/auth/google/callback. Set PLUM_OAUTH_REDIRECT_URI only if you run your own docker-compose without plum server and can't forward X-Forwarded-Proto / X-Forwarded-Host from your proxy — give it the exact https://api.example.com/auth/google/callback registered on the OAuth client.

Frontend base URL

The UI bundle is built with a sentinel for the API URL and the entrypoint substitutes the real value on every container start from VITE_API_URL (which plum server writes into docker-compose.override.yml). You can change the API URL and restart without rebuilding the image.

Clone this wiki locally