Skip to content

Requirements

All figures on this page come from DEPLOY.md. The capacity numbers were measured with test/load.js, not estimated. You can re-run them yourself. The platform facts were checked in August 2026. Free tiers change constantly, so re-check anything that decides your bill.

Software

  • Node 22 (the Dockerfile uses node:22-slim, and CI runs Node 22). The server uses node:sqlite and Ed25519 in WebCrypto.
  • One npm dependency: ws. node_modules is about 200 KB.
  • Optional: GNU Backgammon (gnubg) for a strong hard bot and deep analysis. The Docker image already includes it. BGBlitz is commercial and cannot be bundled. See Analysis & PR.

Measured capacity

One container, one process:

whatmeasured
idle71 MB RSS, 9 MB heap
200 concurrent 9-point matches (LOAD_MATCH_LENGTH=9 node test/load.js 200)231 MB RSS peak, 824 KB per live match, 400 sockets
200 concurrent 1-point matches154 MB RSS, 2,180 events/sec
25 concurrent matches against the bot110 MB RSS
cold start (boot → /healthz answering)291 ms
a finished match on disk~4 KB gzipped
database~92 KB at 22 players / 16 matches
runtime dependenciesone (ws); node_modules is 200 KB

Re-run it

bash
node test/load.js 200                              # 200 concurrent 1-point matches
LOAD_MATCH_LENGTH=9 node test/load.js 200          # 200 concurrent 9-point matches

test/load.js opens every socket from one address, so it runs into the connection rate limit. That is how the project discovered the limit needed to be tunable. Raise LIMIT_CONNECT_BURST for large runs. See Rate limiting.

What that means

  • Minimum that works: 512 MB RAM, 1 shared vCPU. That holds about 200 concurrent long matches with headroom. 256 MB works for about 100 concurrent long matches. Below that, the idle 71 MB starts to dominate.
  • CPU is near zero for games between humans. The server does no evaluation for them. Bot games are the only CPU cost, and deep analysis runs on volunteer workers, not on the server.
  • Disk is a rounding error. At 4 KB per match, 10,000 matches take 40 MB. You need a volume for persistence, not for capacity.
  • A 4 GB box can also run an analysis worker with gnubg alongside the server. A 512 MB managed instance cannot.

Persistence is not optional

Without a persistent volume, server-key.json is regenerated on every restart, and every record the server has ever signed becomes unverifiable against the key it then publishes. That is not just data loss: it breaks the project's central claim. If your platform has secrets but no disk, pass the key as SERVER_KEY_PKCS8.

Where to run it

optionwhat DEPLOY.md says (checked August 2026)
Hetzner CX22 (VPS)2 vCPU, 4 GB RAM, 40 GB disk, 20 TB traffic. €4.49/month as of the 1 April 2026 price change. Hetzner raised prices again in June 2026, and reports of the size of that increase disagree, so check the current price. IPv4 is billed separately (a few cents a month). This is the path documented in Deploy to a VPS
Hetzner CAX11 (ARM)same 2 vCPU / 4 GB, about €0.70/month cheaper. Not verified with this project
Oracle Cloud Always Free2 OCPU / 12 GB Ampere A1 (ARM) plus 200 GB block storage, with no time limit. Ampere capacity is a lottery: people wait days or weeks
Northflankthe free Sandbox plan is always-on (no sleeping). DEPLOY.md could not confirm whether it includes a persistent volume. Check before relying on it. Pay-as-you-go starts at $2.70/month for 0.1 vCPU / 256 MB, roughly $5–6/month at 512 MB
Renderfree web services sleep after 15 minutes idle (30–60 s cold start) and cannot attach a persistent disk. render.yaml therefore uses the paid starter plan with a 1 GB disk
Railway$5/month of included credit on Hobby, usage-based, no hard spending cap. Reads railway.json
Fly.iono free allowance for new organisations since 2024: a short trial, then roughly $2–5/month. fly.toml sets pristine = true so the proxy does not interfere with the WebSocket upgrade
Cloudflare Workers + Durable Objectsfits the architecture but needs a port (see Architecture)

Cloudflare Workers + Durable Objects

DEPLOY.md sizes the Workers Free plan for SQLite-backed Durable Objects at about 3M requests/month (100,000/day), about 390K GB-s (13,000/day), and 5 GB storage. Incoming WebSocket messages bill at 20:1, and outgoing messages are free. A 9-point match runs about 990 events, which works out to roughly 50 billable requests per match, or on the order of 60,000 matches a month at no cost. The paid tier starts at $5/month.

A completely free stack, as listed in DEPLOY.md

pieceproviderfree allowance
serverNorthflank Sandbox2 services, always-on. Volume support unconfirmed
server, alternativeOracle Always Free2 OCPU / 12 GB ARM VM + 200 GB disk, if capacity is available
emailMailjet6,000/month, 200/day, multiple domains
backupsCloudflare R210 GB, no egress fees
error alertsDiscord webhookno account needed
analysisyour own laptopnpm run worker

The only unavoidable cost is the domain (about $10–15 a year).

What you take on with a VPS

managed platformVPS
TLSincludedCaddy
deploy on pushincludeddeploy/push.sh
restart on crashincludedrestart: unless-stopped (already in the compose file)
logs, metricsUIdocker logs, journalctl
OS patching, firewall, SSH hardeningnot your problemyours, permanently

The last row is the real cost, and it costs time rather than money. That is why deploy/ automates it. DEPLOY.md notes that for roughly what a managed 512 MB instance costs, a CX22 buys about eight times the RAM.

Rules engine, fairness protocol, verifier, analysis and worker: MIT. Server and client: AGPL-3.0-or-later.