Dashboard

System overview and metrics

CPU Usage

0%

Memory Usage

0%
⏳
Checking...
System Status
πŸ“Š
-
Active Streams
πŸ‘₯
-
Total Users
⚑
-
System Uptime
πŸ’Ύ
-
Storage Used

Service Management

Service Name Status
Loading services...

Recent Activity

Loading... Fetching recent activity...
Stream Key
Status
Broadcaster
Viewers
Duration
Data I/O
Actions
Loading streams...
🎬
0
Total Videos
βœ…
0
Published
βš™οΈ
0
Transcoding
πŸ’Ύ
0 GB
Total Storage
Title / Filename
Duration
Size
Status
Broadcaster
Published
Uploaded
Actions
Loading videos...
⏺️
0
Total Recordings
πŸ’Ύ
0 GB
Total Storage
πŸ—“οΈ
7
Retention (days)
Filename
Stream Key
Size
Modified
Retained Period
Actions
Loading recordings...
🏒
0
Total Organizations
βœ…
0
Active
⏳
0
On Trial
πŸ’°
β‚Ή0
Monthly Revenue
Organization
Plan
Users
Streams
Status
Broadcaster
Created
Actions
Loading organizations...
πŸ‘₯
156
Total Users
🟒
23
Online Now
πŸ‘€
8
Admins
πŸ“Ή
45
Broadcasters
User
Organization
Role
Groups
Status
Lockout
Last Login
Actions
Loading users...
πŸ‘₯
0
Total Groups
βœ…
0
Active
πŸ‘€
0
Total Members
πŸ“Ή
0
Active Streams

Loading groups...

Roles & Permissions

System Roles

πŸ‘‘
Super Admin
System Role
2 users
Full access to all system features, organizations, and settings.
βœ“ Manage All Organizations
βœ“ Manage All Users
βœ“ System Configuration
βœ“ Billing Management
🏒
Organization Admin
System Role
12 users
Full access within their organization. Can manage users, groups, and streams.
βœ“ Manage Org Users
βœ“ Manage Org Groups
βœ“ Manage Org Streams
βœ— System Configuration

Custom Roles

πŸ“Ή
Broadcaster
Custom Role
45 users
Can create and manage their own streams. View analytics for owned streams.
βœ“ Create Streams
βœ“ Manage Own Streams
βœ“ View Analytics
βœ— Manage Users
πŸ‘οΈ
Viewer
Custom Role
89 users
Can view streams and participate in chat. No streaming permissions.
βœ“ View Streams
βœ“ Participate in Chat
βœ— Create Streams
βœ— Manage Users
πŸ›‘οΈ
Moderator
Custom Role
8 users
Can moderate streams and chat. Ban/mute users during streams.
βœ“ Moderate Chat
βœ“ Ban/Mute Users
βœ“ View All Streams
βœ— Create Streams

Subscription Plans

πŸ’΅
β‚Ή1,45,000
Monthly Recurring Revenue
+12% from last month
πŸ“‹
47
Active Subscriptions
πŸ“‰
2.3%
Churn Rate
πŸ’Ž
β‚Ή45,000
Average LTV

Pricing Plans

Starter

β‚Ή 999 /month
  • βœ“ 5 Users
  • βœ“ 2 Concurrent Streams
  • βœ“ 720p Quality
  • βœ“ 50GB Storage
  • βœ“ Email Support
  • βœ— Custom Branding
  • βœ— API Access
12 subscribers

Enterprise

β‚Ή 9,999 /month
  • βœ“ Unlimited Users
  • βœ“ 20 Concurrent Streams
  • βœ“ 4K Quality
  • βœ“ 1TB Storage
  • βœ“ 24/7 Support
  • βœ“ Custom Branding
  • βœ“ Full API Access
8 subscribers

Custom

Contact Sales
  • βœ“ Custom User Limits
  • βœ“ Custom Stream Limits
  • βœ“ Custom Quality
  • βœ“ Custom Storage
  • βœ“ Dedicated Support
  • βœ“ White Label
  • βœ“ SLA Guarantee
4 subscribers

Recent Subscriptions

Organization
Plan
Billing Cycle
Amount
Status
Broadcaster
Next Billing
Actions
Acme Corporation
Enterprise
Annual
β‚Ή99,990/yr
Active
Dec 15, 2025
TechMedia Inc
Professional
Monthly
β‚Ή2,999/mo
Active
Dec 1, 2025
StartupXYZ
Starter
Monthly
β‚Ή999/mo
Trial
Dec 5, 2025

Billing & Invoices

πŸ’°
β‚Ή1,45,000
Total Revenue (This Month)
⏳
β‚Ή23,500
Pending Payments
5 invoices pending
⚠️
β‚Ή8,997
Overdue Amount
2 invoices overdue
βœ…
β‚Ή1,12,503
Collected (This Month)
40 payments received
Invoice #
Organization
Amount
Issue Date
Due Date
Status
Broadcaster
Actions
INV-2025-0047
Acme Corporation
β‚Ή9,999
Nov 15, 2025
Nov 30, 2025
INV-2025-0046
TechMedia Inc
β‚Ή2,999
Nov 10, 2025
Nov 25, 2025
Pending
INV-2025-0045
MediaCorp Ltd
β‚Ή2,999
Nov 1, 2025
Nov 15, 2025
Overdue
INV-2025-0044
StartupXYZ
β‚Ή999
Nov 5, 2025
Nov 20, 2025
Transaction ID
Organization
Amount
Method
Date
Status
Broadcaster
Actions
TXN-20251125-001
Acme Corporation
β‚Ή9,999
πŸ’³ Visa β€’β€’β€’β€’ 4242
Nov 25, 2025
Success
TXN-20251120-003
StartupXYZ
β‚Ή999
πŸ“± UPI
Nov 20, 2025
Success
TXN-20251118-002
TechMedia Inc
β‚Ή2,999
πŸ’³ Mastercard β€’β€’β€’β€’ 5678
Nov 18, 2025
Failed
Credit/Debit Cards Enabled
UPI Enabled
Net Banking Enabled
Bank Transfer Disabled

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 5s
Loading service resources...
Loading logs...
Time IP Address Status Method URI
Loading Caddy access logs...
Loading firewall logs...
Time Status Severity IP Address Method URI / Attack Type
Loading WAF event logs...
πŸ›‘οΈ

Firewall Status

Active - CSF Enabled
πŸ”’

SSL Certificate

Valid - Let's Encrypt
πŸ›‘οΈ

WAF Status

Active
🚫

Blocked IPs

-

Security Events

Loading... Fetching security events...
πŸ“Š

Today's Security Summary

WAF Blocks 0
Firewall Blocks 0
Rate Limited 0
Active Sessions 0

πŸ”₯ CSF Firewall Status

Status: Loading...
Active Rules: Loading...
Blocked IPs: Loading...

πŸ“‹ Firewall Rules

Loading rules...

🚫 Banned IP Addresses (RTMP Rate Limit)

Loading...

βš™οΈ CSF Configuration

Loading configuration...
πŸ”₯

WAF Status

Loading...
βš™οΈ

Current Mode

-
🚫

Blocked Today

0
πŸ“Š

Total Blocked

0
🎯

Attack Types

Loading...

Protection Rules

Loading rules...
Add Custom Rule

IP Management

Loading...
Loading...
Config file: /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

IPv4 addresses only. Changes take effect immediately.
πŸ“‹
0 Whitelisted IPs
πŸ•
- Last Updated
# IP Address Type Actions
Loading whitelisted IPs...
Config file: /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

6px

Section Colors

Container Styling

8px

Typography

18px

Borders & Effects

3

Table Styling

50px
45px

Customization Actions

Customize the appearance of slide-down notifications. Changes are saved to your profile and persist across sessions.

Colors
Dimensions
75%
48px
1px
6px
Position
5px
0px
Text & Padding
14px
14px
16px
40px
Behavior
5s
Live Preview
This is a preview notification message

General Settings

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.

Display Name Service ID (systemd) Status Element ID Enabled Actions

Streaming Configuration

Server, encoding, HLS, and storage settings from streaming.config.json

Server Settings

Domain Settings

Encoding Settings

HLS Settings

Recording Settings

Default retention period is configured here.

Session Settings

Rate Limiting - Auth

Rate Limiting - API

Admin Dashboard

API key is read-only for security

ABR Transcoding Configuration

Adaptive Bitrate quality profiles from abr.config.json

Quality Profiles

Quality profiles for multi-bitrate streaming

Loading quality profiles...

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

Loading IP whitelist...

SRS Server Configuration

View-only: SRS media server configuration from srs.conf

View Only
Loading SRS configuration...
To edit: 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

View Only
Loading Caddy configuration...
To edit: 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:

FeatureDescription
Multi-Protocol IngestRTMP, WebRTC publishing support
ABR Transcoding5 quality levels (1080p to 240p) with FFmpeg
Multi-Protocol DeliveryHLS, HTTP-FLV, WebRTC playback
Admin DashboardReal-time monitoring, stream management, security controls
Enterprise SecurityJWT authentication, WAF protection, CSF firewall
API-First DesignRESTful 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:

ProfileResolutionVideo BitrateAudioUse Case
1080p1920x10805000 kbps192k AACDesktop, Smart TV
720p1280x7202800 kbps128k AACTablet, Fast mobile
480p854x4801400 kbps128k AACMobile 4G
360p640x360800 kbps96k AACMobile 3G
240p426x240400 kbps64k AACLow 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:

ServicePortPurpose
streaming-api1987Stream management, monitoring, admin operations
streaming-auth1988JWT 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:

FeatureKey PatternTTL
JWT Sessionssession:{username}:{timestamp}24 hours
Rate Limitingratelimit:{ip}:{endpoint}60 seconds
Stream Statestream:{streamKey}No expiry
Auth Failuresauthfail:{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

POST /api/auth/login

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 }
  }
}
POST /api/auth/verify

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": "..." }
}
POST /api/auth/logout

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"
}
GET /api/auth/users

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" }
  ]
}
POST /api/auth/users

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" }
}
PUT /api/auth/users/:username

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" }
PATCH /api/auth/users/:username/status

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" }
DELETE /api/auth/users/:username

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" }
POST /api/auth/users/:username/reset-password

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" }
GET /api/auth/users/lockout-status

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": []
}
POST /api/auth/users/:username/unlock

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

GET /api/admin/streams/all

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 }
    }
  ]
}
POST /api/admin/streams/create

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"
}
GET /api/admin/streams/:key/metrics

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 }
}
POST /api/admin/streams/:key/stop

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 /api/admin/streams/:key

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" }
POST /api/test-stream/:key

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" }
POST /api/file-stream/:key

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" }
POST /api/streams/:streamName/viewers/:clientId/block

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

GET /api/admin/recordings

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
}
GET /api/admin/recordings/download/:filename

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 /api/admin/recordings/:filename

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" }
PUT /api/admin/recordings/retention

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

POST /api/upload

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"
  }
}
GET /api/vod

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 /api/vod/:id

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 }
}
PUT /api/vod/:id

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 /api/vod/:id

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" }
POST /api/vod/:id/publish

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 }
POST /api/vod/:id/unpublish

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 }
POST /api/vod/:id/transcode

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" }
GET /api/vod/:id/transcode/status

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 }
GET /api/vod/public

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

GET /api/auth/organizations

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"
    }
  ]
}
POST /api/auth/organizations

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" }
}
PUT /api/auth/organizations/:id

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 /api/auth/organizations/:id

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" }
GET /api/auth/groups

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 }
  ]
}
POST /api/auth/groups

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" } }
GET /api/auth/billing/invoices

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 }
}
POST /api/auth/billing/invoices

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

GET /api/admin/config/streaming

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 }
}
PUT /api/admin/config/streaming

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" }
GET /api/admin/config/whitelist/detailed

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"
    }
  ]
}
POST /api/admin/config/whitelist/add

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" }
POST /api/admin/config/whitelist/remove

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

POST /api/viewer/session

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..."
}
POST /api/viewer/heartbeat

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 /api/viewer/count/:streamKey

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 }
GET /api/admin/streams/:streamKey/hls-viewers

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 /api/admin/security/overview

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
}
GET /api/waf-analytics/events

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
}
GET /api/waf-analytics/access

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 /api/admin/csf/status

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 } }
POST /api/admin/csf/action

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" }
GET /api/admin/banned-ips

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" } ] }
DELETE /api/admin/banned-ips/:ip

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" }
GET http://127.0.0.1:3009/geo?ip=:ip

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 /api/admin/system/stats

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 /api/admin/services/status

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" }
  ]
}
POST /api/admin/services/manage

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" }
POST /api/contact

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" }
GET /api/contact/submissions

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

ComponentMinimumRecommended
OSUbuntu 22.04 LTSUbuntu 24.04 LTS
CPU4 cores8+ cores
RAM8 GB16+ GB
Storage50 GB SSD200+ GB NVMe
Network100 Mbps1 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

MetricValue
Runtime before OOM~22.5 hours
Starting Memory~18MB
Peak Memory at OOM5.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

ParameterBeforeAfterImpact
hls_fragment4s2sReduced latency by 2s
hls_window300s60s80% reduction in disk I/O
hls_playlist_size1020Better buffering stability
hls_dispose300s60sFaster 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

OptimizationSettingResult
Presetveryfast60% CPU reduction
TunezerolatencyReduced encoding delay
Threadsauto (per core)Optimal CPU utilization
GOP Size48 (2s @ 24fps)Better seeking
Keyframe Interval48Segment 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

EndpointBeforeAfterReduction
SRS /api/v1/streams5s15s67%
SRS /api/v1/versions5s60s92%
System stats5s10s50%
Service status5s10s50%
// 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:

MetricWarningCriticalAction
SRS Memory500MB1GBSchedule restart
CPU Usage80%95%Reduce ABR levels
Disk Usage80%90%Cleanup HLS
Redis Memory100MB500MBCheck key expiry
Network Conns500010000Check 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:

PriorityImprovementExpected Impact
HIGHHardware encoding (NVENC/QSV)90% CPU reduction
HIGHSRS upgrade when memory fix releasedNo more OOM kills
MEDIUMRedis Cluster for HABetter availability
MEDIUMCDN integration for HLS deliveryReduced origin load
LOWWebSocket for real-time dashboardEliminate polling

ℹ️ About

GetSetLive Streaming Server - Technology Stack and System Information

Technology Stack

Core Runtime

🟒
Node.js v20.19.5
JavaScript Runtime
πŸ“¦
npm v10.8.2
Package Manager
πŸ”΅
Go v1.22.2
Backend Language

Media & Streaming

🎬
SRS v7.0.94
Media Server (RTMP/HLS/WebRTC)
πŸŽ₯
FFmpeg v6.1.1
ABR Transcoding Engine

Web & Proxy

🌐
Caddy v2.10.2
Web Server & Reverse Proxy
πŸ›‘οΈ
Coraza WAF v3.x
Web Application Firewall

Database & Cache

πŸ”΄
Redis v7.0.15
In-Memory Data Store

Operating System

🐧
Ubuntu 24.04.3 LTS
Linux Distribution

Security

πŸ”₯
CSF Firewall Active
Network Firewall
πŸ”
JWT Auth RS256
Token-Based Authentication

System Architecture

Server Path: /opt/streaming-server/
Config Directory: /opt/streaming-server/configs/
WAF Directory: /opt/streaming-server/waf/
HLS Output: /opt/streaming-server/hls/

Service Ports

443 HTTPS (Caddy)
1935 RTMP (SRS)
1985 SRS API
1987 Streaming API
1988 Auth Service
6379 Redis
8080 SRS HTTP

Credits

Developed for GetSetLive - Professional Live Streaming Platform

Admin Dashboard v1.0 - December 2025