A small, boring and reliable HLS-aware IPTV streaming gateway written in Go.
Proxy, rewrite and reliably deliver IPTV streams without running a full IPTV management stack.
StreamGate is deliberately not an IPTV management suite. It does not manage a media library, replace Jellyfin, or try to become another IPTV panel. It focuses on the streaming data plane.
Many IPTV proxies are either thin URL-forwarding layers or complete media-management platforms. StreamGate sits between those two extremes: it keeps the deployment small while treating stream delivery as infrastructure.
- HLS-aware, not extension-aware. Playlists are parsed as a graph of variants, renditions and media resources instead of checking whether a URL ends in
.ts. - Reliability without a control-plane stack. Sources can fail over, concurrent segment fetches are deduplicated and continuous streams can be shared.
- Provider URLs stay private. Clients receive opaque resource IDs rather than user-controlled
?url=proxy endpoints. - Correctness is testable. HLS rewriting, provider parsing, failover, caching and streaming behavior are exercised with unit, golden and end-to-end tests.
- Operationally boring. One static binary, strict YAML, structured logs, Prometheus metrics, graceful shutdown and a hardened container image.
StreamGate currently accepts M3U and Xtream live-TV providers and serves gateway M3U, HTTP/HLS streams, read-only catalog APIs and an optional Xtream-compatible live-TV subset. Transcoding, WebUI, EPG management, DVR, VOD and series management are intentionally out of scope.
Choose one of the two supported installation methods.
The published image supports Linux amd64 and arm64. Docker is the only runtime requirement.
mkdir streamgate && cd streamgate
curl -fsSL https://raw.githubusercontent.com/MrSibe/streamgate/v1.0.0/configs/example.yaml -o config.yamlEdit the provider URL in config.yaml, then run the latest published package:
docker pull ghcr.io/mrsibe/streamgate:latest
docker run -d \
--name streamgate \
--restart unless-stopped \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,size=64m \
--cap-drop ALL \
--security-opt no-new-privileges:true \
-p 8080:8080 \
--mount type=bind,source="$(pwd)/config.yaml",target=/app/configs/config.yaml,readonly \
--mount type=volume,source=streamgate-data,target=/app/data \
ghcr.io/mrsibe/streamgate:latestUse ghcr.io/mrsibe/streamgate:1.0.0 instead when you want to pin this exact release. Docker Compose, NAS and reverse-proxy examples are covered by NAS deployment.
Download the archive for your operating system and architecture from the latest GitHub Release:
- Linux:
linux_amd64.tar.gzorlinux_arm64.tar.gz - Windows:
windows_amd64.ziporwindows_arm64.zip - macOS:
darwin_amd64.tar.gzordarwin_arm64.tar.gz
Each archive contains the binary, example configuration, documentation and license. Verify it with the published checksums.txt, extract it, then edit configs/example.yaml and start StreamGate:
cp configs/example.yaml config.yaml
# Edit config.yaml, then run:
./streamgate -config config.yamlOn Windows, use Copy-Item configs/example.yaml config.yaml, edit the copy, then run .\streamgate.exe -config config.yaml in PowerShell.
Open these endpoints:
Playlist: http://localhost:8080/playlist.m3u
Health: http://localhost:8080/healthz
Metrics: http://localhost:8080/metrics
Channels: http://localhost:8080/api/v1/channels
Load playlist.m3u in VLC, Jellyfin, Emby, Plex or another IPTV client.
flowchart LR
P[M3U / Xtream providers] --> R[Channel registry]
R --> S[Health-aware source selector]
S --> T{Stream type}
T -->|HLS| H[Parse and rewrite playlist graph]
H --> O[Opaque resources]
O --> C[Segment cache and singleflight]
T -->|Continuous HTTP / MPEG-TS| F[Bounded fan-out session]
C --> U[Provider]
F --> U
H --> X[Client]
C --> X
F --> X
For HLS, StreamGate discovers every known URI, resolves it against the current playlist, stores the upstream mapping server-side and returns a short-lived gateway resource URL. Clients never need the original provider URL. HLS clients share segment work through the cache; continuous streams use a separate bounded fan-out model.
Read the detailed architecture and HLS proxy design.
| HLS behavior | Support |
|---|---|
| Master and media playlists | ✅ |
| Relative and absolute URI resolution | ✅ |
| Variant streams and I-frame playlists | ✅ |
| Alternative audio and subtitle renditions | ✅ |
EXT-X-KEY and EXT-X-SESSION-KEY |
✅ |
EXT-X-MAP and fMP4 media |
✅ |
EXT-X-BYTERANGE preservation |
✅ |
| Query parameters | ✅ |
| LL-HLS parts, preload hints and rendition reports | ✅ |
| Content steering and image playlists | ✅ |
The rewriting pipeline is covered by focused tests and golden playlist fixtures. Unknown tags, comments and ordering are preserved, but unknown vendor URI attributes are not guessed or rewritten. Non-HTTP key-system and inline data URIs remain untouched.
- Atomic provider refresh with last-known-good snapshots
- Deterministic multi-provider channel merging by stable
tvg-id - Passive health tracking and bounded active recovery checks
- Health-then-priority source selection and pre-commit failover
- Range and conditional request forwarding
- Bounded in-memory LRU and optional persistent disk cache
singleflightdeduplication for concurrent segment misses- Separate handling for live playlists and cacheable media resources
- One upstream continuous-stream session for matching subscribers
- Bounded subscriber queues that disconnect slow clients without blocking others
- Random 128-bit opaque HLS resource IDs
- SSRF checks during DNS resolution, dialing and every redirect
- Private-network providers require explicit opt-in and hostname allowlisting
- Client cookies and authorization headers are not forwarded implicitly
- URLs, query tokens and credentials are excluded from logs and health output
- Structured JSON logs and request IDs
- Prometheus metrics under the
iptv_prefix - Cache, session, source-health and failover statistics in
/healthz - Optional pprof on a separate, disabled-by-default admin listener
- A standard-library concurrent load generator in
cmd/loadgen
StreamGate is inspired by the IPTV proxy ecosystem, but it deliberately optimizes for a narrow streaming data plane rather than the largest feature set.
| Project | Best suited for |
|---|---|
| StreamGate | A lightweight, HLS-focused streaming gateway with explicit correctness and observability |
| KPTV Proxy | A full-featured IPTV platform with management features |
| Threadfin | Plex, Jellyfin and Emby-oriented M3U/DVR integration |
| iptv-proxy | A straightforward M3U and Xtream reverse proxy |
| StreamShare | IPTV account sharing and multiplexing workflows |
If you need a WebUI, EPG management, DVR workflows or a broad Xtream ecosystem today, a larger platform may be a better fit. Choose StreamGate when the streaming path itself is the part you want to keep small, inspectable and dependable.
StreamGate v1 uses strict YAML with config_version: 1. Unknown fields and missing ${ENV_NAME} references fail at startup. Start from configs/example.yaml, then use these contracts for production deployments:
- Configuration contract
- HTTP API contract
- Xtream compatibility
- Operations and failure modes
- Upgrade policy
Private, loopback and local upstreams are denied by default. See the configuration contract before enabling a LAN provider.
Microbenchmarks cover HLS rewriting, M3U parsing and parallel memory-cache hits. The load generator measures a running gateway with controlled concurrency and reports throughput, failures, bytes and P50/P95/P99 latency.
make bench
go run ./cmd/loadgen \
-url http://localhost:8080/resource/RESOURCE_ID \
-requests 1000 \
-concurrency 20Benchmark numbers are environment-specific. The benchmark methodology documents how to collect reproducible results without turning a development-machine snapshot into a production claim.
The most useful contribution is a real compatibility case. If an M3U, HLS stream or player fails, open an issue with a minimal sanitized playlist, expected behavior and relevant logs. Never include provider credentials or reusable stream tokens.
Before submitting a change:
go test ./...
go test -race ./...
go vet ./...A provider-specific regression should become a minimal fixture and a test whenever possible. Over time, that compatibility corpus is more valuable than another unchecked feature box.
See the roadmap for released milestones and current non-goals.