Streaming Server with Nginx-RTMP: Complete Setup Guide
Introduction
Live streaming has become an essential communication tool for content creators, educators, businesses, and gamers worldwide. While platforms like Twitch, YouTube Live, and Facebook Live offer ready-made solutions, hosting your own streaming server provides unparalleled control, privacy, and flexibility. The Nginx-RTMP module transforms the powerful Nginx web server into a full-featured streaming platform capable of handling multiple simultaneous streams, transcoding video in real-time, and distributing content to various platforms.
This comprehensive guide walks you through building a professional-grade streaming server using Nginx with the RTMP (Real-Time Messaging Protocol) module. You'll learn how to configure RTMP ingestion, set up HLS (HTTP Live Streaming) for web playback, implement multi-platform restreaming, add authentication and security, optimize for low latency, and monitor performance.
Whether you're creating a private streaming solution for your organization, building a platform for educational content, setting up a gaming stream server, or developing a foundation for a custom video platform, this guide provides everything needed to deploy a production-ready streaming infrastructure on Linux.
Use Case Overview
Why Host Your Own Streaming Server?
Running a self-hosted streaming server offers significant advantages over relying solely on third-party platforms:
Complete Privacy and Control: Your content remains on infrastructure you control. No algorithms deciding content visibility, no unexpected policy changes, and no platform censorship concerns.
Zero Platform Fees: Commercial streaming platforms often charge for advanced features, higher bitrates, or increased storage. Self-hosting eliminates ongoing platform fees.
Custom Features: Implement custom authentication, integrate with existing systems, add specialized overlays, or build unique interactive features impossible on commercial platforms.
Multi-Platform Distribution: Simultaneously restream to multiple platforms (Twitch, YouTube, Facebook) from a single source, managing everything from one central location.
Lower Latency: Direct RTMP streaming can achieve sub-second latency, crucial for interactive applications, gaming, auctions, or live events where real-time interaction matters.
Unlimited Storage: Record streams with only your storage capacity as the limit, not arbitrary platform restrictions or deletion policies.
Brand Control: Fully white-label streaming experiences with custom players, branding, and user interfaces without platform watermarks or recommendations.
Common Deployment Scenarios
Corporate Communications: Companies streaming internal meetings, training sessions, or company-wide announcements with guaranteed privacy and integration with existing authentication systems.
Educational Streaming: Schools and universities delivering live lectures, seminars, or distance learning programs with recorded archives and custom learning management system integration.
Gaming Tournaments: Esports organizations streaming competitions with low-latency feeds to multiple platforms simultaneously, custom overlays, and instant replay capabilities.
Surveillance and Monitoring: Security systems streaming multiple camera feeds to centralized monitoring stations with recording and playback capabilities.
Religious Organizations: Churches, mosques, temples, and synagogues streaming services to congregation members unable to attend in person, with permanent archives.
Content Creator Networks: Multi-creator platforms where numerous streamers broadcast through shared infrastructure with centralized management and analytics.
Live Events: Conferences, concerts, webinars, and workshops streamed to audiences with optional ticketing, Q&A integration, and high-quality archival.
Technical Capabilities
A properly configured Nginx-RTMP server provides:
- RTMP Ingestion: Accept streams from OBS Studio, Streamlabs, XSplit, and other broadcasting software
- HLS Transcoding: Convert RTMP to HLS for browser-based playback without plugins
- Multi-Bitrate Streaming: Adaptive bitrate streaming for viewers with varying bandwidth
- Recording: Automatic recording of live streams to video files
- DVR Functionality: Pause, rewind, and replay live streams
- Multiple Application Support: Separate streaming applications for different purposes
- Statistics and Monitoring: Real-time metrics on viewers, bitrates, and server performance
- Restreaming: Forward streams to external platforms automatically
Requirements
System Requirements
Minimum Requirements (Single Stream, 720p):
- CPU: 2 cores at 2.5+ GHz (Intel Core i3 or AMD Ryzen 3)
- RAM: 2GB
- Storage: 20GB (more for recording storage)
- Network: 10 Mbps upload (for 720p streaming at 3-4 Mbps bitrate)
- OS: Ubuntu 20.04/22.04, Debian 11/12, CentOS 8, Rocky Linux 8/9
Recommended Requirements (Multiple Streams, 1080p with transcoding):
- CPU: 4+ cores at 3.0+ GHz (Intel Core i5/i7 or AMD Ryzen 5/7)
- RAM: 8GB
- Storage: 100GB+ SSD (for recordings and transcoding cache)
- Network: 50+ Mbps upload bandwidth
- OS: Ubuntu 22.04 LTS (recommended)
High-Performance Requirements (Many simultaneous streams, 4K, heavy transcoding):
- CPU: 8+ cores at 3.5+ GHz (Intel Xeon or AMD EPYC)
- RAM: 16GB+
- Storage: 500GB+ NVMe SSD
- Network: 100+ Mbps dedicated bandwidth with low latency
- OS: Ubuntu 22.04 LTS with kernel optimizations
Bandwidth Considerations
Streaming Bitrate Requirements:
- 480p (SD): 1-2 Mbps
- 720p (HD): 3-5 Mbps
- 1080p (Full HD): 5-8 Mbps
- 1440p (2K): 8-12 Mbps
- 2160p (4K): 15-25 Mbps
Calculate total bandwidth: (Number of simultaneous streams × bitrate) + (Number of viewers × bitrate)
For example, hosting 5 simultaneous 1080p streams with 100 viewers:
- Ingest: 5 streams × 6 Mbps = 30 Mbps
- Viewers: 100 viewers × 6 Mbps = 600 Mbps
- Total: ~630 Mbps
Content Delivery Networks (CDNs) significantly reduce server bandwidth requirements for large audiences.
Software Requirements
Build Dependencies: GCC compiler, make, build tools, and development libraries for compiling Nginx with RTMP module.
FFmpeg: Required for transcoding, recording, and format conversion. Version 4.0 or newer recommended.
SSL/TLS Certificates: Let's Encrypt for HTTPS delivery of HLS streams (optional but recommended).
Video Players: Video.js, HLS.js, or custom HTML5 players for browser-based playback.
Network Requirements
Open Ports:
- 1935/TCP: RTMP streaming protocol (incoming streams)
- 80/TCP: HTTP for HLS delivery (if not using separate web server)
- 443/TCP: HTTPS for secure HLS delivery
- 8080/TCP: Optional statistics page
Firewall Configuration: Allow incoming connections on RTMP and HTTP/HTTPS ports.
Low Latency Network: Lower latency improves streaming experience. Sub-50ms latency to streamers ideal.
Prerequisites Knowledge
- Linux command-line proficiency
- Basic understanding of video codecs and streaming protocols
- Familiarity with Nginx web server configuration
- Network configuration knowledge (ports, firewalls, DNS)
- Basic video broadcasting software operation (OBS Studio recommended)
Step-by-Step Setup
Step 1: System Preparation and Updates
Connect to your Linux server via SSH and update system packages:
# Ubuntu/Debian
sudo apt update && sudo apt upgrade -y
# CentOS/Rocky Linux
sudo dnf update -y
Install essential build tools and dependencies:
# Ubuntu/Debian
sudo apt install -y build-essential libpcre3 libpcre3-dev libssl-dev \
zlib1g-dev git wget unzip
# CentOS/Rocky Linux
sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y pcre-devel openssl-devel zlib-devel git wget unzip
Step 2: Install FFmpeg
FFmpeg handles video transcoding and recording.
Ubuntu/Debian:
sudo apt install -y ffmpeg
CentOS/Rocky Linux:
# Enable EPEL repository
sudo dnf install -y epel-release
# Enable RPM Fusion repository
sudo dnf install -y --nogpgcheck \
https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-$(rpm -E %rhel).noarch.rpm
# Install FFmpeg
sudo dnf install -y ffmpeg
Verify installation:
ffmpeg -version
Step 3: Download Nginx and RTMP Module
Create working directory:
cd /tmp
Download Nginx source (use latest stable version):
wget http://nginx.org/download/nginx-1.24.0.tar.gz
tar -xzf nginx-1.24.0.tar.gz
Download nginx-rtmp-module:
git clone https://github.com/arut/nginx-rtmp-module.git
Step 4: Compile Nginx with RTMP Module
Navigate to Nginx source directory:
cd nginx-1.24.0
Configure build with RTMP module:
./configure \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib64/nginx/modules \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_stub_status_module \
--with-http_auth_request_module \
--with-threads \
--with-stream \
--with-stream_ssl_module \
--with-http_slice_module \
--with-file-aio \
--with-http_v2_module \
--add-module=/tmp/nginx-rtmp-module
Compile and install:
make -j$(nproc)
sudo make install
This process takes several minutes depending on CPU performance.
Step 5: Create Nginx User and Directories
Create nginx user:
sudo useradd -r -M -s /sbin/nologin nginx
Create required directories:
sudo mkdir -p /var/cache/nginx/client_temp
sudo mkdir -p /var/cache/nginx/proxy_temp
sudo mkdir -p /var/cache/nginx/fastcgi_temp
sudo mkdir -p /var/cache/nginx/uwsgi_temp
sudo mkdir -p /var/cache/nginx/scgi_temp
sudo mkdir -p /var/www/html/hls
sudo mkdir -p /var/www/html/dash
sudo mkdir -p /var/www/html/recordings
sudo chown -R nginx:nginx /var/www/html
sudo chown -R nginx:nginx /var/cache/nginx
Step 6: Configure Nginx with RTMP
Create main Nginx configuration:
sudo nano /etc/nginx/nginx.conf
Add the following comprehensive configuration:
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
# RTMP configuration
rtmp {
server {
listen 1935;
chunk_size 4096;
allow publish 127.0.0.1;
deny publish all;
# Main live streaming application
application live {
live on;
record off;
# HLS packaging
hls on;
hls_path /var/www/html/hls;
hls_fragment 3;
hls_playlist_length 60;
# Disable consuming the stream from nginx as rtmp
deny play all;
}
# Recording application
application recording {
live on;
record all;
record_path /var/www/html/recordings;
record_suffix -%Y%m%d-%H%M%S.flv;
record_unique on;
hls on;
hls_path /var/www/html/hls;
hls_fragment 3;
hls_playlist_length 60;
}
# Streaming application with authentication
application secure {
live on;
# Enable stream key authentication
on_publish http://localhost/auth;
hls on;
hls_path /var/www/html/hls;
hls_fragment 3;
hls_playlist_length 60;
}
}
}
# HTTP configuration
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# HLS delivery
server {
listen 80;
server_name _;
# HLS stream delivery
location /hls {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root /var/www/html;
add_header Cache-Control no-cache;
add_header Access-Control-Allow-Origin *;
}
# DASH stream delivery
location /dash {
root /var/www/html;
add_header Cache-Control no-cache;
add_header Access-Control-Allow-Origin *;
}
# Recordings
location /recordings {
root /var/www/html;
autoindex on;
add_header Access-Control-Allow-Origin *;
}
# Statistics
location /stat {
rtmp_stat all;
rtmp_stat_stylesheet stat.xsl;
}
location /stat.xsl {
root /etc/nginx;
}
# Test player page
location /player {
root /var/www/html;
index player.html;
}
}
}
Save and exit.
Step 7: Create Systemd Service
Create systemd service file:
sudo nano /etc/systemd/system/nginx.service
Add the following content:
[Unit]
Description=Nginx RTMP Streaming Server
After=network.target
[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
Enable and start Nginx:
sudo systemctl daemon-reload
sudo systemctl enable nginx
sudo systemctl start nginx
Check status:
sudo systemctl status nginx
Step 8: Configure Firewall
Open required ports:
# UFW (Ubuntu/Debian)
sudo ufw allow 1935/tcp comment 'RTMP'
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
# Firewalld (CentOS/Rocky Linux)
sudo firewall-cmd --permanent --add-port=1935/tcp
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
Step 9: Create Test HTML Player
Create a simple test player:
sudo mkdir -p /var/www/html/player
sudo nano /var/www/html/player/player.html
Add this HTML5 player using Video.js:
<!DOCTYPE html>
<html>
<head>
<title>RTMP Stream Player</title>
<link href="https://vjs.zencdn.net/8.6.1/video-js.css" rel="stylesheet" />
<style>
body {
font-family: Arial, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: #1a1a1a;
color: #fff;
}
h1 {
text-align: center;
}
.video-container {
max-width: 900px;
margin: 0 auto;
}
.info {
background: #2a2a2a;
padding: 20px;
margin-top: 20px;
border-radius: 5px;
}
</style>
</head>
<body>
<h1>Live Stream Player</h1>
<div class="video-container">
<video id="my-video" class="video-js vjs-default-skin" controls preload="auto"
width="900" height="506" data-setup='{}'>
<source src="http://YOUR_SERVER_IP/hls/stream.m3u8" type="application/x-mpegURL">
</video>
</div>
<div class="info">
<h2>Stream Information</h2>
<p><strong>RTMP URL:</strong> rtmp://YOUR_SERVER_IP/live</p>
<p><strong>Stream Key:</strong> stream</p>
<p><strong>HLS Playback URL:</strong> http://YOUR_SERVER_IP/hls/stream.m3u8</p>
</div>
<script src="https://vjs.zencdn.net/8.6.1/video.min.js"></script>
</body>
</html>
Replace YOUR_SERVER_IP with your actual server IP address.
Set permissions:
sudo chown -R nginx:nginx /var/www/html/player
Step 10: Test the Streaming Setup
Configure OBS Studio (or similar broadcasting software):
- Download and install OBS Studio from obsproject.com
- Open OBS Studio
- Go to Settings > Stream
- Select "Custom" as Service
- Enter Server:
rtmp://YOUR_SERVER_IP/live - Enter Stream Key:
stream - Click OK
Start Streaming:
- Add sources to OBS (webcam, screen capture, etc.)
- Click "Start Streaming"
- OBS should connect to your server
Watch Stream:
Open browser and navigate to:
http://YOUR_SERVER_IP/player/player.html
The stream should appear after a few seconds of buffering.
Configuration
RTMP Applications Configuration
The RTMP module supports multiple applications for different purposes.
Basic Live Streaming Application:
application live {
live on;
record off;
# Allow publishing from specific IPs
allow publish 192.168.1.0/24;
allow publish 10.0.0.0/8;
deny publish all;
# Allow playback from anywhere
allow play all;
# HLS settings
hls on;
hls_path /var/www/html/hls;
hls_fragment 3;
hls_playlist_length 60;
hls_cleanup on;
}
Recording Application:
application recording {
live on;
# Record all streams
record all;
record_path /var/www/html/recordings;
record_suffix -%Y%m%d-%H%M%S.flv;
record_unique on;
record_max_size 1024M;
record_max_frames 2;
# Optional: execute command when recording finishes
exec_record_done ffmpeg -i $path -codec copy /var/www/html/recordings/$basename.mp4;
}
Multi-Bitrate Streaming:
application live {
live on;
# Create multiple quality variants
exec ffmpeg -i rtmp://localhost/live/$name
-c:v libx264 -preset veryfast -tune zerolatency -b:v 5000k -maxrate 5000k -bufsize 10000k -s 1920x1080 -c:a aac -b:a 128k -f flv rtmp://localhost/hls/$name_1080p
-c:v libx264 -preset veryfast -tune zerolatency -b:v 3000k -maxrate 3000k -bufsize 6000k -s 1280x720 -c:a aac -b:a 128k -f flv rtmp://localhost/hls/$name_720p
-c:v libx264 -preset veryfast -tune zerolatency -b:v 1500k -maxrate 1500k -bufsize 3000k -s 854x480 -c:a aac -b:a 96k -f flv rtmp://localhost/hls/$name_480p;
}
application hls {
live on;
hls on;
hls_path /var/www/html/hls;
hls_fragment 3;
hls_playlist_length 60;
hls_variant _1080p BANDWIDTH=5128000;
hls_variant _720p BANDWIDTH=3128000;
hls_variant _480p BANDWIDTH=1596000;
}
Stream Authentication
Implement stream key authentication to prevent unauthorized streaming:
Create authentication script:
sudo nano /var/www/html/auth.php
<?php
// Simple stream key authentication
$valid_keys = [
'secret_key_1' => 'streamer1',
'secret_key_2' => 'streamer2',
'secret_key_3' => 'streamer3'
];
$stream_key = $_POST['name'] ?? '';
if (array_key_exists($stream_key, $valid_keys)) {
http_response_code(200);
echo "OK";
} else {
http_response_code(403);
echo "Forbidden";
}
?>
Install PHP:
sudo apt install php-fpm -y
Configure Nginx for PHP:
Add to HTTP server block:
location /auth {
fastcgi_pass unix:/var/run/php/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME /var/www/html/auth.php;
include fastcgi_params;
}
Update RTMP application:
application secure {
live on;
on_publish http://localhost/auth;
hls on;
hls_path /var/www/html/hls;
}
HLS Configuration Optimization
Low Latency Settings:
hls on;
hls_path /var/www/html/hls;
hls_fragment 2; # Smaller fragments = lower latency
hls_playlist_length 10; # Shorter playlist = lower latency
hls_cleanup on;
hls_nested on; # Organize by stream name
High Compatibility Settings:
hls on;
hls_path /var/www/html/hls;
hls_fragment 6; # Larger fragments = better compatibility
hls_playlist_length 60;
hls_type live;
hls_continuous on; # Don't reset on disconnect
Restreaming to Multiple Platforms
Configure automatic restreaming to Twitch, YouTube, and Facebook:
application multistream {
live on;
# Stream to Twitch
push rtmp://live.twitch.tv/app/YOUR_TWITCH_STREAM_KEY;
# Stream to YouTube
push rtmp://a.rtmp.youtube.com/live2/YOUR_YOUTUBE_STREAM_KEY;
# Stream to Facebook
push rtmps://live-api-s.facebook.com:443/rtmp/YOUR_FACEBOOK_STREAM_KEY;
# Local HLS
hls on;
hls_path /var/www/html/hls;
hls_fragment 3;
hls_playlist_length 60;
}
Streamers use this application to simultaneously broadcast to all platforms:
rtmp://YOUR_SERVER_IP/multistream/YOUR_STREAM_KEY
DVR and Time-Shift Configuration
Enable DVR functionality for pause/rewind:
application dvr {
live on;
# Enable HLS DVR
hls on;
hls_path /var/www/html/hls;
hls_fragment 6;
hls_playlist_length 3600; # 1 hour of DVR
hls_type event; # Event type for DVR
hls_continuous on;
}
Statistics Page Setup
Copy the statistics stylesheet:
sudo wget https://raw.githubusercontent.com/arut/nginx-rtmp-module/master/stat.xsl -O /etc/nginx/stat.xsl
Access statistics at: http://YOUR_SERVER_IP/stat
Optimization
Worker Process Optimization
Optimize Nginx worker processes based on CPU cores:
# Set to number of CPU cores
worker_processes auto;
events {
worker_connections 4096; # Increase for many concurrent connections
use epoll; # Linux-specific optimization
multi_accept on;
}
RTMP Performance Tuning
rtmp {
server {
listen 1935;
chunk_size 4096; # Default, can increase to 8192 for better performance
max_connections 1000; # Limit total connections
application live {
live on;
# Limit bitrate
max_bitrate 10000k;
# Buffer settings
buffer 5s;
# Drop slow clients
drop_idle_publisher 10s;
# Synchronization
sync 10ms;
}
}
}
FFmpeg Transcoding Optimization
Hardware Acceleration with NVIDIA GPU:
exec ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i rtmp://localhost/live/$name
-c:v h264_nvenc -preset fast -b:v 3000k -maxrate 3000k -bufsize 6000k -s 1280x720
-c:a aac -b:a 128k -f flv rtmp://localhost/hls/$name_720p;
CPU Optimization:
exec ffmpeg -threads 4 -i rtmp://localhost/live/$name
-c:v libx264 -preset veryfast -tune zerolatency -profile:v baseline
-b:v 3000k -maxrate 3000k -bufsize 6000k -s 1280x720
-c:a aac -b:a 128k -f flv rtmp://localhost/hls/$name_720p;
Network Buffer Optimization
System-wide TCP tuning:
sudo nano /etc/sysctl.conf
Add:
# Increase TCP buffer sizes
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864
# Optimize connection handling
net.ipv4.tcp_max_syn_backlog = 8192
net.core.netdev_max_backlog = 5000
net.core.somaxconn = 1024
# Enable TCP Fast Open
net.ipv4.tcp_fastopen = 3
Apply changes:
sudo sysctl -p
Storage Optimization
Use SSD/NVMe for HLS fragments:
HLS generation involves many small file writes. Fast storage significantly improves performance.
Tmpfs for temporary HLS files (reduces disk I/O):
sudo mkdir -p /tmp/hls
sudo mount -t tmpfs -o size=2G tmpfs /tmp/hls
Update nginx.conf:
hls_path /tmp/hls;
Make persistent across reboots by adding to /etc/fstab:
tmpfs /tmp/hls tmpfs defaults,size=2G 0 0
Load Balancing Multiple Servers
For large-scale deployments, use multiple streaming servers:
Origin Server (receives streams):
application origin {
live on;
push rtmp://edge1.example.com/live;
push rtmp://edge2.example.com/live;
}
Edge Servers (deliver to viewers):
application live {
live on;
pull rtmp://origin.example.com/origin/$name;
hls on;
hls_path /var/www/html/hls;
}
Use DNS round-robin or load balancer to distribute viewer traffic across edge servers.
Troubleshooting
Stream Not Appearing
Check if Nginx is receiving the stream:
# Check RTMP statistics
curl http://localhost/stat
# Check nginx error log
sudo tail -f /var/log/nginx/error.log
# Verify port 1935 is listening
sudo netstat -tlnp | grep 1935
Verify OBS connection:
In OBS, check the bottom status bar. Should show green "Live" indicator with bitrate.
Check firewall:
# UFW
sudo ufw status
# Firewalld
sudo firewall-cmd --list-all
Ensure port 1935 is allowed.
Check HLS directory permissions:
ls -la /var/www/html/hls
Should be owned by nginx user:
sudo chown -R nginx:nginx /var/www/html/hls
Playback Issues
HLS files not generating:
# Check if HLS directory exists and has write permissions
ls -la /var/www/html/hls/
# Watch for new .ts and .m3u8 files being created
watch -n 1 ls -la /var/www/html/hls/
CORS errors in browser console:
Ensure CORS headers are set:
location /hls {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, OPTIONS";
}
High latency:
Reduce HLS fragment size:
hls_fragment 2;
hls_playlist_length 10;
Buffering issues:
Check viewer bandwidth:
- 480p requires 1-2 Mbps
- 720p requires 3-5 Mbps
- 1080p requires 5-8 Mbps
Implement adaptive bitrate streaming with multiple quality variants.
High CPU Usage
Identify cause:
# Check nginx worker CPU usage
top -p $(pgrep nginx | tr '\n' ',' | sed 's/,$//')
# Check ffmpeg processes
ps aux | grep ffmpeg
Solutions:
- Reduce transcoding complexity (use faster presets)
- Limit number of quality variants
- Use hardware acceleration (GPU encoding)
- Increase CPU resources
Optimize FFmpeg settings:
exec ffmpeg -threads 2 -i rtmp://localhost/live/$name
-c:v libx264 -preset ultrafast -tune zerolatency
-c:a copy -f flv rtmp://localhost/hls/$name;
Recording Issues
Recordings not saving:
# Check recording directory permissions
ls -la /var/www/html/recordings/
# Set correct permissions
sudo chown -R nginx:nginx /var/www/html/recordings/
sudo chmod 755 /var/www/html/recordings/
Check available disk space:
df -h /var/www/html/recordings/
Disk full errors:
Implement automatic cleanup:
record_max_size 2048M; # Limit recording file size
# Or use cron job to delete old recordings
0 2 * * * find /var/www/html/recordings -name "*.flv" -mtime +7 -delete
Authentication Not Working
Check PHP-FPM status:
sudo systemctl status php-fpm
Verify auth script:
curl -X POST -d "name=secret_key_1" http://localhost/auth
Should return "OK" for valid keys, "Forbidden" for invalid.
Check nginx error log:
sudo tail -f /var/log/nginx/error.log
Look for FastCGI or authentication errors.
Connection Drops
Increase timeouts:
rtmp {
server {
timeout 60s;
ping 30s;
ping_timeout 30s;
}
}
Check network stability:
# Ping test
ping -c 100 YOUR_SERVER_IP
# Check for packet loss
mtr YOUR_SERVER_IP
Increase buffer sizes:
application live {
live on;
buffer 10s; # Increase buffer
}
Advanced Features
SSL/TLS for Secure Streaming
Install Certbot for Let's Encrypt:
sudo apt install certbot -y
Obtain certificate:
sudo certbot certonly --standalone -d stream.example.com
Configure HTTPS in nginx:
server {
listen 443 ssl http2;
server_name stream.example.com;
ssl_certificate /etc/letsencrypt/live/stream.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/stream.example.com/privkey.pem;
location /hls {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root /var/www/html;
add_header Cache-Control no-cache;
add_header Access-Control-Allow-Origin *;
}
}
Custom Video Player with Controls
Create advanced player with quality selection:
<!DOCTYPE html>
<html>
<head>
<title>Advanced Stream Player</title>
<link href="https://vjs.zencdn.net/8.6.1/video-js.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/videojs-contrib-quality-levels@2/dist/videojs-contrib-quality-levels.css" rel="stylesheet" />
</head>
<body>
<video id="player" class="video-js vjs-default-skin" controls width="1280" height="720">
<source src="https://stream.example.com/hls/stream.m3u8" type="application/x-mpegURL">
</video>
<script src="https://vjs.zencdn.net/8.6.1/video.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/videojs-contrib-quality-levels@2/dist/videojs-contrib-quality-levels.min.js"></script>
<script>
var player = videojs('player', {
liveui: true,
controls: true,
autoplay: true,
preload: 'auto'
});
</script>
</body>
</html>
Webhook Notifications
Execute scripts on stream events:
application live {
live on;
# Execute on stream start
on_publish http://localhost/webhook/publish;
# Execute on stream end
on_publish_done http://localhost/webhook/publish_done;
# Execute on playback start
on_play http://localhost/webhook/play;
}
Create webhook handler:
<?php
// /var/www/html/webhook/publish.php
$stream = $_POST['name'] ?? 'unknown';
$timestamp = date('Y-m-d H:i:s');
// Log event
file_put_contents('/var/log/nginx/stream_events.log',
"$timestamp - Stream started: $stream\n", FILE_APPEND);
// Send notification (email, Slack, Discord, etc.)
// Example: mail('[email protected]', 'Stream Started', "Stream $stream is now live");
http_response_code(200);
?>
Conclusion
You now have a fully functional, professional-grade streaming server powered by Nginx-RTMP. This setup provides enterprise-level streaming capabilities with complete control over your content, viewer experience, and data.
Key achievements from this guide:
- Custom streaming infrastructure independent of commercial platforms
- Multi-format delivery supporting RTMP ingestion and HLS playback
- Production-ready configuration with authentication, recording, and monitoring
- Optimized performance for low latency and high concurrent viewer counts
- Scalability foundation ready for expansion with load balancing and CDN integration
- Advanced features including multi-bitrate streaming, DVR, and multi-platform restreaming
The modular architecture allows incremental improvements. Start with basic streaming and progressively add features like transcoding, authentication, analytics, and content delivery network integration as requirements grow.
Remember to monitor server performance regularly, implement regular backups of configuration files and recordings, and keep Nginx and FFmpeg updated for security and performance improvements. The streaming landscape continuously evolves, so staying informed about new protocols (like SRT and WebRTC) and optimization techniques ensures your infrastructure remains cutting-edge.
Whether hosting personal streams, building a platform for content creators, delivering corporate communications, or creating educational content, this Nginx-RTMP foundation provides the flexibility and power needed for professional streaming operations.
Happy streaming!


