Prerequisites
- Node.js 22.13 or later, for both processes. The client sets that floor: it pins pnpm 11.1.2, which refuses to run on anything older. The signaling server has no
enginesfield, so nothing stops you from starting it on something older, but the oldest version anything tests is Node.js 22. Both published images run Node.js 24. - pnpm 11, for the client.
client/package.jsonpinspnpm@11.1.2. Install that version, for example withnpm install -g pnpm@11.1.2, which is what the image build does. - Git, to clone the repository and to update it later.
Running each component
The signaling server and the web client are two long-lived processes, so each needs its own terminal, or a process supervisor such as pm2 or systemd.1
Clone the repository
Terminal
2
Copy the environment files
Terminal
3
Start the signaling server
Terminal
curl -s http://localhost:3001/health.4
Build and start the web client
The server holds the first terminal, so open a second one in the Then open http://localhost:3000.
floe folder:Terminal
CLIENT_PORT does nothing here. To serve the client on another port, start it with PORT=8080 pnpm start, and set CLIENT_URL in server/.env to the new address.pnpm build, then pnpm start. pnpm dev is for development only, and it always dials http://localhost:3001 unless NEXT_PUBLIC_SOCKET_URL is set, whatever SOCKET_URL says.
To try the instance from a terminal, build the CLI and point it at the signaling server:
Terminal
Environment variables
Both example files are written for one machine. Before the instance serves anyone else, change these:
Both client values are inlined when the client is built, so changing either one later means another
pnpm build.
To change the signaling address later without rebuilding:
- Remove
NEXT_PUBLIC_SOCKET_URLfromclient/.env.local, then runpnpm buildonce more. - Start the client with the unprefixed
SOCKET_URLin its environment, as inSOCKET_URL=https://api.your-domain.com pnpm start.
/api/config. See How the client finds the server. Leave both empty when the client and the signaling server share one origin behind a reverse proxy.
The server reads .env from the folder it is started in, so start it from server/, or point your supervisor’s working directory there. A variable already set in the process environment wins over the file.
Keep NODE_ENV=production, which server/.env.example already sets: it matches what the published image runs.
Request links stay off until POLICY_FILE in server/.env names a policy file. See Turn on request links.
Updating an existing deployment
The Docker instructions in Operations assume there is no repository to keep in sync. Running directly with Node means there is, so pull, reinstall, then restart:Terminal
pm2 restart <name>, systemctl restart <unit>, or your own runner). pnpm start serves whatever pnpm build last produced, so skipping the client rebuild leaves the old client running with nothing to indicate it is stale. A server restart forgets every room and room code, so pick a quiet moment; see Operations.
Confirm the restart landed by checking that uptime reset:
Terminal
Terminal
If something goes wrong
- The server prints nothing after
npm start, or only a line aboutTRUSTED_PROXY_COUNT: that is expected. See The server logs nothing at all. - The server prints a line starting
Only one of,TURN_DOMAIN holdsorUpstash counter: a setting may need fixing. See The server logs very little. - The page loads and the badge stays on Offline: see The browser cannot connect to my signaling server.
- The server answers
403to the browser:CLIENT_URLdoes not match the page’s origin. See Browser requests are blocked, and the server answers HTTP 403.