Docker Compose
One image serves every role; theROLE variable picks what each container runs.
1
Clone and install
2
Create wallets
.env, and prints each
address and balance. It never prints a key and never replaces a value that is already set. Fund
the three addresses from the faucet.3
Start the network
OHTTP_ALLOW_LOCAL=on lets the OHTTP relay forward to http://localhost relayers. Use it only
locally.4
Check health
"ok": true. The relayers also report their queue, batches written, balance and
heartbeat entity.Public deployment with HTTPS
Browsers and OHTTP relays only use https relayers on public hosts.-
Point DNS for your hostnames (for example
relay-1.example.com,relay-2.example.com) at the machine. -
Put those hostnames in
deploy/Caddyfile. -
Set the public URLs in
.env:.env -
Start with the TLS overlay:
Without Docker
Node.js 22 or newer:Platforms (Railway, Fly, Render)
Every service is the sameDockerfile; create one service per role and set ROLE. The repository’s
railway.json configures the Dockerfile build, the /healthz health check and restart-always. The
Railway + Vercel guide has the exact variables.
Run only part of it
- Only a relayer, no tokens:
REQUIRE_TOKENS=off. A per-address rate limit protects your gas. - A relayer that accepts another team’s tokens:
REQUIRE_TOKENS=on,ISSUER_WALLET_ADDRESSandISSUER_URLof their issuer. - Only an OHTTP relay for someone else’s relayers:
ROLE=ohttp-relay, nothing else to set.
Operating it
- Gas. Every batch and every heartbeat costs gas. Across all our test runs (several hundred
records plus heartbeats) one relayer spent about 0.1 GLM. Watch
balanceGlmon/healthz; the relayer logsLOW BALANCEbelowLOW_BALANCE_GLM. The faucet gives 0.1 GLM a day per wallet. - One wallet, one process. Never run two processes on the same relayer wallet: their transactions collide.
- Restarts are safe. Queued requests are lost and clients retry elsewhere; a record that was already written is recognised by its client, so nothing is written twice. The heartbeat and the OHTTP gateway key survive restarts.
- Issuer keys rotate daily and derive from
ISSUER_RSA_SEED. Never change the seed during a day: clients would see two keys and refuse the issuer. - Logs contain batch summaries only, never IPs or request bodies. Keep your proxy the same.