Überblick
Dieses Projekt ist eine selbst gehostete Live-Streaming-Plattform, die es ermöglicht, Video-Streams von OBS Studio zu empfangen, in ein für Web-Browser optimiertes Format zu konvertieren und an Zuschauer auszuliefern. Die Infrastruktur basiert auf bewährten Open-Source-Technologien und bietet eine Low-Latency-Lösung für Live-Übertragungen.
Projekt-Kontext
Diese Streaming-Infrastruktur wurde speziell für den Grundschultag 2025 der Realschule Plus und FOS Mendig - Laacher-See-Schule entwickelt und eingesetzt.
Den feierlichen Abschluss des Grundschultages bildete das Konzert, in dem Schülerinnen und Schüler ihre musikalischen Beiträge präsentierten. Aufgrund des begrenzten Platzangebots am Konzertort entstand die Herausforderung, dass nicht alle interessierten Eltern, Grundschüler und Gäste vor Ort teilnehmen konnten.
Die Lösung: Eine Live-Übertragung des Konzerts in die Schulmensa. Die Streaming-Infrastruktur ermöglichte es, das Konzert zeitgleich an einen zweiten Standort zu übertragen, sodass deutlich mehr Gäste an diesem besonderen Event teilnehmen konnten. Die selbst gehostete Lösung gewährleistete dabei vollständige Kontrolle über die Datenströme und erfüllte alle Datenschutzanforderungen der Schule. Die niedrige Latenz von 4–8 Sekunden sorgte für eine nahezu echtzeit Übertragung zwischen Konzertort und Mensa.
Ursprünglich war geplant, das Signal über NDI (Network Device Interface) zu übertragen – eine Technologie, die Video- und Audiodaten mit sehr geringer Latenz direkt über das lokale Netzwerk streamt. Aufgrund der bestehenden Schulnetzwerk-Infrastruktur war dies jedoch nicht möglich, da NDI-Streams bestimmte Netzwerkprotokolle und Broadcast-Kommunikation erfordern, die vom IT-Dienstleister aus Sicherheitsgründen nicht freigeschaltet werden konnten.
System-Architektur
Die Streaming-Infrastruktur besteht aus zwei Hauptkomponenten: dem Stream-Ingest (Empfang von OBS Studio) und dem Stream-Playback (Auslieferung an Zuschauer). Beide Prozesse laufen über NGINX mit spezialisiertem RTMP-Modul.
1. Stream-Ingest Pipeline (OBS → HLS-Dateien)
┌───────────────────────────────────────────────────────────────────┐
│ OBS Studio │
│────────────────────────────────────────────────────────────────── │
│ Server: rtmp://STREAM-SERVER/ingest?key=XXXXXXXXXXXX │
│ Streamkey: YYYYYYY │
└──────────────┬────────────────────────────────────────────────────┘
│ (RTMP Publish)
▼
Port 1935 (RTMP)
┌───────────────────────────────────────────────────────────────────┐
│ NGINX (RTMP Module) │
│────────────────────────────────────────────────────────────────── │
│ application ingest { │
│ on_publish http://127.0.0.1:8080/rtmp-auth; <──┐ │
│ push rtmp://127.0.0.1/live/hls; │ │
│ } │ │
│ │ │
└───────────────────────────────────────────────────────┼───────────┘
│
│ (HTTP POST)
▼
Port 8080 (FastCGI)
┌────────────────────────────────┐
│ PHP Script (Auth) │
│ /var/www/script/rtmp-auth.php │
│ │
│ - prüft Key = XXXXXXXXXXXX │
│ - erlaubt/verbietet Publish │
└────────────────────────────────┘
│
200 OK (Key korrekt) │
▼
interne Weiterleitung per "push"
┌──────────────────────────────────────────────────────────────────┐
│ NGINX (RTMP Module) │
│──────────────────────────────────────────────────────────────────│
│ application live { │
│ hls on; │
│ hls_path /var/www/hls; │
│ hls_fragment 2; │
│ hls_playlist_length 6; │
│ } │
└──────────────────────────────────────────────────────────────────┘
│
│ (Erzeugt HLS-Dateien)
▼
┌──────────────────────────────────────────────────────────────────┐
│ /var/www/hls/ │
│ ├── hls.m3u8 ← Playlist (HLS Manifest) │
│ ├── hls-00001.ts ← Videosegment 1 │
│ ├── hls-00002.ts ← Videosegment 2 │
│ └── ... │
└──────────────────────────────────────────────────────────────────┘
2. Stream-Playback Pipeline (Browser → Video)
┌──────────────────────────────────────────────────────────────────┐
│ Web-Browser │
│───────────────────────────────────────────────────────────────────│
│ Lädt: https://STREAM-SERVER/index.html │
│ HTML enthält <video> mit src="/hls/hls.m3u8" │
│ Hls.js streamt Segmente (HTTP-Requests) │
└──────────────┬────────────────────────────────────────────────────┘
│ (HTTPS Requests)
▼
Port 443 / 80 (HTTP/S)
┌──────────────────────────────────────────────────────────────────┐
│ NGINX (HTTP Server) │
│──────────────────────────────────────────────────────────────────│
│ location /hls { │
│ root /var/www; │
│ types { │
│ application/vnd.apple.mpegurl m3u8; │
│ video/mp2t ts; │
│ } │
│ add_header Cache-Control no-cache; │
│ } │
└──────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ /var/www/hls/hls.m3u8 → Playlist │
│ /var/www/hls/hls-00001.ts, hls-00002.ts, ... │
└──────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ Videoausgabe im Browserplayer │
│──────────────────────────────────────────────────────────────────│
│ Hls.js lädt Segmente → decodiert → HTML5 <video> zeigt Stream │
│ Verzögerung: ca. 4–8 Sekunden │
└──────────────────────────────────────────────────────────────────┘
Technische Komponenten
NGINX mit RTMP-Modul
Das Herzstück der Infrastruktur ist NGINX mit dem nginx-rtmp-module. Dieses Modul erweitert NGINX
um die Fähigkeit, RTMP-Streams zu empfangen und zu verarbeiten. Die Konfiguration umfasst:
- Ingest Application: Nimmt RTMP-Streams von OBS Studio entgegen und leitet sie nach erfolgreicher Authentifizierung weiter
- Live Application: Konvertiert RTMP-Streams in HLS-Format und speichert die Segmente auf dem Dateisystem
- HLS-Konfiguration: Fragment-Länge von 2 Sekunden für niedrige Latenz, Playlist-Länge von 6 Sekunden
PHP-Authentifizierung
Bevor ein Stream akzeptiert wird, validiert ein PHP-Script die Authentifizierung. Das Script empfängt HTTP POST-Requests
von NGINX (via on_publish Hook) und prüft den übermittelten Token. Nur bei einem HTTP 200-Status erlaubt
NGINX das Publishing des Streams.
- Token-basierte Authentifizierung über URL-Parameter
- Integration via FastCGI (Port 8080)
- Schutz vor unbefugtem Stream-Publishing
HLS (HTTP Live Streaming)
HLS ist das Standardprotokoll für adaptive Streaming-Übertragungen im Web. Die Vorteile:
- Browser-native Unterstützung (Safari) oder via Hls.js (Chrome, Firefox)
- Durchläuft Firewalls problemlos (nutzt HTTP/HTTPS)
- Adaptives Streaming möglich (verschiedene Qualitätsstufen)
- Segmentierung ermöglicht einfaches Caching und CDN-Integration
Web-Player
Der Web-Player basiert auf dem HTML5 <video>-Element in Kombination mit Hls.js, einer JavaScript-Library
für HLS-Playback in Browsern ohne native HLS-Unterstützung. Dies ermöglicht universelle Kompatibilität über alle modernen Browser hinweg.
Herausforderungen & Lösungen
Herausforderung: Stream-Latenz minimieren
Problem: Standard-HLS-Konfigurationen führen oft zu Latenzen von 20-30 Sekunden, was für interaktive Streaming-Anwendungen ungeeignet ist.
Lösung: Durch die Optimierung der HLS-Parameter (hls_fragment: 2s, hls_playlist_length: 6s)
konnte die Latenz auf 4-8 Sekunden reduziert werden - ein guter Kompromiss zwischen Latenz und Buffering-Stabilität.
Herausforderung: Sicherheit bei Stream-Publishing
Problem: RTMP-Server sind standardmäßig offen und können von jedem zum Publishing verwendet werden, was zu Missbrauch führen kann.
Lösung: Integration eines PHP-Authentifizierungsscripts, das über den on_publish-Hook
vor jedem Stream-Start ausgeführt wird. Nur mit validem Token wird der Stream akzeptiert.
Herausforderung: Browser-Kompatibilität
Problem: Nicht alle Browser unterstützen HLS nativ - insbesondere Chrome und Firefox erfordern zusätzliche JavaScript-Libraries.
Lösung: Einsatz von Hls.js, einer weit verbreiteten JavaScript-Library, die HLS in allen modernen Browsern ermöglicht. Die Library führt automatisches Feature-Detection durch und fällt auf native Implementierung zurück, wenn verfügbar.
Herausforderung: MIME-Type-Konfiguration
Problem: Browser erkennen .m3u8 und .ts Dateien nicht automatisch als Video-Content, was zu Download-Dialogen statt Streaming führen kann.
Lösung: Explizite MIME-Type-Konfiguration in NGINX für application/vnd.apple.mpegurl
(.m3u8) und video/mp2t (.ts), kombiniert mit Cache-Control: no-cache Headers für Live-Content.
Ergebnisse & Learnings
Technische Ergebnisse
- Latenz: 4-8 Sekunden End-to-End-Verzögerung (OBS → Browser)
- Stabilität: Kontinuierlicher Betrieb ohne Ausfälle
- Skalierbarkeit: Multiple parallele Streams möglich (durch Streamkey-Separation)
- Sicherheit: Token-basierte Authentifizierung verhindert unbefugtes Publishing
- Kompatibilität: Funktioniert in allen modernen Browsern (Chrome, Firefox, Safari, Edge)
Wichtigste Learnings
- Die Wahl der richtigen Protokolle ist entscheidend: RTMP für Ingest (universelle OBS-Unterstützung), HLS für Playback (Browser-Kompatibilität)
- Authentifizierung sollte immer auf Server-Seite implementiert werden - Client-seitige Validierung ist nicht ausreichend
- Bei Live-Streaming ist Latenz immer ein Trade-off: Kleinere Segmente = niedrigere Latenz, aber höhere CPU-Last und mehr HTTP-Requests
- NGINX ist extrem performant für Video-Streaming - ein einzelner Server kann problemlos Dutzende parallele Streams handhaben
- Proper MIME-Type- und Caching-Konfiguration ist essentiell für reibungslose Browser-Playback-Erfahrung
Technologie-Stack
NGINX
Webserver mit RTMP-Modul für Stream-Handling
RTMP
Real-Time Messaging Protocol für Stream-Ingest
HLS
HTTP Live Streaming für Browser-Playback
PHP
Server-seitige Authentifizierung
Hls.js
JavaScript-Library für HLS-Playback
Linux
Server-Betriebssystem (Ubuntu)