nimeet Docs
中文

Self-Hosting

Minimal topology, LiveKit and Egress, environment variable reference, health probes, backup and upgrade.

Version v1.1.0 · Updated 2026-10-26 · revision 1

Self-hosting is what most distinguishes ni-meet from "just using someone else's cloud": the whole stack runs on your own machines or cluster. This page covers the three deployment shapes, environment variables, health checks, backup and upgrade, and the hard requirements for production.

Three deployment shapes

ShapeCommandMedia planeRecordingUse
Local developmentpnpm dev:apimemory simulatorin-process simulated schedulingbusiness logic, tests and doc examples with zero dependencies
Local real SFUdocker compose -f deploy/compose.yml up livekit redis api (NIMEET_SFU_ADAPTER=livekit)real LiveKitLiveKit Egressverify the real media path
Full stackdocker compose -f deploy/compose.yml upLiveKit + TURNdedicated egress container + egress-workersame shape as production, including isolation and load testing
bash
docker compose -f deploy/compose.yml up -d --build
# API            https://api.your-domain.example
# console        https://console.your-domain.example
# docs           https://docs.your-domain.example
# meeting demo   https://meet.your-domain.example
# LiveKit ws     wss://sfu.your-domain.example
# MinIO          https://objects.your-domain.example    (optional `objectstore` profile; nimeet / nimeet-secret)
# egress worker  internal health/stats surface (not public)

On first start the API writes one-time demo credentials to data/demo-credentials.json. Before exposing it to the internet you must change CONSOLE_SEED_PASSWORD, NIMEET_WEBHOOK_SIM_SECRET and NIMEET_EGRESS_WORKER_TOKEN.

Environment variables (only the ones that affect behaviour)

VariableDefaultMeaning
PORT / HOST8787 / 0.0.0.0API listener
NIMEET_SFU_ADAPTERmemorymemory (simulated) or livekit
LIVEKIT_HOST / LIVEKIT_API_KEY / LIVEKIT_API_SECRET—required by the livekit adapter
NIMEET_EGRESS_MODElocalwith remote, jobs are dispatched to worker processes
NIMEET_EGRESS_WORKERS—comma-separated list of worker URLs
NIMEET_EGRESS_WORKER_TOKEN—bearer token for the worker control plane
EGRESS_MAX_CONCURRENT / EGRESS_QUEUE_LIMIT8 / 200control-plane concurrency gate and queue
EGRESS_NODE_COUNT / EGRESS_NODE_CAPACITY2 / 4shape of the local node pool
NIMEET_SEED_DEMOtruewhether to seed the demo project and analytics data (set false in production)
RECORDING_STORAGE_VENDORlocals3 / oss / cos / gcs / local
RTMP_PUSH_BASE / HLS_PLAY_BASEexample domainsingest/playback URL templates
WORKER_CAPACITY / WORKER_QUEUE_LIMIT / WORKER_MAX_JOB_MS2 / 100 / 4hegress worker limits
NIMEET_RATE_LIMIT_PER_MINUTE / _BURST600 / 60request rate limiting (see Quota)
PUBLIC_BASE_URL—externally reachable address; used to build absolute URLs for callback links and share links
VITE_SFU_URL (at front-end build/start time)—the media address the browser connects to (local wss://sfu.your-domain.example, production wss://sfu.your-domain.example). The token carries no SFU address field: the front end has only two sources — this build-time variable, or the serverUrl returned by the IM provider

Health and readiness

EndpointPurpose
GET /healthzliveness probe (the process is still up)
GET /readyzreadiness probe (storage and SFU are usable)
GET /metricsPrometheus metrics (operator use; never expose publicly)

In Kubernetes, wire healthz as the liveness probe and readyz as the readiness probe; keep scheduler and worker operator surfaces on the cluster network only.

Network and ingress

  • The public reverse proxy should expose only: /v1/*, /dev/v1/*, /console/*, the operator surface; the remaining the operator surface endpoints are operations tooling;
  • WebSocket upgrade must be allowed (/rtc proxied to LiveKit), otherwise clients reconnect forever;
  • TURN: the compose stack ships LiveKit with TURN built in; allow 3478/udp and 5349/tcp;
  • The LiveKit webhook only has to be configured once (deploy/livekit.yaml); the API derives the project from the room name <appId>:<channel> and verifies the signature.

Production hard requirements (do not go live without them)

ItemRequirementWhy
StorageUse a Postgres implementation of the storage interfacethe in-memory store assumes a single process and loses everything on restart
Recording isolationRun egress-worker on separate machines/CPU pools from the SFUrecording is CPU-intensive and will starve the media plane
CapacitySize WORKER_CAPACITY from your own measured egress stress-test numbersguessing leads to queued jobs timing out
SecretsKeep everything in a secret manager, never in the imagea leaked appCertificate means every token can be forged
BackupDaily business-database backups + an object-storage lifecycle policyrecording files are customer assets

Upgrade steps

  1. Upgrade the API first (one version of backward compatibility) and watch readyz and the error rate;
  2. Then upgrade the egress worker: drain it (stop accepting new jobs) → wait for running jobs to finish → replace it;
  3. Finally upgrade LiveKit / Egress (media-plane version changes affect streaming and recording encoding);
  4. After upgrading, run node examples/run-all.mjs --all in the documentation examples directory as a regression check.

Backup and restore

DataLocationBackup method
Projects/channels/jobs/usagebusiness databasedatabase snapshots + PITR
Recording filesthe object storage behind RECORDING_STORAGE_VENDORbucket versioning + cross-region replication
Driver logsprocess stdout / logging systemretain ≥ 7 days, searchable by X-Request-Id

Common deployment problems

SymptomCauseAction
Clients stay in RECONNECTINGthe reverse proxy does not allow WebSocketenable Upgrade/Connection header pass-through
Recording jobs stay queuedEGRESS_MAX_CONCURRENT too small, or the worker is downcheck the operator surface
Recording files return 404storage vendor configuration and bucket permissions disagreerun the recording-storage self-check
Callbacks never arrivewebhook not configured / secret mismatchconfigure it in the console, then check the delivery log
All data is lost after a restartthe in-memory store was usedswitch to a Postgres implementation

Generated by the documentation build pipeline · 2026-10-31 01:24:02 UTC · Documentation center v1.1.0.

Content follows the public API definitions.

ni-meet is a self-hosted RTC PaaS with a LiveKit-based media plane (Apache-2.0) and an Agora-compatible API.