Files
obs-game-stream-plugin/docs/npm-setup.md
T
bhetherman 0dff4eeee3 Update all docs to reflect current working configuration
- README: update architecture diagram for RTMP+FFmpeg pipeline, add FFmpeg
  install step, fix path descriptions
- obs-setup: switch from WHIP to RTMP output, add FFmpeg prerequisite, fix
  script log messages (MediaMTX starts on load not streaming start), add
  Python setup note, update troubleshooting for game-opus path and audio
- npm-setup: remove Custom Locations GUI instructions (must be empty - all
  locations defined in Advanced tab only), update verify steps to game-opus
  paths, add troubleshooting for WHEP 400/401 causes
- authentik-setup: add section 6 covering both manual account creation and
  self-service enrollment via invite link; clarify User Write stage group
  field is what triggers auto-add (not the invitation form)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 03:46:13 -04:00

4.4 KiB

Nginx Proxy Manager setup

Configures NPM to:

  1. Serve https://stream.hetherman.cloud with TLS + Authentik forward auth, reverse-proxying HTTP traffic to the Windows gaming PC.
  2. Forward public UDP 48189 (WebRTC media) to the gaming PC via an NPM Stream (L4 UDP proxy).

Replace <PC-LAN-IP> with the LAN IP of the Windows gaming PC (e.g., 192.168.50.254).

1. DNS

Create an A / CNAME record for stream.hetherman.cloud pointing to the same DDNS hostname / public IP your other NPM-hosted services use.

2. Router port forwarding

Make sure your router forwards these to NPM (not to the PC directly):

Proto External port Internal target
TCP 443 NPM host, 443
UDP 48189 NPM host, 48189

(TCP 443 is probably already forwarded for your other services; UDP 48189 is the new one for this app.)

3. NPM Proxy Host (HTTP)

In NPM, Hosts -> Proxy Hosts -> Add Proxy Host.

Details tab:

Field Value
Domain Names stream.hetherman.cloud
Scheme http
Forward Hostname <PC-LAN-IP>
Forward Port 48080
Cache Assets off
Block Common Exploits on
Websockets Support on

Custom Locations tab: leave this empty. Do not add any custom location entries here. The /whep/, /hls/, and /v3/ locations are defined in the Advanced tab config below with trailing-slash path stripping. Adding them in the GUI creates duplicate nginx location blocks that cause routing failures.

SSL tab:

  • SSL Certificate: Request a new SSL Certificate with Let's Encrypt
  • Force SSL: on
  • HTTP/2 Support: on
  • HSTS Enabled: optional

Advanced tab: paste the entire contents of config/npm-advanced.conf. This installs:

  • Authentik forward-auth subrequest on all requests
  • /whep/ -> MediaMTX WHEP port 48889 (prefix stripped)
  • /hls/ -> MediaMTX HLS port 48888 (prefix stripped)
  • /v3/ -> MediaMTX API port 19997 (prefix stripped, auth bypassed)
  • /outpost.goauthentik.io -> Authentik internal outpost

Save the proxy host. Wait for the Let's Encrypt certificate to be issued.

4. NPM Stream (UDP L4 proxy)

In NPM, Hosts -> Streams -> Add Stream.

Field Value
Incoming Port 48189
Forward Host <PC-LAN-IP>
Forward Port 48189
TCP off
UDP on

Save. NPM (nginx stream module) now forwards public UDP 48189 to MediaMTX on the gaming PC. This is the path WebRTC media takes after ICE negotiation.

5. Verify

  1. HTTP + auth: from an incognito browser on a different network, visit https://stream.hetherman.cloud. You should be redirected to auth.hetherman.cloud to log in. Log in as a stream-viewers member - you should land back at the stream page (video container + "Stream offline" overlay, assuming you haven't started OBS yet).
  2. Certificate: the padlock icon should show the Let's Encrypt cert.
  3. With OBS streaming, open DevTools on the stream page and confirm:
    • POST /whep/game-opus/whep returns 201
    • GET /hls/game-opus/index.m3u8 returns 200
    • GET /status returns 200 with "ready": true
  4. UDP stream: with OBS streaming and a viewer connected, run tcpdump -n -i any udp port 48189 on the NPM host and confirm packets flow.

Troubleshooting

  • 500 or auth loop on stream.hetherman.cloud: check the outpost proxy_pass in the Advanced config uses the internal Authentik address (http://192.168.50.224:30140) not the public HTTPS URL. Using the public URL causes SSL SNI issues when NPM tries to proxy to itself.
  • WHEP returns 400: the Custom Locations tab in the NPM GUI has /whep, /hls, or /v3 entries. Remove them - these must only be in the Advanced tab config so the trailing-slash path stripping works correctly.
  • WHEP returns 401 / browser shows a Basic Auth dialog: MediaMTX is challenging the viewer directly. Check authInternalUsers in mediamtx.yml has a rule allowing read from any IP (empty ips: []).