Ports, Services & API Details
This document covers what ports the system uses, what each Docker container does, and a full reference of the internal API.
1. Docker Services & Internal Ports
The stack has 3 main services located within the Docker network shopstream_default.
broadcaststream-mediamtx(The Ingester):- Ingest Protocol:
RTMP, WHIP, RTSP - Port 1935 (TCP): Public RTMP Port. Used by OBS, vMix, and mobile broadcast software.
- Port 8889 (TCP): WebRTC/WHIP ingest port. Proxied by NGINX internally.
- Port 8554 (TCP): Internal RTSP protocol port. Used internally by
transcode.shto grab the raw video viartsp://localhost:8554/....
- Ingest Protocol:
broadcaststream-api(The State Manager):- Internal Port 4000 (TCP): Runs Express.js. Serves as a unified state database using an in-memory
Mapthat tracks exactly who is broadcasting. This port is completely blocked to the outside internet.
- Internal Port 4000 (TCP): Runs Express.js. Serves as a unified state database using an in-memory
broadcaststream-nginx(The Cache & Tunnel):- Public Port 8080 (TCP): The only port necessary for Cloudflare tunnels. Any request to standard HTTP endpoints flows through this, including static
.htmlfiles in/public,.tsvideo chunks in/var/www/hls, and reverse-proxying API endpoints.
- Public Port 8080 (TCP): The only port necessary for Cloudflare tunnels. Any request to standard HTTP endpoints flows through this, including static
2. API Endpoints Reference
The Node.js Express API (broadcaststream-api) acts as the state manager for the entire application.
GET /health
- Visibility: Public via Cloudflare (
http://.../api/health) or NGINX (:8080/api/health). - Purpose: Orchestrator readiness. Used internally by Docker Compose's
HEALTHCHECKto ensure the Node instance is ready to receive requests. - Return: JSON
{"status": "ok", "service": "broadcaststream-api"}
GET /streams
- Visibility: Public via Cloudflare / NGINX reverse proxy (
/api/streams). - Purpose: Used by the Viewers (
viewer.html). Returns a JSON array of every user currently broadcasting. NGINX enables wide-open CORS so any frontend app on the internet can call this endpoint. - Return Structure:json
{ "success": true, "data": { "count": 1, "streams": [ { "streamKey": "test", "startedAt": "2026-02-26T...", "clientIp": "192.168.1.5", "masterPlaylistUrl": "http://localhost:8080/hls/test/master.m3u8", "qualities": [ ... ] } ] } }
POST /webhook/on-publish
- Visibility: Internal completely. NGINX refuses to proxy this. Only
broadcaststream-mediamtxcan call this. - Payload:
application/x-www-form-urlencodedname: The stream key (e.g. "test").remoteAddr: Broadcaster IP address.
- Purpose: When
on_publish.shsuccessfully begins creating video files, it POSTs this webhook. The API adds the stream to its memoryMapmaking the stream globally visible.
POST /webhook/on-unpublish
- Visibility: Internal completely.
- Payload:
application/x-www-form-urlencoded(name,remoteAddr). - Purpose: When the stream disconnects,
on_unpublish.shtriggers this. The API instantly removes the session from theMap, causingviewer.htmlpages to stop seeing the "test" stream.