gateway.tracelane.dev runs on a small VPS or a
hardened production Docker Compose stack.
Prerequisites
Quick start — local development only
The fastest path to a running stack::8080, dashboard on :3000.
Production — two topologies
Pick one. They cannot be mixed: single-tenant self-host mode refuses to start if a Postgres, WorkOS or SPIRE setting is present in the environment (crates/shared/src/self_host.rs, MULTI_TENANT_SIGNAL_ENVS).
A. Single-tenant self-host — the shipped compose
infra/self-host/docker-compose.yml runs ClickHouse + NATS/JetStream + gateway +
ingest on one box, built from source, as one workspace with no control plane:
no Postgres, no WorkOS, no Polar, and no dashboard service. Every request
authenticates with the bearer token TRACELANE_MASTER_KEY, and every span is
stamped with TRACELANE_SINGLE_TENANT_ID. Provider keys are read from the
environment (ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_API_KEY — set at
least one).
Put a TLS-terminating reverse proxy in front of
:8080. A self-hosted gateway
with no control plane has no per-minute request cap
(crates/gateway/src/rate_limiter.rs) — cap it at your reverse proxy if you
need one.
B. Multi-tenant — running the hosted topology yourself
The hosted topology adds a Postgres control plane (tenants, API keys, entitlements, billing and the canonical audit ledger), WorkOS for identity, Polar for billing, and the Next.js dashboard. This repo ships no production compose file for it:infra/dev/docker-compose.yml brings up the backing services for
development, and infra/docker/ holds the gateway and ingest Dockerfiles.
Postgres is external (Neon or RDS); the dashboard runs on Vercel/Cloudflare; the
gateway and ingest sit behind a TLS-terminating reverse proxy. (Tracelane
Cloud’s own production compose is not published.)
Images are built on-node from source. A published Helm chart and
signed Chainguard/Wolfi image registry are on the roadmap — not yet shipped.
Environment variables — multi-tenant topology
The tables below are for topology B. Topology A’s variables are in its table above; do not add these to a single-tenant deployment.Required (production)
Optional
There are no cold-tier storage variables for the gateway or ingest to read.
Cold archival is a ClickHouse storage policy (an object-storage volume that aged
parts move to), configured in ClickHouse itself — the hosted service runs one;
a self-host without it keeps spans on the ClickHouse disk.
Apply migrations
SLO tables/views (
slo_hourly_stats, v_slo_stats) live in
infra/dev/clickhouse/migrations/06_genai_attr_keys_and_slo.sql, not in
schema.sql — a fresh compose stack must also apply the migrations dir or
/v1/slo returns UNKNOWN_TABLE.Configure WorkOS
WorkOS handles SSO (Google, Microsoft, SAML, GitHub, email OTP).- Create a WorkOS application at workos.com.
- Set the Redirect URI to
https://app.<your-domain>/auth/callback. - Configure Connections for the providers you want to support.
- Add a Webhook at
https://gateway.<your-domain>/v1/webhooks/workos, subscribed to:organization.created,user.created,dsync.user.created. - Copy the webhook secret to
WORKOS_WEBHOOK_SECRET. - Copy Client ID and API Key to
WORKOS_CLIENT_IDandWORKOS_API_KEY.
Configure Polar
Tracelane bills through Polar.sh (Merchant of Record); there is no direct Stripe integration.-
Create Products with these
lookup_keyvalues (set on each product’sproduct_metadata) — one monthly base product per paid plan. Annual billing is not offered yet; when it is, it is a separate base-plus-usage pair per plan, described on the pricing page. -
Create six Meters with
event_name:ingest_gb,hot_gb_month,series,scan_units,cold_gb_month,eval_runs
-
Create a Webhook at
https://<your-dashboard-domain>/api/webhooks/polar, subscribed to:subscription.created,subscription.updated,subscription.active,subscription.canceled,order.created,order.paid. - Issue an Organization Access Token with read/write scope for products, subscriptions, meter events, and customer-portal sessions.
-
Set
POLAR_ACCESS_TOKEN,POLAR_WEBHOOK_SECRET, andPOLAR_EXPECTED_ORGANIZATION_ID.
Generate audit signing key
The SHA-256 hash chain and Ed25519 per-tenant signing are live. Anchored
batches carry a resolved Sigstore Rekor v2 inclusion proof (best-effort,
opt-in); universal per-run anchoring is on the roadmap.
rekor-signing.pem in your secrets manager. Losing it means you cannot
anchor new audit batches — existing anchors remain verifiable.
Verify the stack
In topology A the bearer token is yourTRACELANE_MASTER_KEY, not a tlane_…
key — there is no dashboard to mint one.
Production checklist
Before accepting production traffic, in either topology:-
TRACELANE_REKOR_SIGNING_KEYgenerated and stored;TRACELANE_REKOR_URLset if batches are to be anchored (unset, they are signed locally and never anchored) - ClickHouse pointing at production storage (not dev compose)
- TLS termination at reverse proxy (Caddy, Nginx, or Cloudflare Tunnel)
- OSV-Scanner + Grype clean on deployed commit
- Conformance suites green:
pnpm --filter @tracelanedev/audit-verifier test
-
TRACELANE_MASTER_KEYset (32 random bytes, stored in secrets manager) — it is the bearer token every client sends - No
POSTGRES_URL/PGHOST/WORKOS_CLIENT_ID/TRACELANE_SPIRE_SOCKETin the environment — the gateway and ingest refuse to start with one
-
TRACELANE_BYOK_MASTER_KEYset and rotated (32 random bytes, stored in secrets manager) - Confirm
POSTGRES_URLis set — a release build has no auth fallback and refuses every API key without it - Postgres pointing at production branch (Neon or RDS)
- WorkOS webhook verified (send a test event, confirm tenant is provisioned)
- Polar products + meters + webhook configured and verified