# OpenVibe.Live Configuration # Copy this to .env and fill in your values. # Production env file lives at /etc/openvibe/live.env (mode 0600). # Platform Admin — username of the site owner (applied on first setup only) ADMIN_USERNAME=admin ADMIN_PASSWORD=changeme123 # Home-page "Star of OpenVibe" spotlight — a username. The `star_streamer` site setting # (admin settings API) overrides this. Non-English streamers get their bio auto-translated. # STAR_STREAMER=JapaneseOldGuy # Multilingual whisper.cpp model for non-English streamers (chat + live captions + timeline). # The default *.en models can only emit English. Download e.g. ggml-base.bin / ggml-small.bin # (no ".en") into ~/whisper.cpp/models and point this at it. Without it, non-English # channels keep using the English model and live captions stay hidden. # WHISPER_MODEL_MULTI=/home/openvibe/whisper.cpp/models/ggml-small.bin # Speech-to-text engine for English and 24 other European languages: NVIDIA Parakeet TDT 0.6B v3 through # whisper.cpp's parakeet-cli (more accurate than whisper base.en and fast enough for live on 4 cores). Used # when both files exist; other languages, and any Parakeet failure, go to whisper. ASR_ENGINE=whisper forces whisper. # Model: https://huggingface.co/ggml-org/parakeet-GGUF (ggml-parakeet-tdt-0.6b-v3-q8_0.bin). # PARAKEET_BIN=/home/openvibe/whisper.cpp/build/bin/parakeet-cli # PARAKEET_MODEL=/home/openvibe/whisper.cpp/models/ggml-parakeet-tdt-0.6b-v3-q8_0.bin # ASR_ENGINE=whisper # OpenVibe.AI (roadmap Wave 13, WS-O task 2). Every AI call Live makes (chat AI, moments, paste/frame # analysis, overviews, translation, recaps, slogans, arena, AI viewers) is a workflow run on the AI # service, with a service token for audience openvibe.ai (grants ai.run.create, ai.run.read and # ai.credential.manage for client `live`). Provider keys, a streamer's own included, live in the AI # service; Live calls a provider only to test a key a streamer typed and has not saved yet. The admin # ai_enabled switch and the local daily cap still apply to other AI workflows. Live stream transcription stays here. # AI_SERVICE=off turns AI off entirely. #AI_SERVICE=off #OV_AI_INTERNAL_URL=http://127.0.0.1:4700 # Finished VOD/clip analysis: local (current frame/whisper path) or ai (one media.analyze run). #LIVE_MEDIA_ANALYSIS=local # How long one call waits for media.analyze before re-joining the run 15 minutes later (ms). #LIVE_MEDIA_ANALYSIS_WAIT_MS=60000 # Server PORT=3000 HOST=0.0.0.0 NODE_ENV=development BASE_URL=http://localhost:3000 # JWT Secret (generate a strong random string) JWT_SECRET=change-me-to-a-random-secret-at-least-32-chars # Database # Production requires both URLs. Development without DATABASE_URL uses PGlite under DATA_DIR. # DATABASE_URL=postgres://live_runtime:password@localhost:5432/ov_live # DATABASE_DIRECT_URL=postgres://live_owner:password@localhost:5432/ov_live # Every file Live writes lives under one data directory (default ./data, relative to the working # directory). The *_PATH variables below still move single locations (server/paths.js). # DATA_DIR=./data # Restore-drill mode, set only by `ovhost drill live` (OpenVibe.Host docs/restore-drills.md): reads # only from a restored copy; refuses to start unless DATA_DIR is outside the checkout, # HOST is loopback and PORT is not 3000. Starts no jobs, sockets or listeners but its HTTP port and # makes no outbound connection (server/drill.js). # LIVE_DRILL=1 # ── OpenVibe.Network (SSO provider + OpenCoins wallet + URL registry) ───────── # Public base of the identity provider (issuer for RS256 JWTs) OV_NETWORK_URL=https://openvibe.network # Internal (server-to-server) base — wallet API + /internal/* endpoints OV_NETWORK_INTERNAL_URL=http://127.0.0.1:4000 # OAuth client credentials (client id `live` is seeded in the Network DB) OV_OAUTH_CLIENT_ID=live OV_OAUTH_CLIENT_SECRET= # OpenVibe.Events (durable events): stream lifecycle is published through Live's outbox with the # OAuth client above (grant events.event.publish). Unset = off. EVENTS_PUBLISH=off also disables it. #EVENTS_URL=http://127.0.0.1:4300 # Go-live notifications come only from Network's live.stream.started consumer (compatibility register C-85). # OpenRestream (roadmap Wave 7): the ingest/restream authority. Unset = off, and every stream slot # is ingested by Live exactly as before. When set, an admin can switch one slot at a time # (PUT /api/admin/openre/managed/:id/ingest-authority); RTMP, WHIP and JSMPEG move with it. Live's service principal # (the OAuth client above) needs openre.stream.read, openre.stream.write, openre.key.rotate and # openre.session.read on audience openvibe.openre. #OPENRE_URL=http://127.0.0.1:4500 #OPENRE_PUBLIC_URL=https://openre.stream # Secret of Live's OpenVibe.Events subscription to openre.session.* (endpoint # http://127.0.0.1:3000/internal/openre-events); sessions are mirrored into `streams` from it. #OPENRE_EVENTS_SECRET= # Path to the Network's RS256 public key (offline JWT verification) #OV_NETWORK_PUBLIC_KEY=./data/keys/openvibe-network-public.pem # ── Per-actor limits on API writes (server/net/actor-limits.js, roadmap WS-R task 4) ── # Writes by a signed-in person or their hbt_ token, per minute and per hour; named routes (clips, pastes, follows, # stream keys, uploads, comments, money, AI key tests) have tighter numbers of their own. Reads, signed-out writes # and device traffic are not counted here (the per-address limits apply). #LIVE_LIMITS_MINUTE=120 #LIVE_LIMITS_HOUR=3000 # ── OpenVibe.Media (VODs / clips / pastes / thumbnails service) ─────────────── # Internal API base (server-to-server, Bearer service token for openvibe.media) MEDIA_URL=http://127.0.0.1:4100 # Public serving base (playback/thumbnail/paste URLs handed to browsers) MEDIA_PUBLIC_URL=https://openvibe.media # Tenant id — the namespace Live's service token is scoped to MEDIA_APP_ID=live # Media (VOD/clip/paste) calls authenticate with Live's service token from # OV_OAUTH_CLIENT_ID / OV_OAUTH_CLIENT_SECRET (audience openvibe.media, namespace live). # Media outcomes (vod/clip ready or failed, storage alerts) arrive over OpenVibe.Events: the secret of # Live's subscriptions to media.vod.* / media.clip.* / media.storage.* (endpoint # http://127.0.0.1:3000/internal/media-events, created by scripts/subscribe-media-events.js; # 32+ characters, openssl rand -hex 32). Without it Live receives no Media outcomes. #MEDIA_EVENTS_SECRET= # ── RTMP ingest ─────────────────────────────────────────────────────────────── RTMP_PORT=1935 RTMP_CHUNK_SIZE=60000 # Public ingest hostname shown to streamers (rtmp:///live) RTMP_HOST=ingest.openvibe.live # JSMPEG Relay JSMPEG_VIDEO_PORT=9710 JSMPEG_AUDIO_PORT=9711 # WebRTC / Mediasoup MEDIASOUP_LISTEN_IP=0.0.0.0 MEDIASOUP_ANNOUNCED_IP=127.0.0.1 MEDIASOUP_MIN_PORT=10000 MEDIASOUP_MAX_PORT=10100 WEBRTC_PORT=4443 # TURN Server (coturn) — required for NAT traversal TURN_URL=turn:turn.openvibe.live TURN_USERNAME= TURN_CREDENTIAL= # Preferred: coturn `use-auth-secret` + `static-auth-secret=` — every ICE list then carries a # credential that expires after an hour instead of the static pair above. TURN_AUTH_SECRET= # PayPal (for Vibes cashout — Vibes stay Live-local) PAYPAL_CLIENT_ID= PAYPAL_CLIENT_SECRET= PAYPAL_MODE=sandbox # Vibes MIN_CASHOUT_BUCKS=500 ESCROW_HOLD_DAYS=14 # Live-local media state (VOD/clip/paste FILES live in OpenVibe.Media now) # Ephemeral live-stream thumbnails LIVE_THUMBS_PATH=./data/live-thumbs # Song-request media cache (yt-dlp downloads for the watch-party queue) # lives under ./data/media/cache — no env needed. # Max size of a browser VOD upload forwarded to Media MAX_VOD_SIZE_MB=2048 # Word Filter UNSAFE_WORDS_PATH=./server/chat/unsafe-words.txt # Ops alerts (optional) — Discord-compatible webhook that receives storage alerts relayed # from OpenVibe.Media (drain stalled / disk critical / recovered). Can also be set from the # admin settings as `ops_alert_webhook_url`. OPS_ALERT_WEBHOOK_URL= # Pastes are served by openvibe.community (Live 301s /p/:slug there and links straight to it) OV_COMMUNITY_URL=https://openvibe.community # Community's loopback API: pastes and VOD/clip comments, which are # Community threads (server/comments-client.js; Live's service token needs community.comment.write # and community.comment.moderate on openvibe.community) OV_COMMUNITY_INTERNAL_URL=http://127.0.0.1:4200 # OpenVibe.Chat runs chat (/ws/chat and /api/chat|dm|tts|sounds; nginx sends them there). Live delivers its # own chat producers (AI viewer lines, donations and alerts, relay and RobotStreamer chat, cards, moderation, # cache hints, presence) through Chat's typed ingress /internal/chat/* and reads chat stats, queues and history # from Chat (server/chat/chat-delivery.js, chat-reads.js; Live's principal needs chat.message.send, # chat.event.publish, chat.moderation.write, chat.cache.invalidate, chat.presence.read and the chat.*.read # capabilities for audience openvibe.chat). There is no switch: without OV_OAUTH_CLIENT_SECRET chat is inert. OV_CHAT_INTERNAL_URL=http://127.0.0.1:4400 # Bot panel embed (server/bot/): "1" lets a channel owner bind the channel to an OpenVibe.Bot robot # (PUT /api/streams/channel/:username/bot) and adds bot_embed { enabled, robot_id, url } to the channel # JSON; off, the route answers 404 and the JSON is unchanged. Live never calls Bot to bind: the robot # owner's embed_public toggle in Bot decides what the embed shows. Turn-on order: Bot deployed with # GET /panel/:id/embed and its BOT_EMBED_ORIGINS including this site's origins → set this → bind a channel. #LIVE_BOT_EMBED=1 # Bot's origin for the embed URL (/panel//embed): a bare https origin, or # http://localhost* outside production; anything else falls back to the default with a warning. #LIVE_BOT_URL=https://openvibe.bot # Voice/video calls are OpenVibe.Chat's (no setting): nginx sends /ws/call and the call routes there, and Live # creates/removes stream voice channels in Chat on go-live and stream end (server/streaming/calls-authority.js). # OpenVibe.Billing is the money ledger (since 2026-10-17; ADR-012): Live calls it for checkouts, donations, cashouts, # recycling, subscriptions, balances and entitlements with its service token (audience openvibe.billing). There is no # other mode (BILLING_AUTHORITY is no longer read). OV_BILLING_INTERNAL_URL=http://127.0.0.1:4600 OV_QUEST_INTERNAL_URL=http://127.0.0.1:4980 OV_BILLING_PUBLIC_URL=https://billing.openvibe.network # Cosmetics live in OpenVibe.Inventory (ADR-054 §8): live.* items issued by service:live, Live's item ids as aliases. # Live reads and writes them with its service token (audience openvibe.inventory) acting for the person. #INVENTORY_URL=http://127.0.0.1:5030 # OV_BILLING_TIMEOUT_MS=8000 OV_BENCH_INTERNAL_URL=http://127.0.0.1:5230 # The Companion extension's side panel frames /embed/agent: set this to the Chrome Web Store id once the extension # is published (exactly chrome-extension:// + 32 letters a-p; comma-separate several; anything else is ignored). #AGENT_EMBED_EXTENSION_ORIGINS=chrome-extension://bjcjcfcecpkkmfndegkjekoipdmbgakd