Complete Node Media Server Setup Guide
Step-by-step tutorial for installing and configuring Node Media Server on Linux. Learn RTMP server setup, HLS streaming, authentication, FFmpeg transcoding, security hardening, and production deployment. Estimated time: 2-3 hours.
Prerequisites & Requirements
Server Requirements
Minimum Specs (5-10 streams):
- • CPU: 2 cores (2.0 GHz+)
- • RAM: 2 GB minimum
- • Storage: 20 GB SSD
- • Network: 100 Mbps port
- • Bandwidth: 1 TB/month minimum
- • OS: Ubuntu 20.04/22.04 or CentOS 8+
Recommended (20-50 streams):
- • CPU: 4-8 cores (3.0 GHz+)
- • RAM: 8-16 GB
- • Storage: 100+ GB SSD NVMe
- • Network: 1 Gbps dedicated port
Software Requirements
Required:
- • Node.js: Version 10.x or higher (14.x+ recommended)
- • npm: Comes with Node.js installation
- • SSH Access: Root or sudo privileges
- • Text Editor: nano, vim, or VS Code remote
Optional (But Recommended):
- • FFmpeg: For HLS/DASH transcoding
- • PM2: Process manager for production
- • Nginx: Reverse proxy for SSL/load balancing
- • Domain Name: For SSL certificate (Let's Encrypt)
Knowledge Prerequisites
To complete this guide successfully, you should have:
- Linux CLI Basics: Navigate directories, edit files, manage processes
- Node.js Familiarity: Understand npm, package.json, running Node apps
- Networking Basics: Ports, firewalls, IP addresses, TCP/UDP protocols
- Streaming Concepts: RTMP, HLS, encoders (OBS), bitrates, codecs
Install Node.js and npm
Node Media Server requires Node.js runtime. We'll install Node.js 18.x LTS (Long Term Support) which provides the best stability and performance.
On Ubuntu 20.04/22.04:
First, install Node.js using NodeSource repository (recommended method):
sudo apt update && sudo apt upgrade -y
# Install Node.js 18.x LTS from NodeSource
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs
# Verify installation
node --version # Should show v18.x.x
npm --version # Should show 9.x.x or higher
Alternative: Use apt install nodejs npm but this may install older versions. NodeSource gives you the latest LTS release.
On CentOS 8/RHEL 8:
sudo dnf install epel-release -y
# Install Node.js 18.x from NodeSource
curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash -
sudo dnf install -y nodejs
# Verify installation
node --version
npm --version
Install Build Tools (Optional):
Some npm packages require compilation. Install build tools just in case:
sudo apt install -y build-essential
# CentOS/RHEL
sudo dnf groupinstall "Development Tools" -y
Install Node Media Server Package
Now we'll create a project directory and install the node-media-server npm package.
Create Project Directory:
sudo mkdir -p /opt/streaming-server
cd /opt/streaming-server
# Initialize npm project
npm init -y
Install Node Media Server:
npm install node-media-server --save
# Verify installation
npm list node-media-server
Note: You can also install globally with npm install -g node-media-server but local installation is recommended for production environments.
Create Basic Server File:
Create server.js file with basic RTMP configuration:
const config = {
rtmp: {
port: 1935,
chunk_size: 60000,
gop_cache: true,
ping: 30,
ping_timeout: 60
},
http: {
port: 8000,
allow_origin: '*'
}
};
var nms = new NodeMediaServer(config);
nms.run();
console.log('Node Media Server running...');
console.log('RTMP: rtmp://localhost:1935');
console.log('HTTP-FLV: http://localhost:8000');
Save this as /opt/streaming-server/server.js. You can test it with: node server.js
Configure RTMP Server
Let's enhance the RTMP configuration with production-ready settings for optimal streaming performance.
Advanced RTMP Configuration:
rtmp: {
port: 1935,
chunk_size: 60000, // Data chunk size (bytes)
gop_cache: true, // Enable GOP cache for instant playback
ping: 30, // Ping interval (seconds)
ping_timeout: 60 // Ping timeout (seconds)
},
http: {
port: 8000,
mediaroot: './media', // Media file storage path
allow_origin: '*' // CORS header
},
logType: 3 // 0=no log, 1=error, 2=normal, 3=debug
};
Configuration Parameters Explained:
- port (1935): Standard RTMP port. Keep default unless you have port conflicts.
- chunk_size (60000): Larger = better throughput, smaller = lower latency. 60KB is good balance.
- gop_cache (true): Caches Group of Pictures for instant stream start. Highly recommended!
- ping/ping_timeout: Keeps connection alive. Default values work for most cases.
- allow_origin (*): Allows cross-origin playback. Restrict in production for security.
Firewall Configuration:
Open RTMP port (1935) and HTTP port (8000) in your firewall:
sudo ufw allow 1935/tcp
sudo ufw allow 8000/tcp
sudo ufw reload
# Firewalld (CentOS)
sudo firewall-cmd --permanent --add-port=1935/tcp
sudo firewall-cmd --permanent --add-port=8000/tcp
sudo firewall-cmd --reload
Enable HLS and DASH Streaming
HTTP Live Streaming (HLS) enables adaptive bitrate streaming compatible with iOS, Android, and modern web browsers. Requires FFmpeg for transcoding.
Install FFmpeg:
sudo apt install -y ffmpeg
# CentOS 8+ (Enable RPM Fusion first)
sudo dnf install -y ffmpeg
# Verify installation
ffmpeg -version
Configure HLS Transcoding:
Update your server.js with transcoding configuration:
rtmp: {
port: 1935,
chunk_size: 60000,
gop_cache: true,
ping: 30,
ping_timeout: 60
},
http: {
port: 8000,
mediaroot: './media',
allow_origin: '*'
},
trans: {
ffmpeg: '/usr/bin/ffmpeg',
tasks: [
{
app: 'live',
hls: true,
hlsFlags: '[hls_time=2:hls_list_size=3:hls_flags=delete_segments]',
dash: true,
dashFlags: '[f=dash:window_size=3:extra_window_size=5]'
}
]
}
};
HLS Configuration Explained:
- app: 'live': Applies transcoding to streams published to /live/* path
- hls: true: Enables HLS output generation
- hls_time: 2: Segment duration 2 seconds (lower = lower latency but more files)
- hls_list_size: 3: Keep 3 segments in playlist (memory optimization)
- delete_segments: Auto-delete old segments to save disk space
- dash: true: Also generates MPEG-DASH for universal browser support
Playback URLs:
- • RTMP:
rtmp://yourserver:1935/live/streamkey - • HTTP-FLV:
http://yourserver:8000/live/streamkey.flv - • HLS:
http://yourserver:8000/live/streamkey/index.m3u8
Implement Authentication & Security
By default, anyone can publish to your server. Let's add authentication to control who can stream and view content.
Event-Based Authentication:
Node Media Server triggers events you can hook into. Add this code to your server.js:
// ... config object here ...
var nms = new NodeMediaServer(config);
nms.run();
// Hook: Before someone publishes a stream
nms.on('prePublish', (id, StreamPath, args) => {
console.log('[NodeEvent on prePublish]', `id=${id} StreamPath=${StreamPath} args=${JSON.stringify(args)}`);
// Extract stream key from path (e.g., /live/streamkey -> streamkey)
let stream_key = getStreamKeyFromStreamPath(StreamPath);
// Validate stream key (check database, hardcoded list, etc.)
if (!isValidStreamKey(stream_key)) {
console.log('[Auth] Invalid stream key, rejecting:', stream_key);
let session = nms.getSession(id);
session.reject(); // Reject the connection
} else {
console.log('[Auth] Valid stream key, allowing:', stream_key);
}
});
// Hook: Before someone plays a stream
nms.on('prePlay', (id, StreamPath, args) => {
console.log('[NodeEvent on prePlay]', `id=${id} StreamPath=${StreamPath}`);
// Add viewer authentication logic here if needed
// For public streams, you can leave this empty
});
// Helper function to extract stream key from path
function getStreamKeyFromStreamPath(path) {
let parts = path.split('/');
return parts[parts.length - 1];
}
// Validation function (customize for your needs)
function isValidStreamKey(key) {
// Example: Hardcoded list of allowed keys
const allowedKeys = ['secret123', 'mystream', 'live2024'];
return allowedKeys.includes(key);
// OR: Check against database
// return db.streamKeys.find(k => k.key === key && k.active);
}
Available Events:
- •
prePublish- Before stream publish (auth check) - •
postPublish- After publish starts (logging, notifications) - •
donePublish- Stream ended (cleanup, save stats) - •
prePlay- Before viewer plays stream (viewer auth) - •
postPlay- Viewer connected (analytics) - •
donePlay- Viewer disconnected (viewer stats)
Database Integration Example:
For production, validate stream keys against a database (MySQL, PostgreSQL, MongoDB):
const db = mysql.createPool({
host: 'localhost',
user: 'streamuser',
password: 'password',
database: 'streaming'
});
async function isValidStreamKey(key) {
try {
const [rows] = await db.query(
'SELECT * FROM stream_keys WHERE stream_key = ? AND active = 1',
[key]
);
return rows.length > 0;
} catch (err) {
console.error('Database error:', err);
return false;
}
}
Connect Encoder (OBS Studio)
Now let's configure OBS Studio to stream to your Node Media Server. These settings also apply to other encoders like vMix, Wirecast, or FFmpeg.
OBS Studio Configuration
-
Open OBS Studio
Go toFile → Settings → Stream -
Service: Select
Custom... -
Server:
rtmp://YOUR_SERVER_IP:1935/live -
Stream Key:
secret123(or your authenticated key) - Click Apply and OK
Recommended Encoder Settings
Output Settings:
- • Video Bitrate: 2500-4500 kbps (720p-1080p)
- • Audio Bitrate: 128-160 kbps
- • Encoder: x264 (software) or NVENC (hardware)
- • Rate Control: CBR (Constant Bitrate)
- • Keyframe Interval: 2 seconds
Video Settings:
- • Resolution: 1920x1080 or 1280x720
- • FPS: 30 or 60 fps
- • Preset: veryfast or faster
Test Your Stream:
- Click Start Streaming in OBS Studio
- Check server logs:
node server.jsshould show connection - Test playback with VLC or online players:
- • RTMP URL:
rtmp://YOUR_SERVER_IP:1935/live/secret123 - • HTTP-FLV URL:
http://YOUR_SERVER_IP:8000/live/secret123.flv - • HLS URL:
http://YOUR_SERVER_IP:8000/live/secret123/index.m3u8
Production Deployment with PM2
Don't run node server.js manually in production. Use PM2 process manager for automatic restarts, monitoring, and log management.
Install PM2:
sudo npm install -g pm2
# Start your server with PM2
cd /opt/streaming-server
pm2 start server.js --name "streaming-server"
# Enable auto-start on server reboot
pm2 startup
pm2 save
PM2 Management Commands:
Basic Commands:
pm2 logs streaming-server # View logs
pm2 restart streaming-server # Restart
pm2 stop streaming-server # Stop
pm2 delete streaming-server # Remove
pm2 monit # Monitoring dashboard
Advanced Commands:
pm2 flush # Clear logs
pm2 scale streaming-server 4 # Scale to 4 instances
pm2 reload streaming-server # Zero-downtime reload
pm2 describe streaming-server # Detailed info
Alternative: Systemd Service:
Create systemd service for native Linux integration:
sudo nano /etc/systemd/system/streaming.service
# Add this content:
[Unit]
Description=Node Media Streaming Server
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/streaming-server
ExecStart=/usr/bin/node server.js
Restart=always
RestartSec=10
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=streaming-server
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable streaming.service
sudo systemctl start streaming.service
# Check status
sudo systemctl status streaming.service
Monitoring & Troubleshooting
HTTP API for Monitoring
Enable HTTP API in your config:
port: 8000,
allow_origin: '*',
api: true // Enable API
}
API Endpoints:
- •
GET /api/streams- List all streams - •
GET /api/server- Server stats - •
POST /api/streams/:app/:stream/stop- Stop stream
Common Issues & Solutions
-
Connection Refused:
Check firewall (port 1935), verify server running, check IP address -
Stream Won't Play:
Check GOP cache enabled, verify FFmpeg installed for HLS, test with VLC -
High CPU Usage:
Disable transcoding if not needed, reduce number of streams, upgrade server -
Authentication Not Working:
Check event hooks, verify stream key validation logic, review logs
Useful Debugging Commands:
ps aux | grep node
# Check open ports
sudo netstat -tulpn | grep :1935
sudo netstat -tulpn | grep :8000
# Monitor server logs
pm2 logs streaming-server --lines 50
# Test RTMP connectivity from another machine
ffmpeg -i rtmp://YOUR_SERVER:1935/live/test -f null -
# Check server resource usage
htop
df -h # Disk space
free -h # Memory
Completed the Setup? Here's What to Expect Next...
Congratulations on setting up your Node Media Server! Now begins the ongoing maintenance:
- Weekly: Security patches, Node.js updates, monitoring downtime
- Monthly: Bandwidth cost surprises, log file cleanup, backup verification
- When Issues Hit: Debug at 2 AM, research error messages, community forum searches
- Scaling: Configure load balancers, CDN integration, database optimization
Reality Check: Most users spend 4-8 hours/month maintaining their streaming server. At $50/hr, that's $200-400/month in hidden costs - far more than managed hosting.
Next Steps & Resources
Secure with SSL
Setup Nginx reverse proxy with Let's Encrypt SSL certificate for HTTPS/RTMPS
SSL GuideOptimize Performance
Tune server settings, enable CDN, configure edge servers for global delivery
Learn MoreScale to Production
Load balancing, auto-scaling, multi-region deployment for enterprise traffic
Scaling TipsOr Go Managed
Skip all this complexity. Stream in 5 minutes with professional support and uptime
Start NowCongratulations! You've Built Your Streaming Server
You now have a functional RTMP streaming server. Remember: this is just the beginning. Production streaming requires monitoring, security hardening, bandwidth management, and 24/7 vigilance.
Compare Your Options:
$10-20/mo hosting
+ 4-8 hrs/mo maintenance
+ Bandwidth overages
+ Downtime stress
= $300+/mo total cost
$4-16/mo all-inclusive
+ 0 hrs maintenance
+ Unlimited bandwidth
+ 99.9% uptime SLA
= $4-16/mo total cost