Socket server on Fly.io

Why the WebSocket machine must never auto-stop, and how to deploy it

The circular-socket app runs Socket.io in Frankfurt — next to the Supabase database it authenticates against, and in the EU market's own region.

Auto-stop is off, deliberately

apps/socket/fly.toml
[http_service]
  auto_stop_machines = false   # never stop on idle
  auto_start_machines = true   # still recover if something stops it
  min_machines_running = 1     # always one machine up

Fly's auto-stop is built for HTTP APIs, where the proxy can wake a machine on the next request. A WebSocket server has no such moment: when the last client disconnects, Fly sees "excess capacity" and stops the machine — with min_machines_running = 0, every machine — and the app goes suspended. The next client to arrive gets connection errors until a cold boot finishes.

It took under five minutes of quiet to lose the machine.

Auto-stop is right for HTTP APIs, cron workers and low-traffic preview apps. It is wrong for anything holding long-lived connections: WebSockets, SSE, gRPC streams.

Cost of leaving one shared-cpu-1x/512MB up all month: roughly $3–5.

Deploy from the repo root

The Dockerfile expects monorepo context:

fly deploy --config apps/socket/fly.toml

Running it from inside apps/socket/ fails — COPY packages/db ./packages/db cannot resolve from there.

If a machine is stopped

fly machine update --app circular-socket --autostop=off --skip-start -y <MACHINE_ID>
fly machine start  --app circular-socket <MACHINE_ID>
fly status --app circular-socket

On this page