Dashboard
System overview and metrics
Loading groups...
System Roles
Super Admin
System RoleOrganization Admin
System RoleCustom Roles
Broadcaster
Custom RoleViewer
Custom RoleModerator
Custom RolePricing Plans
Starter
- β 5 Users
- β 2 Concurrent Streams
- β 720p Quality
- β 50GB Storage
- β Email Support
- β Custom Branding
- β API Access
Professional
- β 25 Users
- β 5 Concurrent Streams
- β 1080p Quality
- β 200GB Storage
- β Priority Support
- β Custom Branding
- β API Access
Enterprise
- β Unlimited Users
- β 20 Concurrent Streams
- β 4K Quality
- β 1TB Storage
- β 24/7 Support
- β Custom Branding
- β Full API Access
Custom
- β Custom User Limits
- β Custom Stream Limits
- β Custom Quality
- β Custom Storage
- β Dedicated Support
- β White Label
- β SLA Guarantee
Recent Subscriptions
Payment Gateway Configuration
Invoice Settings
Company Details (for Invoices)
Notification Settings
Auto-Billing
CPU Usage Over Time
Memory Usage Over Time
Network Throughput
Per-Service Resource Usage
Auto-refreshing every 5sFirewall Status
SSL Certificate
WAF Status
Blocked IPs
Security Events
Today's Security Summary
WAF Status
Current Mode
Blocked Today
Total Blocked
Attack Types
Protection Rules
Add Custom Rule
IP Management
/opt/streaming-server/waf/config/coraza-main.conf
Audit log: /opt/streaming-server/waf/logs/audit.log
Upload IP Whitelist
Manage IP addresses allowed to upload files and perform sensitive operations
| # | IP Address | Type | Actions |
|---|---|---|---|
| Loading whitelisted IPs... | |||
/opt/streaming-server/configs/whitelist_ips.json
Auto-reload: Enabled (5 second interval)
π¨ Customize UI
Customize the appearance and styling of the admin interface
Button Styling
Section Colors
Container Styling
Typography
Borders & Effects
Table Styling
Customization Actions
Customize the appearance of slide-down notifications. Changes are saved to your profile and persist across sessions.
Colors
Dimensions
Position
Text & Padding
Behavior
Live Preview
Streaming Settings
Camera & Input Settings
WebRTC Settings
SRS Server Settings
Security & Authentication
Rate Limiting & Performance
Service Management Configuration
Configure which services appear in the Dashboard Service Management widget. Add, remove, or edit services that should be monitored.
Streaming Configuration
Server, encoding, HLS, and storage settings from streaming.config.json
Server Settings
Domain Settings
Encoding Settings
HLS Settings
Recording Settings
Session Settings
Rate Limiting - Auth
Rate Limiting - API
Admin Dashboard
ABR Transcoding Configuration
Adaptive Bitrate quality profiles from abr.config.json
Quality Profiles
Quality profiles for multi-bitrate streaming
Encoding Defaults
Audio Settings
IP Whitelist Configuration
Allowed IP addresses for upload operations from whitelist_ips.json
Allowed IP Addresses
IP addresses that are allowed to upload content
SRS Server Configuration
View-only: SRS media server configuration from srs.conf
Loading SRS configuration...
sudo nano /opt/streaming-server/configs/srs.conf then sudo systemctl restart srs
Web Server Configuration
View-only: Caddy web server configuration from /etc/caddy/Caddyfile
Loading Caddy configuration...
sudo nano /etc/caddy/Caddyfile then sudo systemctl reload caddy
GetSetLive Streaming Server
Technical Operations Manual
Version 1.0 | December 2025
1. Introduction
1.1 Purpose
This manual provides comprehensive documentation for the GetSetLive Streaming Server platform. It covers the technology stack, architecture decisions, implementation details, testing procedures, deployment process, and operational guidelines.
The platform is designed to provide professional-grade live streaming capabilities with adaptive bitrate (ABR) transcoding, multi-protocol support, and enterprise security features.
1.2 Scope
This documentation covers:
- Complete technology stack with feature explanations
- System architecture and planning decisions
- Step-by-step implementation details
- API reference with curl examples and sample outputs
- Testing and validation procedures
- Production deployment guide
- Operational best practices and troubleshooting
1.3 System Overview
GetSetLive is a complete live streaming solution that enables:
| Feature | Description |
|---|---|
| Multi-Protocol Ingest | RTMP, WebRTC publishing support |
| ABR Transcoding | 5 quality levels (1080p to 240p) with FFmpeg |
| Multi-Protocol Delivery | HLS, HTTP-FLV, WebRTC playback |
| Admin Dashboard | Real-time monitoring, stream management, security controls |
| Enterprise Security | JWT authentication, WAF protection, CSF firewall |
| API-First Design | RESTful APIs for all operations |
2. Technology Stack
2.1 SRS Media Server (v7.0.94)
What it is: Simple Realtime Server (SRS) is a high-performance, open-source media server written in C++ for live streaming.
Key Features:
- RTMP Ingest: Accepts live streams from OBS, FFmpeg, hardware encoders
- HLS Output: Generates HTTP Live Streaming segments for broad device compatibility
- HTTP-FLV: Low-latency Flash video streaming over HTTP
- WebRTC: Ultra-low latency peer-to-peer streaming
- HTTP Callback: Notifies backend on stream publish/unpublish events
- Cluster Support: Edge-origin architecture for scaling
Configuration Location:
/opt/streaming-server/configs/srs.conf
Service Management:
# Check SRS status
$ sudo systemctl status srs
β srs.service - SRS Media Server
Loaded: loaded (/etc/systemd/system/srs.service; enabled)
Active: active (running) since Thu 2025-12-05 00:00:20 UTC
Main PID: 1147206 (srs)
Memory: 45.2M
# View SRS version via API
$ curl -s http://127.0.0.1:1985/api/v1/versions
{
"code": 0,
"server": "vid-583u578",
"data": {
"major": 7,
"minor": 0,
"revision": 94,
"version": "7.0.94"
}
}
Why SRS was chosen:
- High performance: Handles 10,000+ concurrent connections
- Low memory footprint compared to alternatives
- Native HLS support without additional transcoding
- Active development and community support
- HTTP callback integration for custom authentication
2.2 FFmpeg Transcoder (v6.1.1)
What it is: FFmpeg is the industry-standard multimedia framework for encoding, decoding, and transcoding audio/video.
Key Features:
- H.264/H.265 Encoding: Hardware-accelerated video compression
- ABR Ladder Generation: Creates multiple quality renditions from single input
- AAC Audio: High-quality audio encoding
- HLS Segmenting: Generates .ts segments and .m3u8 playlists
ABR Quality Profiles:
| Profile | Resolution | Video Bitrate | Audio | Use Case |
|---|---|---|---|---|
| 1080p | 1920x1080 | 5000 kbps | 192k AAC | Desktop, Smart TV |
| 720p | 1280x720 | 2800 kbps | 128k AAC | Tablet, Fast mobile |
| 480p | 854x480 | 1400 kbps | 128k AAC | Mobile 4G |
| 360p | 640x360 | 800 kbps | 96k AAC | Mobile 3G |
| 240p | 426x240 | 400 kbps | 64k AAC | Low bandwidth |
FFmpeg Command Example:
# ABR transcoding command (simplified)
ffmpeg -i rtmp://localhost/live/stream_key \
-map 0:v -map 0:a -c:v libx264 -preset veryfast \
-b:v:0 5000k -s:v:0 1920x1080 \
-b:v:1 2800k -s:v:1 1280x720 \
-b:v:2 1400k -s:v:2 854x480 \
-c:a aac -b:a 128k \
-f hls -hls_time 2 -hls_list_size 10 \
-master_pl_name master.m3u8 \
/opt/streaming-server/hls/stream_key/playlist.m3u8
2.3 Node.js Backend (v20.19.5)
What it is: Node.js powers both the Streaming API and Authentication Service, providing RESTful endpoints for all platform operations.
Services:
| Service | Port | Purpose |
|---|---|---|
| streaming-api | 1987 | Stream management, monitoring, admin operations |
| streaming-auth | 1988 | JWT authentication, session management |
Key Features:
- Express.js Framework: Fast, minimalist web framework
- JWT Authentication: Stateless token-based auth with RS256 signing
- Redis Integration: Session storage and real-time state
- SRS HTTP Callback: Handles stream events (on_publish, on_unpublish)
- System Monitoring: CPU, memory, disk, network statistics
- Service Management: Start/stop/restart systemd services
Service Management:
# Check API service status
$ sudo systemctl status streaming-api
β streaming-api.service - Streaming API Server
Active: active (running)
Memory: 78.5M
# View API logs
$ sudo journalctl -u streaming-api -f
Dec 05 10:30:15 server streaming-api: [INFO] Server listening on port 1987
Dec 05 10:30:16 server streaming-api: [INFO] Redis connected successfully
2.4 Caddy Web Server (v2.10.2)
What it is: Caddy is a modern web server with automatic HTTPS, serving as the reverse proxy and static file server.
Key Features:
- Automatic HTTPS: Auto-obtains and renews Let's Encrypt certificates
- Reverse Proxy: Routes requests to backend services
- WAF Integration: Coraza WAF module for security
- Static Files: Serves admin dashboard and HLS segments
- HTTP/2 & HTTP/3: Modern protocol support
Configuration:
# /etc/caddy/Caddyfile structure
stream.getsetlive.com {
# WAF protection
route {
coraza_waf {
load_owasp_crs
directives `
SecRuleEngine On
SecRule REQUEST_URI "^/api/admin/" "id:1006,phase:1,pass,nolog,ctl:ruleEngine=Off"
`
}
}
# API routing
handle /api/auth/* {
reverse_proxy 127.0.0.1:1988
}
handle /api/* {
reverse_proxy 127.0.0.1:1987
}
# HLS streaming
handle /hls/* {
root * /opt/streaming-server
file_server
header Access-Control-Allow-Origin "*"
}
# Admin dashboard
handle /admin* {
root * /opt/streaming-server/frontend
try_files {path} /admin.html
file_server
}
}
2.5 Redis Database (v7.0.15)
What it is: Redis is an in-memory data store used for session management, caching, and real-time state.
Use Cases:
| Feature | Key Pattern | TTL |
|---|---|---|
| JWT Sessions | session:{username}:{timestamp} | 24 hours |
| Rate Limiting | ratelimit:{ip}:{endpoint} | 60 seconds |
| Stream State | stream:{streamKey} | No expiry |
| Auth Failures | authfail:{ip} | 15 minutes |
Verification:
# Test Redis connection
$ redis-cli ping
PONG
# View active sessions
$ redis-cli keys "session:*"
1) "session:admin:1733385600000"
# Check memory usage
$ redis-cli info memory | grep used_memory_human
used_memory_human:2.45M
2.6 Security Stack
2.6.1 Coraza WAF
Web Application Firewall integrated with Caddy, using OWASP Core Rule Set (CRS).
- SQL Injection protection
- Cross-Site Scripting (XSS) prevention
- Path traversal blocking
- Request rate limiting
2.6.2 CSF Firewall
ConfigServer Security & Firewall for network-level protection.
# Check CSF status
$ sudo csf -l | head -20
iptables filter table
Chain INPUT (policy DROP)
num target prot opt source destination
1 ACCEPT tcp -- anywhere anywhere tcp dpt:https
2 ACCEPT tcp -- anywhere anywhere tcp dpt:1935
2.6.3 JWT Authentication
Token-based authentication with configurable expiry and refresh mechanisms.
# JWT Token Structure
{
"header": {
"alg": "HS256",
"typ": "JWT"
},
"payload": {
"username": "admin",
"role": "admin",
"iat": 1733385600,
"exp": 1733472000
}
}
3. Architecture & Planning
3.1 System Architecture
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β INTERNET β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββΌββββββββββββββββ
β β β
RTMP :1935 HTTPS :443 WebRTC
β β β
βββββββββββββββββββββ΄ββββββββββββββββ΄ββββββββββββββββ΄ββββββββββββββββββββ
β CSF FIREWALL β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
βΌ βΌ
βββββββββββββ βββββββββββββββββββ
β SRS β β CADDY β
β :1935 β β :443 β
β :1985 β β + Coraza WAF β
β :8080 β ββββββββββ¬βββββββββ
βββββββ¬ββββββ β
β βββββββββ΄βββββββββ¬βββββββββββββββ
β β β β
β βΌ βΌ βΌ
β ββββββββββββ ββββββββββββββ ββββββββββββ
β β Auth API β β Stream API β β Frontend β
β β :1988 β β :1987 β β /admin β
β ββββββ¬ββββββ βββββββ¬βββββββ ββββββββββββ
β β β
β βββββββββ¬ββββββββ
β β
β βΌ
β βββββββββββββββ
β β REDIS β
β β :6379 β
β βββββββββββββββ
β
βΌ
βββββββββββββββββ
β ABR Transcoderβ
β (FFmpeg) β
βββββββββ¬ββββββββ
β
βΌ
βββββββββββββββββ
β HLS Output β
β /hls/*.m3u8 β
βββββββββββββββββ
3.2 Data Flow
Stream Publishing Flow:
1. Encoder (OBS) connects to rtmp://stream.getsetlive.com/live/stream_key
2. SRS receives RTMP connection on port 1935
3. SRS triggers HTTP callback to streaming-api: POST /api/srs/on_publish
4. streaming-api validates stream key and IP whitelist
5. If valid, SRS accepts stream; ABR transcoder starts
6. FFmpeg creates HLS segments in /opt/streaming-server/hls/stream_key/
7. Segments available via https://stream.getsetlive.com/hls/stream_key/master.m3u8
Playback Flow:
1. Player requests https://stream.getsetlive.com/hls/stream_key/master.m3u8
2. Caddy serves master playlist with available quality levels
3. Player selects quality based on bandwidth
4. Player requests .ts segments for chosen quality
5. Caddy serves segments from /opt/streaming-server/hls/
3.3 Directory Structure
/opt/streaming-server/
βββ auth/ # Authentication service
β βββ server.js # Main auth server
β βββ package.json # Dependencies
β βββ node_modules/
β
βββ streaming/ # Streaming API service
β βββ server.js # Main API server
β βββ package.json
β βββ node_modules/
β
βββ frontend/ # Admin dashboard
β βββ admin.html # Main dashboard page
β βββ admin-app.js # Dashboard JavaScript
β βββ admin-styles.css # Dashboard styles
β βββ index.html # Login page
β
βββ configs/ # Configuration files
β βββ streaming.config.json
β βββ security.config.json
β βββ abr.config.json
β βββ whitelist_ips.json
β βββ srs.conf
β
βββ hls/ # HLS output directory
β βββ {stream_key}/
β βββ master.m3u8 # ABR master playlist
β βββ 1080p/
β βββ 720p/
β βββ ...
β
βββ waf/ # WAF configuration
β βββ config/
β β βββ coraza-main.conf
β βββ logs/
β βββ audit.log
β
βββ tmp/ # Temporary files
4. Implementation Details
4.1 Service Configuration
streaming.config.json
{
"server": {
"port": 1987,
"host": "127.0.0.1"
},
"srs": {
"api_url": "http://127.0.0.1:1985",
"rtmp_port": 1935,
"http_port": 8080
},
"hls": {
"output_path": "/opt/streaming-server/hls",
"segment_duration": 2,
"playlist_size": 10
},
"redis": {
"host": "127.0.0.1",
"port": 6379
}
}
security.config.json
{
"authentication": {
"jwt_secret": "your_secure_secret_here",
"jwt_expiry": "24h",
"session": {
"cookie_max_age_seconds": 86400,
"http_only": true,
"secure": true
}
},
"rate_limiting": {
"auth_failures": {
"max_attempts": 5,
"ban_duration_seconds": 900
},
"api_requests": {
"window_seconds": 60,
"max_requests": 100
}
},
"admin_dashboard": {
"api_key": "64_character_secure_key_here"
}
}
4.2 ABR Transcoding Setup
abr.config.json
{
"enabled": true,
"qualities": [
{
"name": "1080p",
"width": 1920,
"height": 1080,
"video_bitrate": "5000k",
"audio_bitrate": "192k"
},
{
"name": "720p",
"width": 1280,
"height": 720,
"video_bitrate": "2800k",
"audio_bitrate": "128k"
},
{
"name": "480p",
"width": 854,
"height": 480,
"video_bitrate": "1400k",
"audio_bitrate": "128k"
},
{
"name": "360p",
"width": 640,
"height": 360,
"video_bitrate": "800k",
"audio_bitrate": "96k"
},
{
"name": "240p",
"width": 426,
"height": 240,
"video_bitrate": "400k",
"audio_bitrate": "64k"
}
],
"encoding": {
"video_codec": "libx264",
"preset": "veryfast",
"audio_codec": "aac"
}
}
4.3 Authentication System
The authentication system uses JWT tokens with Redis session storage.
Login Flow:
1. Client sends POST /api/auth/login with username/password
2. Auth service validates credentials against security.config.json
3. If valid:
- Generate JWT token with 24h expiry
- Store session in Redis: session:{username}:{timestamp}
- Return token + dashboardConfig (including API key)
4. Client stores token in sessionStorage
5. Subsequent requests include Authorization: Bearer {token}
API Key Authentication:
Admin API endpoints use X-API-Key header:
- Key is returned in dashboardConfig after login
- Validated against security.config.json
- Used for: /api/admin/* endpoints
5. API Reference
Complete technical specification for all GetSetLive streaming platform REST APIs, authentication headers, request payloads, and response formats.
5.1 Authentication & User Management APIs
Authenticate user credentials against SQLite database. Enforces Redis brute-force lockout (5 attempts / 60m ban). Returns JWT token and dashboard configuration with admin API key.
Request:
curl -X POST https://streaming.getsetlive.net/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"username": "admin",
"password": "your_secure_password"
}'
Response (200 OK):
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"role": "admin",
"username": "admin",
"expiresIn": "24h",
"dashboardConfig": {
"api_key": "pTuFDIJuTZJGDDfD0qbN@UJHtLsmrzZdvWjzmjd3MYRtpM0HSbc@-jyZ8g.VsGTm",
"refresh_intervals_ms": { "services": 10000, "streams": 5000, "logs": 3000 }
}
}
Verify JWT token validity and retrieve refreshed session claims and dashboard configuration.
Request:
curl -X POST https://streaming.getsetlive.net/api/auth/verify \
-H "Authorization: Bearer <JWT_TOKEN>"
Response (200 OK):
{
"valid": true,
"username": "admin",
"role": "admin",
"dashboardConfig": { "api_key": "..." }
}
Invalidate user session and log logout event.
Request:
curl -X POST https://streaming.getsetlive.net/api/auth/logout \
-H "Authorization: Bearer <JWT_TOKEN>"
Response (200 OK):
{
"success": true,
"message": "Logged out successfully"
}
List all registered users from SQLite with role, active status, organization, and last login IP.
Request:
curl -X GET https://streaming.getsetlive.net/api/auth/users \
-H "Authorization: Bearer <JWT_TOKEN>"
Response (200 OK):
{
"success": true,
"count": 5,
"users": [
{ "id": 1, "username": "admin", "email": "admin@getsetlive.com", "role": "admin", "is_active": 1, "is_publisher": 1, "organization": "Default", "last_login_ip": "127.0.0.1" }
]
}
Create a new user account with bcrypt password hashing (cost 10) in SQLite database.
Request:
curl -X POST https://streaming.getsetlive.net/api/auth/users \
-H "Authorization: Bearer <JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"username": "broadcaster1",
"email": "broadcaster1@getsetlive.com",
"password": "SecurePassword123!",
"role": "broadcaster",
"organization": "Default",
"is_publisher": 1
}'
Response (201 Created):
{
"success": true,
"message": "User created successfully",
"user": { "id": 6, "username": "broadcaster1", "role": "broadcaster" }
}
Update user account profile, email, organization, groups, or role.
Request:
curl -X PUT https://streaming.getsetlive.net/api/auth/users/broadcaster1 \
-H "Authorization: Bearer <JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "email": "newemail@getsetlive.com", "organization": "Default" }'
Response (200 OK):
{ "success": true, "message": "User updated successfully" }
Toggle user active state (1 = active, 0 = disabled).
Request:
curl -X PATCH https://streaming.getsetlive.net/api/auth/users/broadcaster1/status \
-H "Authorization: Bearer <JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "is_active": 0 }'
Response (200 OK):
{ "success": true, "message": "User status updated" }
Permanently delete a user account from SQLite and purge active Redis sessions.
Request:
curl -X DELETE https://streaming.getsetlive.net/api/auth/users/broadcaster1 \
-H "Authorization: Bearer <JWT_TOKEN>"
Response (200 OK):
{ "success": true, "message": "User deleted successfully" }
Administrative password reset. Hashes new password with bcrypt and updates SQLite record.
Request:
curl -X POST https://streaming.getsetlive.net/api/auth/users/broadcaster1/reset-password \
-H "Authorization: Bearer <JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "newPassword": "BrandNewSecurePassword456!" }'
Response (200 OK):
{ "success": true, "message": "Password reset successfully" }
Query Redis for active IP brute-force lockouts and failed login attempt counts.
Request:
curl -X GET https://streaming.getsetlive.net/api/auth/users/lockout-status \
-H "Authorization: Bearer <JWT_TOKEN>"
Response (200 OK):
{
"success": true,
"lockedOutIPs": [ { "ip": "198.51.100.25", "ttl": 1840, "attempts": 5 } ],
"failedAttempts": []
}
Administrative unlock: Clears Redis lockout and resets failed login attempts counter.
Request:
curl -X POST https://streaming.getsetlive.net/api/auth/users/broadcaster1/unlock \
-H "Authorization: Bearer <JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "ip": "198.51.100.25" }'
Response (200 OK):
{ "success": true, "message": "User IP lockout cleared" }
5.2 Live Stream Management & RTMP Ingest APIs
List all configured stream keys merged with live metrics from SRS HTTP summary API (:1985).
Request:
curl -X GET https://streaming.getsetlive.net/api/admin/streams/all \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{
"success": true,
"streams": [
{
"id": "vid-583u578",
"streamKey": "angel-stream2",
"status": "publishing",
"uptime": "5h 12m",
"video": { "codec": "H264", "width": 1920, "height": 1080, "fps": 30 },
"audio": { "codec": "AAC", "sampleRate": 44100, "channels": 2 },
"bitrate": { "video": 4000, "audio": 192, "total": 4192 }
}
]
}
Create a new live stream key record in SQLite database.
Request:
curl -X POST https://streaming.getsetlive.net/api/admin/streams/create \
-H "X-API-Key: <ADMIN_API_KEY>" \
-H "Content-Type: application/json" \
-d '{ "customKey": "event-stream-2026" }'
Response (201 Created):
{
"success": true,
"streamKey": "event-stream-2026",
"rtmpUrl": "rtmp://streaming.getsetlive.net/live/event-stream-2026",
"hlsUrl": "https://streaming.getsetlive.net/hls/event-stream-2026/master.m3u8"
}
Fetch live real-time stream metrics directly from SRS media engine for a specific stream key.
Request:
curl -X GET https://streaming.getsetlive.net/api/admin/streams/angel-stream2/metrics \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{
"success": true,
"stream": { "name": "angel-stream2", "vhost": "__defaultVhost__", "app": "live" },
"video": { "codec": "AVC", "profile": "High", "width": 1920, "height": 1080 },
"audio": { "codec": "AAC", "sample_rate": 44100 },
"kbps": { "recv_30s": 4250, "send_30s": 12800 }
}
Disconnect active live publisher and terminate FFmpeg transcoding worker.
Request:
curl -X POST https://streaming.getsetlive.net/api/admin/streams/angel-stream2/stop \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{ "success": true, "message": "Stream stopped successfully" }
Delete stream key from database and clean up filesystem HLS segments.
Request:
curl -X DELETE https://streaming.getsetlive.net/api/admin/streams/event-stream-2026 \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{ "success": true, "message": "Stream deleted and cleaned" }
Launch an automated FFmpeg SMPTE test pattern feed with lavfi testsrc and sine wave audio.
Request:
curl -X POST https://streaming.getsetlive.net/api/test-stream/test_stream_01 \
-H "Authorization: Bearer <JWT_TOKEN>"
Response (200 OK):
{ "success": true, "message": "Test pattern stream started", "streamKey": "test_stream_01" }
Stream a local MP4 video file from storage to HLS with optional continuous looping.
Request:
curl -X POST https://streaming.getsetlive.net/api/file-stream/promo_stream \
-H "Authorization: Bearer <JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "filename": "sample.mp4", "loop": true }'
Response (200 OK):
{ "success": true, "message": "File stream started", "streamKey": "promo_stream" }
Kick an offending client connection from SRS and ban their IP address in Redis.
Request:
curl -X POST https://streaming.getsetlive.net/api/streams/angel-stream2/viewers/7x2k9p3m/block \
-H "X-API-Key: <ADMIN_API_KEY>" \
-H "Content-Type: application/json" \
-d '{ "ip": "198.51.100.44", "reason": "Abusive stream scraping" }'
Response (200 OK):
{ "success": true, "message": "Client kicked and IP banned" }
5.3 Stream Recording (DVR Capture) & Retention APIs
List all captured SRS DVR broadcast MP4 recordings with file size, modified timestamp, signed download token, and active retention window.
Request:
curl -X GET https://streaming.getsetlive.net/api/admin/recordings \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{
"recordings": [
{
"filename": "angel-stream2.20260818-110000.mp4",
"streamKey": "angel-stream2",
"size": 428945600,
"modified": "2026-08-18T05:30:00.000Z",
"downloadToken": "eyJmaWxlbmFtZSI6ImFuZ2VsLXN0cmVhbTI..."
}
],
"totalBytes": 428945600,
"count": 1,
"retentionDays": 30
}
Stream download an MP4 recording. Accepts either the X-API-Key header or an HMAC-signed short-lived token (?token=) for browser anchor links.
Request:
curl -O -H "X-API-Key: <ADMIN_API_KEY>" \
"https://streaming.getsetlive.net/api/admin/recordings/download/angel-stream2.20260818-110000.mp4"
Response:
HTTP/1.1 200 OK
Content-Type: video/mp4
Content-Disposition: attachment; filename="angel-stream2.20260818-110000.mp4"
[Binary MP4 Stream Data]
Delete a recording file from /opt/streaming-server/storage/recordings/.
Request:
curl -X DELETE https://streaming.getsetlive.net/api/admin/recordings/angel-stream2.20260818-110000.mp4 \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{ "success": true, "message": "Recording deleted successfully" }
Dynamically update the DVR retention window (1β365 days). Persists to streaming.config.json and hot-updates memory with zero downtime.
Request:
curl -X PUT https://streaming.getsetlive.net/api/admin/recordings/retention \
-H "X-API-Key: <ADMIN_API_KEY>" \
-H "Content-Type: application/json" \
-d '{ "days": 30 }'
Response (200 OK):
{
"success": true,
"retentionDays": 30
}
5.4 Video-on-Demand (VOD) Library & Upload APIs
Upload a raw video file (max 2GB). Extracts duration via ffprobe, captures thumbnail at 1s, and registers record in SQLite vod_videos table. Requires IP Whitelist + JWT.
Request:
curl -X POST https://streaming.getsetlive.net/api/upload \
-H "Authorization: Bearer <JWT_TOKEN>" \
-F "video=@presentation.mp4" \
-F "title=Keynote Presentation" \
-F "description=Annual Conference Keynote" \
-F "category=conferences"
Response (201 Created):
{
"success": true,
"video": {
"id": 2,
"filename": "vod-1787031543-a1b2c3.mp4",
"title": "Keynote Presentation",
"duration_seconds": 1845,
"file_size": 154820900,
"stream_key": "vod-1787031543-a1b2c3",
"transcode_status": "pending"
}
}
List all VOD assets in the library with metadata, transcode progress, and publish state.
Request:
curl -X GET https://streaming.getsetlive.net/api/vod \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{
"count": 1,
"videos": [
{
"id": 1,
"title": "Product Overview",
"duration_seconds": 360,
"file_size": 45200100,
"sizeHuman": "43.11 MB",
"thumbnail_path": "/thumbnails/vod-thumb-1.jpg",
"stream_key": "vod-1767867976958-ll03ir",
"transcode_status": "completed",
"transcode_progress": 100,
"is_published": 1,
"views": 42
}
]
}
Get comprehensive metadata and HLS playlist URL for a specific VOD asset.
Request:
curl -X GET https://streaming.getsetlive.net/api/vod/1 \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{
"success": true,
"video": { "id": 1, "title": "Product Overview", "stream_key": "vod-1767867976958-ll03ir", "is_published": 1 }
}
Update VOD video title, description, or category.
Request:
curl -X PUT https://streaming.getsetlive.net/api/vod/1 \
-H "X-API-Key: <ADMIN_API_KEY>" \
-H "Content-Type: application/json" \
-d '{ "title": "Updated Product Overview", "category": "tutorials" }'
Response (200 OK):
{ "success": true, "message": "VOD metadata updated" }
Delete a VOD video, raw file, thumbnail, and HLS directory. Requires IP Whitelist + JWT.
Request:
curl -X DELETE https://streaming.getsetlive.net/api/vod/1 \
-H "Authorization: Bearer <JWT_TOKEN>"
Response (200 OK):
{ "success": true, "message": "VOD video deleted successfully" }
Publish VOD video to the public watch catalog (sets is_published = 1).
Request:
curl -X POST https://streaming.getsetlive.net/api/vod/1/publish \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{ "success": true, "is_published": 1 }
Unpublish VOD video from public watch catalog (sets is_published = 0).
Request:
curl -X POST https://streaming.getsetlive.net/api/vod/1/unpublish \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{ "success": true, "is_published": 0 }
Start background FFmpeg HLS transcoding job. Requires IP Whitelist + JWT.
Request:
curl -X POST https://streaming.getsetlive.net/api/vod/1/transcode \
-H "Authorization: Bearer <JWT_TOKEN>"
Response (200 OK):
{ "success": true, "message": "Transcoding initiated", "status": "transcoding" }
Poll transcoding progress percentage (0β100%) and current job status.
Request:
curl -X GET https://streaming.getsetlive.net/api/vod/1/transcode/status \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{ "status": "completed", "progress": 100 }
Public unauthenticated catalog of published VOD assets for watch pages.
Request:
curl -X GET https://streaming.getsetlive.net/api/vod/public
Response (200 OK):
{
"count": 1,
"videos": [
{ "id": 1, "title": "Product Overview", "stream_key": "vod-1767867976958-ll03ir", "thumbnail_path": "/thumbnails/vod-thumb-1.jpg" }
]
}
5.5 Multi-Tenancy APIs: Organizations, Groups & Invoicing
List all tenant organizations with live userCount, broadcasterCount, and active streamCount computed dynamically from SQLite.
Request:
curl -X GET https://streaming.getsetlive.net/api/auth/organizations \
-H "Authorization: Bearer <JWT_TOKEN>"
Response (200 OK):
{
"organizations": [
{
"id": 1,
"name": "Default",
"plan": "Enterprise",
"status": "active",
"userCount": 5,
"broadcasterCount": 5,
"streamCount": 2,
"created_at": "2026-07-23T10:00:00Z"
}
]
}
Create a new tenant organization record in SQLite.
Request:
curl -X POST https://streaming.getsetlive.net/api/auth/organizations \
-H "Authorization: Bearer <JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "name": "Acme Media Group", "plan": "Enterprise", "status": "active" }'
Response (201 Created):
{
"organization": { "id": 2, "name": "Acme Media Group", "plan": "Enterprise", "status": "active" }
}
Update organization name, plan, or status. Cascades name changes to linked users in SQLite.
Request:
curl -X PUT https://streaming.getsetlive.net/api/auth/organizations/2 \
-H "Authorization: Bearer <JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "name": "Acme Broadcast Networks", "plan": "Custom" }'
Response (200 OK):
{ "organization": { "id": 2, "name": "Acme Broadcast Networks" } }
Delete organization. Returns 409 Conflict if active users are still assigned to the organization.
Request:
curl -X DELETE https://streaming.getsetlive.net/api/auth/organizations/2 \
-H "Authorization: Bearer <JWT_TOKEN>"
Response (200 OK):
{ "success": true, "message": "Organization deleted" }
List all user groups with live member counts aggregated from the users table.
Request:
curl -X GET https://streaming.getsetlive.net/api/auth/groups \
-H "Authorization: Bearer <JWT_TOKEN>"
Response (200 OK):
{
"groups": [
{ "id": 1, "name": "Broadcasters", "description": "Live production staff", "memberCount": 4 }
]
}
Create a new access and permissions group.
Request:
curl -X POST https://streaming.getsetlive.net/api/auth/groups \
-H "Authorization: Bearer <JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "name": "Camera Operators", "description": "Mobile field operators" }'
Response (201 Created):
{ "group": { "id": 2, "name": "Camera Operators" } }
List invoices with summary calculations (total billed, paid, and outstanding balances).
Request:
curl -X GET https://streaming.getsetlive.net/api/auth/billing/invoices \
-H "Authorization: Bearer <JWT_TOKEN>"
Response (200 OK):
{
"invoices": [],
"summary": { "totalCount": 0, "totalAmountCents": 0, "paidAmountCents": 0, "unpaidAmountCents": 0 }
}
Create a new billing invoice with auto-generated sequential number (INV-YYYY-XXXX).
Request:
curl -X POST https://streaming.getsetlive.net/api/auth/billing/invoices \
-H "Authorization: Bearer <JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"organization": "Default",
"amount_cents": 250000,
"currency": "INR",
"status": "unpaid",
"due_at": "2026-09-01"
}'
Response (201 Created):
{
"invoice": { "id": 1, "number": "INV-2026-0001", "amount_cents": 250000, "status": "unpaid" }
}
5.6 Configuration Management APIs
Read current contents of configs/streaming.config.json.
Request:
curl -X GET https://streaming.getsetlive.net/api/admin/config/streaming \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{
"server": { "port": 1987, "host": "127.0.0.1" },
"domain": { "public_host": "streaming.getsetlive.net" },
"recordings": { "retention_days": 30 }
}
Deep-merge updates into streaming.config.json and create automatic timestamped backup.
Request:
curl -X PUT https://streaming.getsetlive.net/api/admin/config/streaming \
-H "X-API-Key: <ADMIN_API_KEY>" \
-H "Content-Type: application/json" \
-d '{ "streaming": { "max_concurrent_streams": 20 } }'
Response (200 OK):
{ "success": true, "message": "Streaming config updated" }
Retrieve upload IP whitelist enriched with country (resolved via local MaxMind Go service), timestamp, admin username, and admin login origin country.
Request:
curl -X GET https://streaming.getsetlive.net/api/admin/config/whitelist/detailed \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{
"whitelisted_ips": [
{
"ip": "60.254.0.187",
"country": "India",
"countryCode": "IN",
"added_by": "admin",
"added_at": "2026-07-24T02:15:00Z",
"added_by_ip": "42.106.251.133",
"added_by_country": "India"
}
]
}
Add IP to whitelist and capture audit metadata with local MaxMind geo resolution.
Request:
curl -X POST https://streaming.getsetlive.net/api/admin/config/whitelist/add \
-H "X-API-Key: <ADMIN_API_KEY>" \
-H "Content-Type: application/json" \
-d '{ "ip": "103.21.244.2", "added_by": "admin" }'
Response (200 OK):
{ "success": true, "message": "IP added to whitelist with audit metadata" }
Remove IP from whitelist and purge its audit metadata record.
Request:
curl -X POST https://streaming.getsetlive.net/api/admin/config/whitelist/remove \
-H "X-API-Key: <ADMIN_API_KEY>" \
-H "Content-Type: application/json" \
-d '{ "ip": "103.21.244.2" }'
Response (200 OK):
{ "success": true, "message": "IP removed from whitelist" }
5.7 Real-Time HLS Viewer Tracking & Heartbeat APIs
Generate a tamper-proof HMAC-SHA256 session token when a viewer loads an HLS video player tab.
Request:
curl -X POST https://streaming.getsetlive.net/api/viewer/session \
-H "Content-Type: application/json" \
-d '{ "streamKey": "angel-stream2" }'
Response (200 OK):
{
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
"token": "eyJzZXNzaW9uSWQiOiI1NTBlODQwMC1lMjliLTR..."
}
Periodic 30-second heartbeat from active HLS players to track live unique viewers even behind shared NAT/WiFi IPs.
Request:
curl -X POST https://streaming.getsetlive.net/api/viewer/heartbeat \
-H "Content-Type: application/json" \
-d '{
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
"streamKey": "angel-stream2",
"token": "eyJzZXNzaW9uSWQiOiI1NTBlODQwMC1lMjliLTR...",
"quality": "1080p"
}'
Response (200 OK):
{ "success": true, "status": "active" }
Get current live unique viewer count for a public or private stream.
Request:
curl -X GET https://streaming.getsetlive.net/api/viewer/count/angel-stream2
Response (200 OK):
{ "streamKey": "angel-stream2", "viewers": 18 }
Administrative breakdown of active HLS viewer sessions, quality distribution, and session uptimes.
Request:
curl -X GET https://streaming.getsetlive.net/api/admin/streams/angel-stream2/hls-viewers \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{
"streamKey": "angel-stream2",
"activeCount": 18,
"qualityBreakdown": { "1080p": 8, "720p": 6, "480p": 4 }
}
5.8 Security, WAF Analytics & Geo APIs
Get security dashboard KPI statistics (active WAF status, firewall blocks, active sessions).
Request:
curl -X GET https://streaming.getsetlive.net/api/admin/security/overview \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{
"success": true,
"firewallStatus": "Active - CSF Enabled",
"wafStatus": "Active - Coraza CRS v4.24.0",
"firewallBlocksToday": 47,
"wafBlocksToday": 262,
"activeSessions": 3
}
Query Coraza WAF blocked transactions from audit.log with level and pagination filters.
Request:
curl -X GET "https://streaming.getsetlive.net/api/waf-analytics/events?filter=all&limit=50"
Response (200 OK):
{
"events": [
{
"timestamp": "2026-08-18T06:12:00Z",
"client_ip": "198.51.100.12",
"method": "GET",
"uri": "/api/vod?q=<script>alert(1)</script>",
"status": 403,
"rule_id": 941100,
"message": "XSS Attack Detected",
"severity": "CRITICAL"
}
],
"total": 262
}
Fetch live streaming Caddy JSON access log entries.
Request:
curl -X GET "https://streaming.getsetlive.net/api/waf-analytics/access?limit=50"
Response (200 OK):
{
"events": [
{ "timestamp": "2026-08-18T06:15:00Z", "client_ip": "42.106.251.133", "method": "GET", "uri": "/hls/angel-stream2/master.m3u8", "status": 200 }
]
}
Get ConfigServer Firewall (CSF) status and active ban counts.
Request:
curl -X GET https://streaming.getsetlive.net/api/admin/csf/status \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{ "success": true, "status": "running", "rules": { "allow": 45, "deny": 1247 } }
Execute CSF firewall actions (allow, deny, tempban, unban).
Request:
curl -X POST https://streaming.getsetlive.net/api/admin/csf/action \
-H "X-API-Key: <ADMIN_API_KEY>" \
-H "Content-Type: application/json" \
-d '{ "action": "deny", "ip": "203.0.113.88", "comment": "Brute force attack" }'
Response (200 OK):
{ "success": true, "message": "IP added to CSF deny list" }
List all temporarily banned IPs from Redis with remaining TTL.
Request:
curl -X GET https://streaming.getsetlive.net/api/admin/banned-ips \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{ "bannedIps": [ { "ip": "198.51.100.25", "ttl": 1200, "reason": "Auth failure lockout" } ] }
Unban an IP address in Redis.
Request:
curl -X DELETE https://streaming.getsetlive.net/api/admin/banned-ips/198.51.100.25 \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{ "success": true, "message": "IP unbanned in Redis" }
Offline MaxMind IP-to-Country lookup via local Go microservice (zero external network dependency).
Request:
curl -X GET "http://127.0.0.1:3009/geo?ip=8.8.8.8"
Response (200 OK):
{ "ip": "8.8.8.8", "country": "United States", "countryCode": "US" }
5.9 System Monitoring, Services & Inquiries APIs
Get system hardware stats: CPU load, memory usage, disk storage, and daemon uptimes.
Request:
curl -X GET https://streaming.getsetlive.net/api/admin/system/stats \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{
"success": true,
"cpu": { "usage": 12.4, "cores": 4 },
"memory": { "total": 6144, "used": 1420, "free": 4724, "usagePercent": 23.1 },
"disk": { "total": 100, "used": 28, "free": 72, "usagePercent": 28.0 }
}
Get health and running status of all managed systemd streaming daemons.
Request:
curl -X GET https://streaming.getsetlive.net/api/admin/services/status \
-H "X-API-Key: <ADMIN_API_KEY>"
Response (200 OK):
{
"services": [
{ "name": "srs", "status": "running" },
{ "name": "streaming-api", "status": "running" },
{ "name": "streaming-auth", "status": "running" },
{ "name": "abr-transcoder", "status": "running" },
{ "name": "geo-service", "status": "running" },
{ "name": "caddy", "status": "running" }
]
}
Manage system services: start, stop, or restart platform daemons.
Request:
curl -X POST https://streaming.getsetlive.net/api/admin/services/manage \
-H "X-API-Key: <ADMIN_API_KEY>" \
-H "Content-Type: application/json" \
-d '{ "services": ["abr-transcoder"], "action": "restart" }'
Response (200 OK):
{ "success": true, "message": "Services restarted successfully" }
Submit contact inquiry from public portal with rate limiting and automated spam filters.
Request:
curl -X POST https://streaming.getsetlive.net/api/contact \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Doe",
"email": "jane@example.com",
"subject": "Enterprise Live Streaming Inquiry",
"message": "Interested in white-label ABR broadcasting options."
}'
Response (200 OK):
{ "success": true, "message": "Inquiry submitted successfully" }
Retrieve submitted contact inquiries for admin review.
Request:
curl -X GET https://streaming.getsetlive.net/api/contact/submissions \
-H "Authorization: Bearer <JWT_TOKEN>"
Response (200 OK):
{ "submissions": [ { "id": "msg-1", "name": "Jane Doe", "email": "jane@example.com", "subject": "Enterprise Live Streaming Inquiry" } ] }
6. Testing & Validation
6.1 Pre-Deployment Testing
Service Health Checks:
# Test all services are running
$ sudo systemctl status srs streaming-api streaming-auth redis-server caddy
# Test Redis connectivity
$ redis-cli ping
PONG
# Test SRS API
$ curl -s http://127.0.0.1:1985/api/v1/versions | jq .
{
"code": 0,
"data": {
"version": "7.0.94"
}
}
# Test Streaming API
$ curl -s http://127.0.0.1:1987/api/health | jq .
{
"status": "ok",
"timestamp": "2025-12-05T15:00:00.000Z"
}
# Test Auth Service
$ curl -s http://127.0.0.1:1988/api/health | jq .
{
"status": "ok",
"redis": "connected"
}
RTMP Stream Test:
# Publish test stream with FFmpeg
$ ffmpeg -re -f lavfi -i testsrc=size=1280x720:rate=30 \
-f lavfi -i sine=frequency=1000 \
-c:v libx264 -preset ultrafast -b:v 2000k \
-c:a aac -b:a 128k \
-f flv rtmp://localhost/live/test_stream
# Verify stream is active
$ curl -s http://127.0.0.1:1985/api/v1/streams/ | jq '.streams | length'
1
# Test HLS playback
$ curl -I https://stream.getsetlive.com/hls/test_stream/master.m3u8
HTTP/2 200
content-type: application/vnd.apple.mpegurl
6.2 Load Testing
# Simulate multiple viewers with Apache Bench
$ ab -n 1000 -c 100 https://stream.getsetlive.com/hls/test_stream/master.m3u8
# Monitor during test
$ htop # CPU/Memory
$ ss -s # Connection stats
$ sudo journalctl -u srs -f # SRS logs
6.3 Security Testing
# Test WAF is blocking malicious requests
$ curl -X GET "https://stream.getsetlive.com/api/test?id=1' OR '1'='1"
# Should return 403 Forbidden
# Test rate limiting
$ for i in {1..10}; do curl -X POST https://stream.getsetlive.com/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"test","password":"wrong"}'; done
# Should get rate limited after 5 attempts
# Verify JWT expiry
$ curl -X POST https://stream.getsetlive.com/api/auth/verify \
-H "Authorization: Bearer expired_token_here"
# Should return 401 Unauthorized
7. Deployment
7.1 System Requirements
| Component | Minimum | Recommended |
|---|---|---|
| OS | Ubuntu 22.04 LTS | Ubuntu 24.04 LTS |
| CPU | 4 cores | 8+ cores |
| RAM | 8 GB | 16+ GB |
| Storage | 50 GB SSD | 200+ GB NVMe |
| Network | 100 Mbps | 1 Gbps |
7.2 Installation Steps
# 1. Install dependencies
sudo apt update && sudo apt upgrade -y
sudo apt install -y nodejs npm redis-server ffmpeg
# 2. Install Caddy with WAF module
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/caddy-stable-archive-keyring.gpg] https://dl.cloudsmith.io/public/caddy/stable/deb/debian any-version main" | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install caddy
# 3. Create directory structure
sudo mkdir -p /opt/streaming-server/{auth,streaming,frontend,configs,hls,waf,tmp}
sudo chown -R $USER:$USER /opt/streaming-server
# 4. Deploy application files
# (Copy auth, streaming, frontend directories)
# 5. Install Node.js dependencies
cd /opt/streaming-server/auth && npm install
cd /opt/streaming-server/streaming && npm install
# 6. Configure systemd services
sudo cp /opt/streaming-server/configs/*.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable srs streaming-api streaming-auth
# 7. Start services
sudo systemctl start redis-server
sudo systemctl start srs streaming-api streaming-auth
sudo systemctl start caddy
7.3 Backup Procedures
# Create backup
$ sudo /usr/local/bin/streaming-backup "Pre-deployment backup"
Creating backup: streaming-server_Pre-deployment_backup_20251205_153000.tar.gz
Backup completed successfully
# List backups
$ ls -la /opt/backups/streaming-server_*.tar.gz
-rw-r--r-- 1 root root 45M Dec 5 15:30 streaming-server_Pre-deployment_backup_20251205_153000.tar.gz
# Restore from backup
$ cd /opt
$ sudo tar -xzf /opt/backups/streaming-server_BACKUP_NAME.tar.gz
$ sudo systemctl restart srs streaming-api streaming-auth
8. Operations Guide
8.1 Daily Operations
# Morning health check
$ sudo systemctl status srs streaming-api streaming-auth redis-server caddy | grep Active
# Check disk space
$ df -h /opt/streaming-server
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 200G 45G 155G 23% /
# Check active streams
$ curl -s http://127.0.0.1:1985/api/v1/streams/ | jq '.streams | length'
# View recent errors
$ sudo journalctl -u streaming-api -p err --since "1 hour ago"
8.2 Maintenance Tasks
# Weekly: Clean old HLS segments
$ find /opt/streaming-server/hls -type f -mtime +7 -delete
# Weekly: Restart SRS (memory leak mitigation)
$ sudo systemctl restart srs
# Monthly: Update SSL certificates (auto with Caddy)
$ sudo systemctl reload caddy
# Monthly: Review WAF logs
$ sudo tail -100 /opt/streaming-server/waf/logs/audit.log
8.3 Monitoring Commands
# Real-time log monitoring
$ sudo journalctl -u srs -u streaming-api -u streaming-auth -f
# Network connections
$ ss -tlnp | grep -E '(1935|1985|1987|1988|443)'
# Process resource usage
$ ps aux --sort=-%mem | head -10
# SRS statistics
$ curl -s http://127.0.0.1:1985/api/v1/summaries | jq .
9. Troubleshooting
9.1 Stream Issues
Problem: RTMP Connection Refused
Symptoms: OBS shows "Failed to connect to server"
# Diagnosis
$ sudo systemctl status srs
$ sudo netstat -tlnp | grep 1935
$ sudo csf -l | grep 1935
# Solution
$ sudo systemctl restart srs
$ sudo csf -a YOUR_IP # Whitelist if needed
Problem: HLS Not Playing
Symptoms: Stream publishes but player shows error
# Diagnosis
$ ls -la /opt/streaming-server/hls/stream_key/
$ curl -I https://stream.getsetlive.com/hls/stream_key/master.m3u8
# Check SRS logs
$ sudo journalctl -u srs -n 50 | grep -i error
# Solution: Verify HLS output path permissions
$ sudo chown -R www-data:www-data /opt/streaming-server/hls
9.2 Authentication Issues
Problem: Login Fails with 401
# Check auth service
$ sudo systemctl status streaming-auth
# Check Redis
$ redis-cli ping
# Check credentials in config
$ cat /opt/streaming-server/configs/security.config.json | jq '.credentials'
# View auth logs
$ sudo journalctl -u streaming-auth -n 50
Problem: Rate Limited
# Check rate limit status
$ redis-cli keys "ratelimit:*"
# Clear rate limit for IP
$ redis-cli del "ratelimit:YOUR_IP:auth"
# Check config
$ cat /opt/streaming-server/configs/security.config.json | jq '.rate_limiting'
9.3 Performance Issues
Problem: High CPU During Transcoding
# Check FFmpeg processes
$ ps aux | grep ffmpeg
# Reduce quality levels in config
$ nano /opt/streaming-server/configs/abr.config.json
# Remove 1080p or 720p quality
# Use faster preset
# Change "preset": "veryfast" to "ultrafast"
Problem: SRS Out of Memory
# Check memory usage
$ ps aux --sort=-%mem | grep srs
# Known issue: HTTP connection leak in SRS 7.0.94
# Solution: Weekly restart via cron
$ sudo crontab -e
# Add: 0 4 * * 0 systemctl restart srs
9.4 Quick Reference Commands
# Restart all services
$ sudo systemctl restart srs streaming-api streaming-auth
# Clear HLS cache
$ rm -rf /opt/streaming-server/hls/*
# View all logs combined
$ sudo journalctl -u streaming-api -u streaming-auth -u srs -f
# Check all service status
$ for svc in srs streaming-api streaming-auth redis-server caddy; do
echo "=== $svc ===" && sudo systemctl status $svc | head -3
done
# Emergency: Stop all streams
$ curl -X POST http://127.0.0.1:1985/api/v1/kick_all
10. Performance Tuning & Bottlenecks
10.1 Bottlenecks Encountered
Issue #1: SRS Memory Leak (OOM Kill)
Discovery Date: December 4, 2025
Symptoms: SRS process killed by OOM killer after ~22.5 hours of runtime
| Metric | Value |
|---|---|
| Runtime before OOM | ~22.5 hours |
| Starting Memory | ~18MB |
| Peak Memory at OOM | 5.0GB |
| Virtual Memory | ~21TB (kernel reported) |
| Anonymous RSS | ~52GB |
Root Cause Analysis:
- HTTP API connections creating "zombie" resources not fully cleaned up
- SRS logs showed:
zombies=3, zombies=4, zombies=5, zombies=6- accumulating - Continuous HTTP API polling (every 5 seconds) creating ~17,000+ connections/day
- Known issue in SRS 7.0.94 with HttpConn resource cleanup
# Evidence from logs
RTC: before dispose resource(HttpConn)(0x50d00004d410), conns=11, zombies=3
RTC: before dispose resource(HttpConn)(0x50d000069be0), conns=11, zombies=4
RTC: before dispose resource(HttpConn)(0x50d00006b030), conns=11, zombies=5
Solution Implemented:
# Weekly SRS restart via cron (Sunday 4 AM)
$ sudo crontab -e
0 4 * * 0 /usr/bin/systemctl restart srs
# Reduce API polling frequency from 5s to 15s
# In streaming.config.json:
"srs_polling_interval_ms": 15000
Issue #2: ABR Transcoding CPU Saturation
Symptoms: 100% CPU usage during multi-stream transcoding, dropped frames
Root Cause:
- 5 quality levels (1080p, 720p, 480p, 360p, 240p) per stream
- Each stream spawns 5 FFmpeg processes
- Original preset: "medium" (CPU-intensive)
Solution:
# Changed FFmpeg preset in abr.config.json
# Before: "preset": "medium"
# After: "preset": "veryfast"
# Result: 60% CPU reduction with acceptable quality trade-off
# Quality comparison (VMAF scores):
# medium preset: 94.5 VMAF
# veryfast preset: 91.2 VMAF (3.5% reduction, acceptable)
Issue #3: HLS Segment Accumulation
Symptoms: Disk space filling up on long-running streams
Root Cause:
- Default HLS window of 300 seconds (5 minutes)
- 5 ABR quality levels Γ 2-second segments = 750 segments kept
- No automatic cleanup after stream ends
Solution:
# 1. Reduced HLS window in srs.conf
hls_window 60; # Reduced from 300 to 60 seconds
hls_fragment 2;
# 2. Added cleanup cron job
0 */6 * * * find /opt/streaming-server/hls -type f -mmin +360 -delete
# 3. Stream-end cleanup in server.js on_unpublish callback
Issue #4: Redis Connection Exhaustion
Symptoms: "ECONNREFUSED" errors during high load
Root Cause:
- Each API request creating new Redis connection
- No connection pooling implemented
- Default maxclients: 10000 being reached
Solution:
# 1. Implemented Redis connection pooling in server.js
const redis = require('redis');
const client = redis.createClient({
socket: {
reconnectStrategy: (retries) => Math.min(retries * 100, 3000)
},
maxRetriesPerRequest: 3
});
# 2. Increased Redis maxclients in redis.conf
maxclients 50000
# 3. Added connection health check
setInterval(() => client.ping(), 30000);
10.2 Performance Optimizations Applied
10.2.1 HLS Configuration Tuning
| Parameter | Before | After | Impact |
|---|---|---|---|
| hls_fragment | 4s | 2s | Reduced latency by 2s |
| hls_window | 300s | 60s | 80% reduction in disk I/O |
| hls_playlist_size | 10 | 20 | Better buffering stability |
| hls_dispose | 300s | 60s | Faster cleanup |
# Current srs.conf HLS settings
vhost __defaultVhost__ {
hls {
enabled on;
hls_fragment 2;
hls_window 60;
hls_dispose 60;
hls_path /opt/streaming-server/hls;
hls_m3u8_file [app]/[stream]/playlist.m3u8;
hls_ts_file [app]/[stream]/[seq].ts;
}
}
10.2.2 FFmpeg Transcoding Optimization
| Optimization | Setting | Result |
|---|---|---|
| Preset | veryfast | 60% CPU reduction |
| Tune | zerolatency | Reduced encoding delay |
| Threads | auto (per core) | Optimal CPU utilization |
| GOP Size | 48 (2s @ 24fps) | Better seeking |
| Keyframe Interval | 48 | Segment alignment |
# Optimized FFmpeg command flags
-preset veryfast
-tune zerolatency
-g 48 -keyint_min 48
-sc_threshold 0
-b_strategy 0
-bf 0
10.2.3 HLS.js Player Optimization
// Disabled low latency mode for stability
const hls = new Hls({
lowLatencyMode: false, // Changed from true
backBufferLength: 30, // Increased from 10
maxBufferLength: 60, // Increased from 30
maxMaxBufferLength: 120,
liveSyncDurationCount: 3,
liveMaxLatencyDurationCount: 10
});
10.2.4 API Polling Optimization
| Endpoint | Before | After | Reduction |
|---|---|---|---|
| SRS /api/v1/streams | 5s | 15s | 67% |
| SRS /api/v1/versions | 5s | 60s | 92% |
| System stats | 5s | 10s | 50% |
| Service status | 5s | 10s | 50% |
// streaming.config.json polling intervals
{
"refresh_intervals_ms": {
"services": 10000,
"streams": 5000,
"logs": 3000,
"stats": 10000
},
"srs_polling_interval_ms": 15000
}
10.2.5 Caddy/WAF Performance
# WAF bypass for admin API (no WAF overhead for authenticated requests)
SecRule REQUEST_URI "^/api/admin/" "id:1006,phase:1,pass,nolog,ctl:ruleEngine=Off"
# Static file caching headers
handle /hls/* {
header Cache-Control "public, max-age=2"
header Access-Control-Allow-Origin "*"
}
10.3 Performance Monitoring
Key Metrics to Watch:
# SRS Memory (should stay under 500MB)
$ ps aux | grep srs | awk '{print $6/1024 " MB"}'
# FFmpeg CPU per stream
$ ps aux | grep ffmpeg | awk '{sum+=$3} END {print sum "%"}'
# Redis memory
$ redis-cli info memory | grep used_memory_human
# Active network connections
$ ss -s | grep estab
# HLS disk usage
$ du -sh /opt/streaming-server/hls/
Alerting Thresholds:
| Metric | Warning | Critical | Action |
|---|---|---|---|
| SRS Memory | 500MB | 1GB | Schedule restart |
| CPU Usage | 80% | 95% | Reduce ABR levels |
| Disk Usage | 80% | 90% | Cleanup HLS |
| Redis Memory | 100MB | 500MB | Check key expiry |
| Network Conns | 5000 | 10000 | Check for leaks |
10.4 Lessons Learned
- Proactive Restarts: Scheduled restarts prevent memory-related outages
- Polling Trade-offs: Less frequent polling reduces load but delays status updates
- Preset Selection: Video quality vs CPU usage is a critical balance
- Connection Pooling: Essential for high-throughput API services
- Log Analysis: "zombie" count in SRS logs is an early warning indicator
- Buffer Tuning: Player buffering affects both latency and stability
Future Improvements Planned:
| Priority | Improvement | Expected Impact |
|---|---|---|
| HIGH | Hardware encoding (NVENC/QSV) | 90% CPU reduction |
| HIGH | SRS upgrade when memory fix released | No more OOM kills |
| MEDIUM | Redis Cluster for HA | Better availability |
| MEDIUM | CDN integration for HLS delivery | Reduced origin load |
| LOW | WebSocket for real-time dashboard | Eliminate polling |
βΉοΈ About
GetSetLive Streaming Server - Technology Stack and System Information
Technology Stack
Core Runtime
Media & Streaming
Web & Proxy
Database & Cache
Operating System
Security
System Architecture
/opt/streaming-server/
/opt/streaming-server/configs/
/opt/streaming-server/waf/
/opt/streaming-server/hls/
Service Ports
Credits
Developed for GetSetLive - Professional Live Streaming Platform
Admin Dashboard v1.0 - December 2025
