Building a Live Streaming Dedicated Server Setup gives you full control, performance, and reliability for professional-grade streaming. This guide will show you how to create a complete pipeline using open-source tools and best practices.
You will learn how to handle RTMP and SRT ingest, perform CPU and GPU-accelerated transcoding with FFmpeg, and generate HLS and CMAF streams ready for web and mobile delivery. Also, to ensure the live streaming platform is secure, we will cover TLS encryption, token-based security, and monitoring.
This setup guide will help you deploy a powerful and flexible live streaming infrastructure on PerLod's dedicated Linux servers.
Prerequisites for Live Streaming Dedicated Server Setup
Before you start setting up your dedicated server for live streaming, you need to prepare your server.
The recommended hardware specifications:
- CPU Only: You need about 6–10 vCPUs to handle one full HD (1080p) stream that’s transcoded into three quality levels, including 1080p, 720p, and 480p.
- NVIDIA GPU (NVENC): A mid-range NVIDIA GPU can handle many streams efficiently using hardware encoding.
- RAM: Around 8–16 GB of memory is enough for a few simultaneous transcoding ladders.
- Disk: Use a fast NVMe SSD. Keep a separate fast drive or partition for storing HLS segment files. For example,
/var/www/hls.
- Network: Choose a 1–10 Gbps network card, depending on how many viewers or streams you plan to support.
Note: If you’re using a GPU dedicated server, ensure your hosting provider supports NVIDIA NVENC or AMD AMF acceleration for FFmpeg.
Then, you must prepare your OS. Here, our OS is Ubuntu 24.04. Run the system update, set the correct timezone, and install the required packages with the command below:
sudo apt update && sudo apt upgrade -ysudo timedatectl set-timezone Asia/Dubaisudo apt install build-essential git curl unzip htop iotop iftop net-tools jq -y
You can also create an app user for your streaming with the commands below:
sudo adduser stream --disabled-password --gecos ""sudo usermod -aG sudo stream
Next, install the UFW firewall on your Ubuntu server:
Allow the required ports, including 80, 443, 1935 for RTMP, and 9000 for SRT:
sudo ufw allow 22/tcpsudo ufw allow 80,443/tcpsudo ufw allow 1935/tcpsudo ufw allow 9000/udp
Then, enable your UFW firewall with:
At this point, you need to tune a few Linux kernel parameters to handle many connections and reduce latency. You can use the commands below to apply optimized network and system settings:
sudo tee /etc/sysctl.d/99-streaming.conf >/dev/null <<'EOF'net.core.somaxconn = 4096net.core.rmem_max = 268435456net.core.wmem_max = 268435456net.ipv4.tcp_fastopen = 3net.ipv4.tcp_congestion_control = bbrfs.inotify.max_user_watches = 524288fs.inotify.max_user_instances = 1024EOF
To apply the changes, run the command below:
Also, you need a domain name that is pointed to your server's IP address.
Once you are done with these requirements, proceed to the next steps to complete the live streaming dedicated server setup.
Install Nginx with RTMP Module and TLS
By default, Ubuntu 24.04 ships with the Nginx RTMP module. To install it, you can easily use the command below:
sudo apt install nginx libnginx-mod-rtmp -y
You can verify your installation with the command below:
nginx -V 2>&1 | grep -q rtmp && echo "RTMP module available"
Then, you must create a directory for your HLS output and set the correct permissions. To do this, run the commands below:
sudo mkdir -p /var/www/hls/livesudo chown -R www-data:www-data /var/www/hls
Configure Nginx for RTMP and HLS
At this point, you need to set up Nginx to accept RTMP streams and automatically generate HLS (CMAF/fMP4) segments.
You can create or update your Nginx configuration file with the following minimal config:
1sudo tee /etc/nginx/nginx.conf >/dev/null <<'EOF'2user www-data;3worker_processes auto;4pid /run/nginx.pid;5 6events {7 worker_connections 4096;8 multi_accept on;9}10 11rtmp {12 server {13 listen 1935;14 chunk_size 4096;15 16 application live {17 live on;18 19 allow publish all;20 allow play all;21 22 hls on;23 hls_path /var/www/hls/live;24 hls_fragment 2s;25 hls_playlist_length 6s;26 27 hls_variant _cmaf;28 hls_fragment_naming system;29 hls_segments 10;30 hls_cleanup on;31 hls_nested on;32 hls_fragment_type fmp4;33 }34 }35}36 37http {38 sendfile on;39 tcp_nopush on;40 tcp_nodelay on;41 server_tokens off;42 43 types_hash_max_size 4096;44 include /etc/nginx/mime.types;45 default_type application/octet-stream;46 47 server {48 listen 80;49 server_name _;50 root /var/www;51 52 location /hls/ {53 add_header Cache-Control "no-cache";54 add_header Access-Control-Allow-Origin "*";55 types {56 application/vnd.apple.mpegurl m3u8;57 video/mp2t ts;58 video/iso.segment m4s;59 application/octet-stream m4s;60 }61 autoindex off;62 }63 64 location /healthz { return 200 "ok\n"; }65 }66}67EOF
Once you are done, test your configuration to make sure it is set correctly:
And reload Nginx to apply the changes:
sudo systemctl restart nginx
Enable TLS with Let’s Encrypt
To secure your setup, you can install Certbot and enable HTTPS for your domain. To do this, you can use the following commands:
sudo apt install certbot python3-certbot-nginx -ysudo certbot --nginx -d stream.example.com --redirect --agree-tos -m you@example.com --no-eff-email
This creates an HTTPS server block and ensures your HLS paths are served under:
https://stream.example.com/hls/...
Install FFmpeg CPU and Optional NVIDIA NVENC
FFmpeg handles transcoding, bitrate ladder generation, and format conversion. A CPU-only setup is perfectly fine for a few 1080p streams.
For a CPU-only installation, you can install FFmpeg using the command below:
sudo apt install ffmpeg -y
Verify the installation with:
ffmpeg -version | head -n1
For optional GPU-accelerated (NVENC) encoding, you must install drivers with NVENC-capable FFmpeg. Install the drivers and reboot the system with the commands below:
sudo ubuntu-drivers autoinstallsudo reboot
After reboot, verify the GPU with the command below:
Also, you can check that FFmpeg recognizes NVENC. To do this, run:
ffmpeg -hwaccels | grep cuda || trueffmpeg -encoders | grep nvenc || true
If you see h264_nvenc or hevc_nvenc, hardware encoding is ready to use.
SRT Ingest to Internal RTMP Bridge
Modern live streaming dedicated server setups often use SRT (Secure Reliable Transport) for contribution, especially when broadcasting over the public internet. It provides better error recovery and lower latency than RTMP in unstable network conditions.
As you may know, Nginx with the RTMP module cannot accept SRT natively. To integrate SRT streams into the pipeline, we can use FFmpeg as a bridge. It receives the SRT input and forwards it internally to Nginx as RTMP.
You can run a bridge service via systemd. To do this, run the command below:
1sudo tee /etc/systemd/system/srt-to-rtmp@.service >/dev/null <<'EOF'2[Unit]3Description=SRT listener on port %i -> RTMP normalize4After=network.target nginx.service5 6[Service]7Type=simple8ExecStart=/usr/bin/ffmpeg -loglevel warning \9 -re -i "srt://0.0.0.0:%i?mode=listener&latency=80&linger=1" \10 -c copy -f flv "rtmp://127.0.0.1/live/%i"11Restart=always12RestartSec=213 14[Install]15WantedBy=multi-user.target16EOF
Enable the service and check the status with:
sudo systemctl daemon-reloadsudo systemctl enable --now srt-to-rtmp@9000.servicesudo systemctl status srt-to-rtmp@9000.service --no-pager
This bridge allows your server to accept SRT ingest while keeping the rest of your RTMP-based workflow safe and healthy.
Automatic Transcoding to an ABR Ladder
To deliver smooth playback across different devices and network conditions, each live stream should be transcoded into multiple quality levels, which is known as an Adaptive Bitrate (ABR) ladder.
In this step, we want to create a fully automated process that converts one incoming stream into three H.264 CMAF/HLS renditions, including 1080p, 720p, and 480p.
While Nginx-RTMP can trigger transcoding automatically using the exec directive, managing these jobs through systemd is more reliable and easier to monitor. Each live stream or stream key runs its own supervised FFmpeg process, ensuring stability and automatic restarts if a transcode stops.
Now create a script at /usr/local/bin/transcode-cmaf.sh that converts an RTMP live stream into multiple HLS video qualities:
sudo tee /usr/local/bin/transcode-cmaf.sh >/dev/null <<'EOF'set -euo pipefail KEY="${1:?stream key required}"INPUT="rtmp://127.0.0.1/live/${KEY}"OUTDIR="/var/www/hls/live/${KEY}"PLAYLIST="${OUTDIR}/index.m3u8" mkdir -p "$OUTDIR" ffmpeg -hide_banner -loglevel warning -threads 2 \ -i "$INPUT" \ -filter_complex "[0:v]split=3[v1080][v720][v480]; \ [v1080]scale=w=1920:h=1080:flags=bicubic[v1080o]; \ [v720]scale=w=1280:h=720:flags=bicubic[v720o]; \ [v480]scale=w=854:h=480:flags=bicubic[v480o]" \ -map "[v1080o]" -map a? -c:v libx264 -preset veryfast -tune zerolatency -profile:v high -level:v 4.1 -b:v 5500k -maxrate 6000k -bufsize 8000k -g 48 -keyint_min 48 -sc_threshold 0 -c:a aac -b:a 160k \ -map "[v720o]" -map a? -c:v libx264 -preset veryfast -tune zerolatency -profile:v high -level:v 4.0 -b:v 3000k -maxrate 3300k -bufsize 4800k -g 48 -keyint_min 48 -sc_threshold 0 -c:a aac -b:a 128k \ -map "[v480o]" -map a? -c:v libx264 -preset veryfast -tune zerolatency -profile:v main -level:v 3.1 -b:v 1300k -maxrate 1500k -bufsize 2200k -g 48 -keyint_min 48 -sc_threshold 0 -c:a aac -b:a 96k \ -f hls \ -hls_time 2 -hls_list_size 6 -hls_flags independent_segments+delete_segments+append_list \ -hls_segment_type fmp4 -hls_playlist_type event \ -master_pl_name master.m3u8 \ -var_stream_map "v:0,a:0,name:1080 v:1,a:1,name:720 v:2,a:2,name:480" \ -hls_segment_filename "${OUTDIR}/%v/seg_%06d.m4s" \ "${OUTDIR}/%v/index.m3u8"EOF
sudo chmod +x /usr/local/bin/transcode-cmaf.sh
Then, create a systemd service that automatically runs the transcode script for any stream key:
1sudo tee /etc/systemd/system/transcode@.service >/dev/null <<'EOF'2[Unit]3Description=Transcode RTMP stream %i to CMAF HLS ABR4After=network.target nginx.service5 6[Service]7Type=simple8ExecStart=/usr/local/bin/transcode-cmaf.sh %i9Restart=always10RestartSec=211 12[Install]13WantedBy=multi-user.target14EOF
To apply the changes, run the command below:
sudo systemctl daemon-reload
Next, you can start the transcode service immediately for a stream key. For example, for the myevent stream key:
sudo systemctl enable --now transcode@myevent.service
Also, you can check live logs from the transcoding process with:
journalctl -u transcode@myevent.service -f
To set up the streaming workflow, follow these steps:
Push from OBS for RTMP with the myevent stream key:
rtmp://stream.example.com/live
sudo systemctl enable --now transcode@myevent.service
For SRT push from OBS on port 9000, then run:
sudo systemctl enable --now transcode@9000.service
The transcoder will automatically convert your stream into multiple HLS qualities for playback.
For GPU-accelerated NVIDIA NVENC, you need to replace the CPU encoding with:
-c:v h264_nvenc -preset p4 -tune ll -rc vbr -cq 23
Or you can target -b:v/-maxrate similarly. For example, for 1080p:
-c:v h264_nvenc -preset p4 -tune ll -rc vbr -b:v 5500k -maxrate 6000k -bufsize 8000k -g 48 -bf 2 -temporal-aq 1 -spatial-aq 1
Apply these settings for 720p and 480p.
Create Live Stream Player Page
At this point, you can create a player page that automatically loads and plays the current broadcast.
To create the player HTML file, run the command below:
1sudo tee /var/www/html/player.html >/dev/null <<'EOF'2<!doctype html>3<html>4<head>5 <meta charset="utf-8" />6 <title>Live Player</title>7 <meta name="viewport" content="width=device-width, initial-scale=1" />8 <style>body{margin:0;background:#111;color:#eee;font-family:sans-serif} .wrap{max-width:900px;margin:40px auto;padding:20px} video{width:100%;max-height:70vh;background:#000}</style>9</head>10<body>11<div class="wrap">12 <h1>Live Player</h1>13 <video id="video" controls playsinline></video>14 <p id="status"></p>15</div>16<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>17<script>18const master = location.origin + "/hls/live/myevent/master.m3u8";19const video = document.getElementById('video');20if (Hls.isSupported()) {21 const hls = new Hls({ lowLatencyMode: true, backBufferLength: 30 });22 hls.loadSource(master);23 hls.attachMedia(video);24 hls.on(Hls.Events.MANIFEST_PARSED, () => video.play());25} else if (video.canPlayType('application/vnd.apple.mpegurl')) {26 video.src = master; video.addEventListener('loadedmetadata', () => video.play());27} else {28 document.getElementById('status').textContent = "HLS not supported in this browser.";29}30</script>31</body>32</html>33EOF
Then you can access it at:
https://stream.example.com/player.html
Secure Your Live Stream: Publish and Playback Protection
At this point, you can secure both RTMP publishing with private stream keys and HLS playback with signed URLs using Nginx's secure_link module.
For stream keys in RTMP, OBS uses rtmp://HOST/live/STREAM_KEY. Keep these keys private and rotate them per event.
You can also add a secret and URL pattern in your Nginx server block with:
1location /hls/ {2 secure_link $arg_md5,$arg_expires;3 secure_link_md5 "$secure_link_expires$uri SECRETSTRING";4 5 if ($secure_link = "") { return 403; }6 if ($secure_link = "0") { return 410; }7 8 add_header Cache-Control "no-cache";9 add_header Access-Control-Allow-Origin "*";10 11}
Then, generate signed URLs in your app:
expires = UNIX_TIMESTAMP_IN_FUTUREtoken = base64url(md5(expires + path + SECRETSTRING))GET /hls/live/myevent/master.m3u8?md5=token&expires=expires
The player would request signed URLs from your backend instead of accessing HLS files directly.
Monitor Live Stream Performance
It is recommended to keep your live stream running smoothly with comprehensive monitoring. You must track viewer counts, stream health, and system resources to quickly identify and resolve issues before they impact your audience.
You can monitor active streams, viewers, and bandwidth usage with Nginx's built-in RTMP statistics page. Add the Nginx RTMP stats to your config file in http{}:
1server {2 listen 8080;3 location /stat {4 rtmp_stat all;5 rtmp_stat_stylesheet stat.xsl;6 }7 location /stat.xsl {8 root /usr/share/doc/libnginx-mod-rtmp/examples/;9 }10}
Check for syntax errors and reload Nginx to apply the changes:
sudo nginx -t && sudo systemctl reload nginx
Now start monitoring stats with the following curl command:
curl http://127.0.0.1:8080/stat
You can also check system health and process monitoring. You can track transcoder performance, resource usage, and service logs with the commands below:
sudo journalctl -u srt-to-rtmp@9000 -fsudo journalctl -u transcode@myevent -fhtopiotop -oPasudo nginx -T | less
Archive Live Streams: Recording and Video-on-Demand
You can also automatically record your live streams while they're broadcasting to create instant video-on-demand assets for later viewing and distribution. To do this, you can append this to your FFmpeg command:
-map 0:v -map a? -c copy -f mp4 -movflags +frag_keyframe+empty_moov "/var/www/hls/live/${KEY}/archive-$(date +%Y%m%dT%H%M%S).mp4"
This creates files like archive.mp4 for later viewing or editing.
That's it, you are done with the live streaming dedicated server setup.
Conclusion
Live Streaming Dedicated Server Setup gives you complete control over quality, scalability, and cost. By using open-source tools like Nginx-RTMP, FFmpeg, and Certbot, you can create a professional-grade streaming workflow. We hope you enjoy this guide.
Subscribe to our X and Facebook channels to get the latest articles for live streaming servers.
For further reading:
Low Latency Game Servers for Faster Performance
Advantages of GPU-Dedicated Servers for Video Editing
Enhancing 3D Rendering on VPS