180e95f74dae39e54a50871db779167e65484f5f
- Switch OBS output to RTMP; add FFmpeg AAC->Opus transcoding via MediaMTX runOnReady so WebRTC can carry audio (WebRTC requires Opus, not AAC) - Enable RTSP on localhost so FFmpeg reads game path without publisher conflict; viewers connect to game-opus path (H264+Opus) - Fix WHEP/HLS path prefix stripping in NPM advanced config; move all custom locations (/whep, /hls, /v3) out of NPM GUI and into advanced conf so trailing-slash proxy_pass correctly strips prefixes before hitting MediaMTX - Fix MediaMTX API port 49997->19997 (49997 was in Windows ephemeral range) - Add /status proxy endpoint to OBS HTTP server so frontend can poll stream readiness without hitting /v3/ through NPM where auth_request blocked it - Fix authInternalUsers: split publish (localhost only) from read (any IP) so WHEP viewers are not challenged with Basic Auth by MediaMTX - Remove muted attribute from video element; show unmute/play button on autoplay block so viewers get audio after one click - Fix webrtcAdditionalHosts to include LAN IP 192.168.50.254 - Fix hlsAllowOrigin->hlsAllowOrigins deprecation warning - Move MediaMTX/HTTP server startup to script_load (not streaming started) so MediaMTX is ready before OBS attempts RTMP connection - Log MediaMTX output to bin/mediamtx.log for easier debugging Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
game-stream-app
Low-latency browser-based game streaming to a small group of friends, gated by Authentik authentication.
- Streamer: Windows PC with an NVIDIA GPU running OBS Studio.
- Viewers: up to ~6 friends, any modern browser, no client install.
- Auth: Authentik forward auth at the Nginx Proxy Manager (NPM) edge.
- Transport: WebRTC (WHEP) for low latency, with LL-HLS fallback.
- Latency target: ~200 ms over WebRTC, ~1-2 s over LL-HLS fallback.
How it works
OBS Studio (NVENC, WHIP out)
-> MediaMTX (localhost) ---> WHEP / HLS / API
-> Frontend HTTP server (localhost:8080)
-> NPM (TLS, Authentik forward auth, reverse proxy)
-> Friend's browser
Everything on the gaming PC (MediaMTX, HTTP server, Windows Firewall rule for
the WebRTC UDP port) is spawned and torn down by an OBS Python script -
obs-script/game_stream.py. You just click Start Streaming in OBS and the
whole pipeline comes up; click Stop Streaming and it all goes away.
Repository layout
| Path | Purpose |
|---|---|
config/mediamtx.yml |
MediaMTX configuration (WHIP in, WHEP/HLS out, locked-down) |
config/npm-advanced.conf |
Authentik forward-auth snippet for the NPM Advanced tab |
obs-script/game_stream.py |
OBS script: lifecycle, HTTP server, firewall toggle |
frontend/index.html |
Viewer page |
frontend/js/player.js |
WHEP client with HLS fallback |
frontend/js/app.js |
Status polling and DOM glue |
frontend/css/style.css |
Dark theme |
scripts/install.ps1 |
Downloads MediaMTX, creates the Windows Firewall rule |
docs/authentik-setup.md |
Authentik proxy provider + group configuration |
docs/npm-setup.md |
NPM proxy host + stream (UDP) configuration |
docs/obs-setup.md |
OBS encoder + WHIP output settings |
Setup at a glance
- Clone this repo onto the Windows gaming PC.
- Install MediaMTX and the firewall rule: open an elevated PowerShell in
the repo root and run
.\scripts\install.ps1. - Configure Authentik - see
docs/authentik-setup.md. - Configure NPM - see
docs/npm-setup.md. - Configure OBS - see
docs/obs-setup.md, then addobs-script/game_stream.pyvia Tools -> Scripts. - Click Start Streaming in OBS. Friends can now open
https://stream.hetherman.cloud, log in with Authentik, and watch.
Security posture
- TLS terminates at NPM with Let's Encrypt.
- Every request is gated by Authentik forward auth before it reaches the frontend, WHEP signaling, HLS, or the MediaMTX API.
- MediaMTX only accepts publishers from
127.0.0.1- nobody on the public internet can hijack the stream. - The UDP port used for WebRTC media is opened on the Windows Firewall only while streaming is active (toggled by the OBS script). Even though NPM and the router still forward the port, the OS silently drops packets between streams, so there is no exposed listener.
- WebRTC media is DTLS-encrypted SRTP. An attacker who hits the UDP port without an Authentik-authenticated WHEP session cannot decrypt or inject media.
- Removing a friend from the Authentik
stream-viewersgroup revokes their access on the next auth_request subrequest (within seconds).
License
MIT
Description
Languages
JavaScript
39.4%
Python
39.1%
PowerShell
9.6%
CSS
8.6%
HTML
3.3%