Services
This page covers what runs on a single StreamHub node: the six Docker Compose services, why they share the host’s network namespace, the ports involved, and the resource caps that keep one runaway session from taking down the box.
Why host networking
Section titled “Why host networking”network_mode: hostis set on every media-facing service (redis, livekit, ingress, egress, core, caddy).
LiveKit (the SFU), ingress (RTMP/WHIP) and egress (recording) push real-time media over UDP/RTMP
and rely on STUN external-IP detection to advertise the right address to clients. Running them
on the host network — rather than Docker’s bridge network with port mapping — is the reliable,
LiveKit-recommended setup and mirrors a bare-metal deployment. Every service talks to the others
over 127.0.0.1, and Caddy (also host-net) terminates TLS on :80/:443.
Services
Section titled “Services”| Service | Image | What it does | Depends on |
|---|---|---|---|
| redis | redis:7-alpine |
LiveKit ingress/egress coordination and BullMQ job queues used by core. Persists with --appendonly yes. |
— |
| livekit | livekit/livekit-server:v1.8.4 |
The SFU: WebRTC signaling and media fan-out. Config is passed as a literal YAML block via LIVEKIT_CONFIG (note: LIVEKIT_CONFIG, not *_CONFIG_BODY like ingress/egress). |
redis |
| ingress | livekit/ingress:latest |
Accepts RTMP push and WHIP, transcodes, and publishes into a LiveKit room. Also the entry point an RTSP→RTMP relay targets. | redis, livekit |
| egress | livekit/egress:latest |
Room-composite recording: runs a headless Chrome per session to produce MP4/HLS on disk. The heaviest service — roughly one Chrome process per active recording or HLS session. | redis, livekit |
| core | built from deploy/Dockerfile |
streamhub-core: REST API, React SPA, HLS, browser SDK, Prometheus /metrics. Binds 127.0.0.1:3020. |
redis, livekit |
| caddy | caddy:2-alpine |
Single TLS vhost; routes /rtc to LiveKit and everything else to core. Waits for core’s healthcheck before starting. |
core (healthy) |
| Port | Proto | Purpose | Exposure |
|---|---|---|---|
| 80, 443 | tcp | Caddy: dashboard, API, /rtc signaling, auto-TLS |
public |
| 7880 | tcp | LiveKit signaling/API | public (proxied at /rtc) |
| 7881 | tcp | LiveKit WebRTC TCP fallback (ICE/TCP) | public |
| 7882 | udp | LiveKit WebRTC media — single mux port | public |
| 1935 | tcp | Ingress: RTMP ingest | public |
| 8080 | tcp | Ingress: WHIP ingest | public |
| 3478 | udp | Embedded TURN (optional; enable with domain + cert) | public |
| 3020 | tcp | streamhub-core | local only (proxy target) |
| 6379 | tcp | redis | local only |
| 6789 | tcp | LiveKit native Prometheus | local (scraped by Prometheus) |
| 6790 | tcp | Ingress native Prometheus | local |
| 6791 | tcp | Egress native Prometheus | local |
| 9090 | tcp | Ingress HTTP relay (internal) | local |
Each LiveKit-family service needs its own Prometheus port (6789/6790/6791) because they all share the host network namespace — two processes can’t bind the same port.
Resource caps
Section titled “Resource caps”Ingress and egress transcode and composite media, which makes them the services most likely to
consume unbounded CPU/RAM under a bad session. Both are capped via Compose v2’s non-swarm
mem_limit/cpus keys, tunable through .env:
| Service | Default cap | Why |
|---|---|---|
| ingress | mem_limit: 1g, cpus: 1.5 (INGRESS_MEM_LIMIT / INGRESS_CPUS) |
Transcodes RTMP/WHIP; bounds a runaway publishing session. |
| egress | mem_limit: 2g, cpus: 2 (EGRESS_MEM_LIMIT / EGRESS_CPUS), plus shm_size: 1gb and cap_add: [SYS_ADMIN] |
Runs a headless Chrome to composite each room; Chrome’s sandbox needs SYS_ADMIN and shared memory. RAM can balloon under multi-track/high-res rooms — this is the single biggest OOM risk on a small host. Defaults target an 8GB/8-core box; raise for heavier rooms. |
Egress also mounts the same DATA_DIR path as core (${STREAMHUB_HOST_DATA_DIR:-./data} on the
host):
Deploy shapes
Section titled “Deploy shapes”Two supported shapes, same architecture underneath:
- Docker Compose + Caddy (default, quick-install) —
redis,livekit,ingress,egress,core,caddyas shown above.docker compose up -d; Caddy gets certs automatically. Requires a Linux host with a public IP (host networking for UDP media + STUN). - systemd + nginx + certbot (plain-server) — LiveKit and core run as systemd units,
ingress/egress stay as Docker containers, redis runs natively, nginx + certbot handle TLS.
This is what the production host (
stream01) runs.
Both shapes route the same way (see Overview) and share the same core image — only the process supervisor and TLS termination differ.