# 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 `` 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 | `` | | 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`](../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 | `` | | 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: []`).