Skip to main content
This page runs the signaling server and the web client straight from a clone of the repository, with Node.js and no containers. It is for hosts where Docker is not an option, and it leaves you with two long-lived processes to supervise and a checkout to keep up to date. The variables in Configuration apply here too, and the rows that behave differently on a direct run say so.

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 engines field, 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.json pins pnpm@11.1.2. Install that version, for example with npm install -g pnpm@11.1.2, which is what the image build does.
  • Git, to clone the repository and to update it later.
The optional CLI build below also needs Go. See Install the CLI.

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
Run every later block from this folder, the repository root.
2

Copy the environment files

Terminal
The copies work as they are while the browser is on the same machine. Before you build for anyone else, set the values under Environment variables: two of them are compiled into the client.
3

Start the signaling server

Terminal
It listens on port 3001, on every network interface. With the example file in place it logs nothing when it starts. Check it from another terminal with 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 floe folder:
Terminal
Then open http://localhost:3000. 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.
Serve the client from a production build: 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
For a development setup with live reload, see CONTRIBUTING.md.

Environment variables

Both example files are written for one machine. Before the instance serves anyone else, change these:
Set NEXT_PUBLIC_SITE_URL to your own address before you run pnpm build, or your instance names another site as its home. The example value, http://localhost:3000, is written into every canonical link, share preview, and sitemap entry, and a build with the line removed or empty names https://www.floe.one. See Container images.
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:
  1. Remove NEXT_PUBLIC_SOCKET_URL from client/.env.local, then run pnpm build once more.
  2. Start the client with the unprefixed SOCKET_URL in its environment, as in SOCKET_URL=https://api.your-domain.com pnpm start.
The browser then reads the address on every page load from /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
A request link from Floe Desktop 1.1 or later needs a client built from 1.12.0 or later, and an older build reads it as an incomplete link, so rebuild the client before Floe Desktop 1.1 reaches your users. Then restart both processes with whatever supervises them (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.
Reinstall before you restart, and do not skip it. A dependency update that only moves a lockfile changes no source file, so a restart on its own re-executes the same node_modules and the update silently does not take effect. The process comes back healthy and the old version is still running.
Confirm the restart landed by checking that uptime reset:
Terminal
To confirm a specific dependency actually moved, read the installed version rather than trusting the restart:
Terminal

If something goes wrong

Last modified on November 5, 2026