Skip to main content
Two commands give you a complete Floe instance on one machine: the web app on port 3000 and the signaling server on port 3001, both from published images. This page is for trying self-hosting locally before you put an instance behind a domain.

Prerequisites

  • Docker and Docker Compose 2.8.0 or later (docker compose, bundled with Docker Desktop and modern Docker Engine; check with docker compose version). An older Compose stops with invalid interpolation format when it reads docker-compose.yml.
  • Ports 3000 and 3001 free on this machine. If another program already uses one, pick other ports as Change the ports shows.

Steps

1

Make a folder for Floe

Terminal
Run every later command from this folder. The compose file goes here, and so does the .env file, or the policy and coturn folders, if you add them later.
2

Download the compose file

Terminal
That is the only file you need. There is nothing to clone and no toolchain to install. In Windows PowerShell, type curl.exe in place of curl: plain curl there is another command, and it does not take these options.
3

Start the stack

Terminal
Docker pulls the prebuilt images and starts the server, then the client once the server reports healthy. Nothing is compiled locally. The server’s health check runs every 30 seconds, so the command can wait on the client for a while before it returns.
4

Open the app

Open http://localhost:3000 in your browser. The badge at the top right of the card reads Ready once the page has reached the signaling server. Pick a file and click Create secure link (1 file) (the button counts the files you picked), then paste that link into a second tab to join as the receiver. Show QR renders the same link as a scannable code, which is how you receive on a phone once the app is reachable from one (see Open it from another device).
A .env file is optional. Every setting has a working default, so the commands above are genuinely all you need to try it. To change something, fetch the annotated example into the same folder:
Terminal
In Windows PowerShell this one is curl.exe too. Compose reads .env when it creates the containers, so run docker compose up -d again after each edit. Every variable is described in Configuration.

What this runs

This stack has no relay. Two devices connect straight to each other, which works on most home and mobile networks, and two devices whose networks block that cannot connect at all. The server hands every client two public Google STUN servers and nothing else. No files pass through the server. To connect devices behind strict firewalls, symmetric NAT, or carrier-grade NAT (CGNAT), add a TURN relay: see TURN relay. Request links are off in this stack until a policy file turns them on. See Turn on request links. The CLI and Floe Desktop work with this instance too. They connect to the signaling server, so give them http://localhost:3001, not the web app’s port. See Use a self-hosted server.

Open it from another device

The defaults assume the browser and the server are on the same machine. To reach the app from another device on your network, set both of these in .env to your machine’s address on your network (its LAN IP). ipconfig on Windows and ip addr on Linux print it. In the example, 192.168.1.x stands for that address. If you have no .env yet, fetch the example as shown above, or create the file with just these two lines:
.env
Terminal
Then open the app at http://192.168.1.x:3000 on the sending machine too, not localhost:3000. The share link and its QR code carry whichever address the page was loaded from, so a sender sitting on localhost hands the phone an address that only resolves back to the phone. No rebuild: the client reads its server address at runtime. CLIENT_URL matters as much as the socket URL, because it tells the server which web address may connect to it. Without it the page loads and never connects. A page opened at a plain http:// address other than localhost runs without the screen wake lock, the clipboard API, and service workers, so the screen may sleep during a long transfer. That is fine for a test. For anything more, serve the app over HTTPS: see Production deployment. The CLI and Floe Desktop on another device take the server’s address on port 3001. They turn exactly http://localhost:3001 into http://localhost:3000 for the links they hand out, and no other address. For any other address, give them the web app’s address as well, as --web or Share link address, or their links open the signaling server instead of the web app.

Change the ports

Set PORT and CLIENT_PORT in .env to publish the signaling server and the web app on host ports other than 3001 and 3000. On one machine that is all it takes: while NEXT_PUBLIC_SOCKET_URL and CLIENT_URL are unset, each follows its port. If you have set either one yourself, it has to carry the new port:
  • A NEXT_PUBLIC_SOCKET_URL you set has to name the server’s address on the new port, or the browser keeps looking for the old one.
  • A CLIENT_URL you set has to name the web app’s address on the new port, or the server refuses the page’s connections.
For example, to move both:
.env
Terminal
No rebuild is needed for either one. The CLI and Floe Desktop then need --web or Share link address even on this machine, because only http://localhost:3001 is paired with the web app for them.
A docker-compose.yml that does not contain the text NEEDS_DOCKER_COMPOSE_2_8_OR_LATER is an older copy whose two addresses do not follow the ports. With it, change a port and the page loads but never connects: the badge stays on Offline. Download the file again, or set both addresses yourself.

If something goes wrong

Last modified on October 14, 2026