Deploy a relay
Runbook for launching your own Cloudflare relay (server-cf/) on Cloudflare Workers + Durable Objects.
1. Prerequisites (one-time)
- Cloudflare Workers paid plan — Durable Objects (incl. SQLite + Hibernation) require it.
- A zone for the base domain added to Cloudflare (e.g.
voltertest.xyz), with a 1-level wildcard so free Universal SSL covers*.<domain>. Tunnel URLs arehttps://<tunnelId>.<domain>. wrangler login(or a CI API token with Workers + DO + the zone).
2. Configure
All commands run from server-cf/.
Vars (wrangler.jsonc → vars) — already set with sensible defaults; confirm:
TUNNEL_DOMAIN— set to your real base domain (currentlyvoltertest.xyz).SIGNUP_DAY_LIMIT/SIGNUP_MONTH_LIMIT— free-tier per-account dollar cap (op-credits, ~$1/million). Do not leave at the code default of 1000 — that is ≈$0.001 and makes free accounts unusable.DEFAULT_RESERVED_MAX(free reserved ids, default 3),RESERVATION_IDLE_TTL_DAYS(default 60),BURST_RPS(0 = off) — confirm vs D6.GLOBAL_DAY_LIMIT/GLOBAL_MONTH_LIMIT— the Σ(account limits) ceiling and therefore your total spend cap and signup-capacity limit.
Secrets (wrangler secret put <NAME>):
ROOT_TOKEN— required. Admin credential (mintvtr_…, e.g.openssl rand -hex 24prefixedvtr_). Rotatable: re-put + redeploy.SIGNUP_ALLOWED_USERS— comma-separated GitHub logins allowed to sign up. Kept as a secret so it isn't committed to a public repo. Signup fails CLOSED: if this is unset/empty, nobody can sign up unlessSIGNUP_OPEN=trueis also set. So the three modes are: allowlist (this set), fully open (SIGNUP_OPEN=true, no allowlist), or closed (neither — the safe default). Recommended launch policy: WAITLIST ONLY. Set on the worker (seeded with<your-login>) → signup is closed to the public; only listed logins can self-provision, everyone else gets 403. To approve someone off the waitlist, append their login and re-put:printf '<your-login>,newlogin' | wrangler secret put SIGNUP_ALLOWED_USERS.JWT_SECRET— optional; HS256 secret for end-user JWT/cookie auth on tunnels.TUNNEL_SECRET— optional legacy shared secret → the internal account. Set it if your own gateway uses the shared-secret path; omit for a pure-signup deployment (an unset secret fails closed — an api token is then required).
Optional:
INSPECT_REPLAY=trueto enable persisted inspector history +/__volter_replay; uncomment theUSAGE_AEbinding after enabling Analytics Engine for durable usage time-series.
3. Deploy
bash
cd server-cf
npm run typecheck && npm test # all suites should pass
npm run deploy # wrangler deployThe privileged internal account self-provisions on first use.
4. Smoke-test the live relay
bash
BASE=https://<your-domain>
# Apex responds
curl -s $BASE/api/status # {"ok":true,"relay":"cloudflare-do"}
curl -s $BASE/ | grep -o '<title>.*</title>' # landing page; /docs serves the docs
# Signup (must be on the allowlist if SIGNUP_ALLOWED_USERS is set)
volter-tunnel login --host $BASE # gh auth token → mints vta_ token
# …or gist proof, sends us no token:
volter-tunnel login --host $BASE --gist
# Expose a local app and hit it
volter-tunnel --port 3000 --host $BASE # prints https://<id>.<domain> + QR
curl -s https://<id>.<domain>/ # reaches your local app
# Admin (root)
curl -s $BASE/admin/accounts -H "Authorization: Bearer $ROOT_TOKEN"
curl -s $BASE/admin/usage -H "Authorization: Bearer $ROOT_TOKEN"5. Operating it
- Create / raise an account (dollars):
POST /admin/accounts {"slug":"x","dayUsd":10,"monthUsd":100}(root). - Abuse: anyone may
POST /report {"tunnelId","reason"}; review withGET /admin/reports(root); revoke a handle withDELETE /admin/reservations/<tunnelId>(root) — frees the id + disconnects. - Waitlist: the apex serves a public landing page (
GET /) + docs (GET /docs); its form posts toPOST /waitlist. Review requests withGET /admin/waitlist(root). Approve someone by appending their GitHub login to the allowlist secret and re-putting it:printf '<your-login>,newlogin' | wrangler secret put SIGNUP_ALLOWED_USERS(the waitlist is a request queue only — approval is the env-secret edit). A user already on the allowlist who submits the form is told they can sign up now. - Tune fair-use: raise
BURST_RPSif you see request floods; the daily/ monthly credit caps are the primary limit. - Edge rate-limit (per-IP): add a Cloudflare WAF rate-limit rule on the unauthenticated surface with
CLOUDFLARE_API_TOKEN=… bash server-cf/scripts/cf-ratelimit.sh(needs a token with Zone → WAF → Edit + Zone → Read). Deploys 20 req / 10s per IP → block. Complements the in-DOSIGNUP_RPSlimiter (which is global, not per-IP). - Rotate root:
wrangler secret put ROOT_TOKEN+ redeploy (no lockout — the env secret is the source of truth).
6. Decide before public launch
- Free-tier
SIGNUP_DAY/MONTH_LIMIT,DEFAULT_RESERVED_MAX,RESERVATION_IDLE_TTL_DAYS, and whetherBURST_RPSis on. - Open vs allowlist signup (
SIGNUP_ALLOWED_USERS). Currently launching in allowlist mode. - Whether to offer
INSPECT_REPLAY(paid retention) and at what caps.
7. Not yet built (Phase 2)
Custom hostnames (#12, needs CF-for-SaaS), TCP/UDP (#13, needs off-Cloudflare compute), and the paid bandwidth/concurrency tiers (#11/#14 — enforcement exists per-account; only packaging remains).