# ═══════════════════════════════════════════════════════════════ # OpenRestream — Environment Configuration # Copy to .env for development. In production this is /etc/openvibe/openre.env (0600), read by # every unit (openre-api, openre-session-coordinator, openre-rtmp-ingest@, openre-restream-worker@); # the units set NODE_ENV, PORT and OPENRE_RELEASE themselves. # Names only here: never commit a value. # ═══════════════════════════════════════════════════════════════ # ── openre-api ───────────────────────────────────────────────── PORT=4500 HOST=127.0.0.1 NODE_ENV=development #BASE_URL=https://openre.stream # Hops in front of Node that set X-Forwarded-For (Cloudflare → nginx → Node). #TRUST_PROXY=2 #COOKIE_SECURE=true # ── Identity: OpenVibe.Network ──────────────────────────────── OV_NETWORK_URL=https://openvibe.network OV_NETWORK_INTERNAL_URL=http://127.0.0.1:4000 #OV_NETWORK_ISSUER=https://openvibe.network # Pin the Network public key instead of fetching /api/.well-known/jwks (PEM, \n escapes allowed). #OV_NETWORK_PUBLIC_KEY= # OAuth client `openre`: browser sign-in for the UI (redirect https://openre.stream/auth/callback) # and OpenRestream's own client-credentials tokens (Events, Media). OV_OAUTH_CLIENT_ID=openre OV_OAUTH_CLIENT_SECRET= #OV_OAUTH_REDIRECT_URI=https://openre.stream/auth/callback # A browser's Network JWT is accepted when its aud contains one of these. #OPENRE_USER_AUDIENCES=openvibe.openre,openvibe.network # ── Store (PostgreSQL, shared by every OpenRestream process) ──────── # PostgreSQL (ADR-035): DATABASE_URL serves through PgBouncer, DATABASE_DIRECT_URL (the owner) runs migrations/ at boot; # OpenVibe.Host `roles/data/add-service.sh openre` writes both. Every OpenRestream process shares the database. Without # DATABASE_URL, development runs on an embedded PGlite database in data/pglite (OPENRE_PGLITE_DIR): one process only. DATABASE_URL= DATABASE_DIRECT_URL= VALKEY_URL= # ── Secrets ─────────────────────────────────────────────────── # 32 bytes (64 hex chars or base64): encrypts restream destination keys and SRT passphrases at rest. # Required for destinations; generate with `openssl rand -hex 32`. OPENRE_SECRETS_KEY= # The previous key while rotating OPENRE_SECRETS_KEY (decryption only). #OPENRE_SECRETS_KEY_PREVIOUS= # ── RTMP ingest (openre-rtmp-ingest) ────────────────────────── # Public port. Live's own ingest keeps 1935 until its RTMP is retired (README "Port plan"). OPENRE_RTMP_PORT=1936 # More public ports every worker also serves, e.g. 1935 after Live's RTMP is retired. #OPENRE_RTMP_EXTRA_PORTS=1935 # Public listener address (default 0.0.0.0). 127.0.0.1 keeps ingest host-local (production until the # cutover, docs/cutover.md step 5). A new value takes effect with the next worker generation # (deploy.sh workers, which runs deploy/scripts/workers.sh), never by restarting a worker. #OPENRE_RTMP_BIND=0.0.0.0 # What encoders are told: rtmp://[:]/live #OPENRE_RTMP_PUBLIC_HOST=ingest.openre.stream #OPENRE_RTMP_PUBLIC_PORT=1936 # Loopback ports each worker generation takes for its RTMP play + HTTP-FLV endpoints. #OPENRE_RTMP_INTERNAL_PORT_MIN=19360 #OPENRE_RTMP_INTERNAL_PORT_MAX=19399 #OPENRE_RTMP_CHUNK_SIZE=60000 #OPENRE_RTMP_MAX_PUBLISHERS=64 # ── Ingest (JSMPEG, openre-jsmpeg@) ─────────────────────────── # Public port: the broadcaster's MPEG-TS HTTP POST and the WebSocket viewers on it. Live's relay # keeps 9710/9711 until the JSMPEG cutover (README "Port plan"). #OPENRE_JSMPEG_PORT=9736 # Public listener address (default 0.0.0.0). #OPENRE_JSMPEG_BIND=0.0.0.0 # What broadcasters/viewers are told (production default ingest.openre.stream, else 127.0.0.1). #OPENRE_JSMPEG_PUBLIC_HOST=ingest.openre.stream #OPENRE_JSMPEG_PUBLIC_PORT=9736 # Loopback ports a worker generation serves its raw MPEG-TS data tap from (the restream worker # reads it); first free port in the range, so two generations can run during a drain. #OPENRE_JSMPEG_INTERNAL_PORT_MIN=19710 #OPENRE_JSMPEG_INTERNAL_PORT_MAX=19749 #OPENRE_JSMPEG_MAX_PUBLISHERS=64 # ── Ingest (WebRTC: WHIP + mediasoup SFU + viewers, openre-webrtc@) ── # Public port: WHIP (POST/PATCH/DELETE /whip/…) and the /b/, /w/ signaling WebSockets. # Live's own WHIP lives on its app port until the WebRTC cutover. #OPENRE_WEBRTC_PORT=9936 # Public listener address (default 0.0.0.0). #OPENRE_WEBRTC_BIND=0.0.0.0 # What broadcasters/viewers are told (production default ingest.openre.stream, else 127.0.0.1). #OPENRE_WEBRTC_PUBLIC_HOST=ingest.openre.stream #OPENRE_WEBRTC_PUBLIC_PORT=9936 # Loopback ports a generation serves RTP descriptors from (restream worker, Media's RTP recorder # and the thumbnail grabber); first free port in the range. #OPENRE_WEBRTC_INTERNAL_PORT_MIN=19810 #OPENRE_WEBRTC_INTERNAL_PORT_MAX=19849 #OPENRE_WEBRTC_MAX_PUBLISHERS=64 # STUN/TURN servers handed to browsers, comma-separated. #OPENRE_WEBRTC_STUN=stun:stun.l.google.com:19302 # Live thumbnails: a frame grabbed from the worker's own source every interval, uploaded to Media # (OPENRE_THUMBNAIL_NS, grant media.object.upload ns live) and carried on the session. #OPENRE_THUMBNAILS=on #OPENRE_THUMBNAIL_INTERVAL_MS=30000 #OPENRE_THUMBNAIL_WIDTH=640 #OPENRE_THUMBNAIL_NS=live # ── mediasoup (inside openre-webrtc) ────────────────────────── # Public address RTC candidates are advertised with. REQUIRED in production: without it remote # WebRTC clients cannot reach the worker's transports. #MEDIASOUP_ANNOUNCED_IP= # Interface RTC transports bind to (either name; MEDIASOUP_LISTEN_IP wins). #MEDIASOUP_LISTEN_IP=0.0.0.0 #OPENRE_MEDIASOUP_LISTEN_IP=0.0.0.0 # Announced address under the OPENRE_ prefix (MEDIASOUP_ANNOUNCED_IP wins when both are set). #OPENRE_MEDIASOUP_ANNOUNCED_IP= # UDP port range for RTC (never Live's 10000–10100) and how many mediasoup workers per process. #OPENRE_MEDIASOUP_MIN_PORT=10200 #OPENRE_MEDIASOUP_MAX_PORT=10300 #OPENRE_MEDIASOUP_WORKERS=1 # ── Workers, leases, drain ──────────────────────────────────── #OPENRE_WORKER_HEARTBEAT_MS=2000 # A worker silent this long is lost: its sessions fail and its outputs move to another worker. #OPENRE_WORKER_LEASE_MS=15000 # A draining generation keeps its sessions at most this long (default 24 h), then ends them. #OPENRE_DRAIN_MAX_MS=86400000 #OPENRE_COORDINATOR_INTERVAL_MS=1000 #OPENRE_RESTREAM_POLL_MS=1000 # ── Restream outputs (openre-restream-worker) ───────────────── #OPENRE_FFMPEG_PATH=ffmpeg # Static OpenSSL ffmpeg used for rtmps:// destinations (as Live's bin/ffmpeg). #OPENRE_FFMPEG_OPENSSL_PATH= #OPENRE_MAX_DESTINATIONS=10 # Allow destinations on loopback/private/link-local hosts (off: SSRF rule). #OPENRE_DEST_ALLOW_PRIVATE=false #OPENRE_OUTPUT_LOG_LIMIT=200 #OPENRE_RESTART_BASE_MS=5000 #OPENRE_RESTART_MAX_MS=120000 #OPENRE_MAX_RESTARTS=30 #OPENRE_RAPID_CRASH_MS=5000 #OPENRE_RAPID_CRASH_GIVEUP=4 #OPENRE_LIVE_ACK_TIMEOUT_MS=20000 #OPENRE_STABLE_MS=30000 #OPENRE_OUTPUT_START_DELAY_MS=3000 # ── Events (OpenVibe.Events; relay runs in the coordinator) ─── # Unset = relay off (rows still commit and wait). Grant: [openre, events.event.publish, openvibe.events]. #EVENTS_URL=http://127.0.0.1:4300 #EVENTS_PUBLISH=on #EVENTS_RELAY_INTERVAL_MS=1000 # ── Recording requests (OpenVibe.Media) ─────────────────────── MEDIA_URL=http://127.0.0.1:4100 # The Media tenant recordings are filed under ('live' keeps them in the Live channel's gallery). MEDIA_APP_ID=live # Requests carry OpenRestream's Network service token (OV_OAUTH_CLIENT_SECRET; grant # [openre, media.object.upload, openvibe.media] with namespace live). # OPENRE_RECORDING=off disables recording requests. #OPENRE_RECORDING=on #OPENRE_RECORDING_START_DELAY_MS=2000 # ── Restore drills ──────────────────────────────────────────── # OPENRE_DRILL=1 only in an `ovhost drill openre` instance (OpenVibe.Host sets it in the drill's # override file): openre-api serves reads from the restored copy and refuses writes, /play/ and # sign-in; the coordinator and every worker refuse to start; no events, no Media calls. # NEVER set it here in production (scripts/cutover-preflight.js --only env fails if it is). #OPENRE_DRILL= # ── Links ───────────────────────────────────────────────────── #OV_LIVE_URL=https://openvibe.live # OpenVibe Live on by default (server/live-link.js): a person's new stream also gets a slot on their Live channel, # through Live's loopback POST /internal/openre/slots. OPENRE_LIVE_LINK=off turns it off. #OV_LIVE_INTERNAL_URL=http://127.0.0.1:3000 #OPENRE_LIVE_LINK=on # Per-actor limits on a signed-in person's API writes (server/api/actor-limits.js, roadmap WS-R task 4), per minute # and per hour; key rotations, destination tests and new streams have tighter numbers. Services are not counted. #OPENRE_LIMITS_MINUTE=120 #OPENRE_LIMITS_HOUR=3000