What you are building
Think of it as a relay with a translator. Your encoder, OBS for most people, speaks RTMP. Browsers do not, so the RTMP module repackages your stream as HLS: a small playlist file plus a row of short video chunks, written to a folder on the server. Ordinary nginx then serves that folder like any website, and a web player pulls the chunks one after another.
Two details from the module's README and source code save you an evening of head-scratching. First, HLS output needs H.264 video and AAC audio, so keep OBS on those. Second, each chunk ends on a keyframe, so set OBS's keyframe interval to 2 seconds and the chunks come out an even length.
Will one server keep up with your audience?
Usually yes, and the network port decides it, not the processor. Multiply the people watching at once by the bitrate each one receives and keep the total under eighty percent of the port, which is the headroom our streaming servers page plans for.
| What viewers watch | Bitrate each | On a 1 Gbps port |
|---|---|---|
| 720p video | 4 Mbps | about 200 at once |
| 1080p video | 6 Mbps | about 133 at once |
| Same, on 10 Gbps | as above | ten times each |
The processor only starts to matter when you ask ffmpeg to make extra qualities, because each one is a full re-encode. Start with one, watch the load with top, and add more only if there is room. If you plan many channels with several qualities each, a GPU machine built for video transcoding is the better fit.
Up and running in an evening
- On a fresh Ubuntu or Debian server, install everything in one line:
sudo apt update && sudo apt install -y libnginx-mod-rtmp ffmpeg nginx. On Ubuntu the module comes from the universe repository. - Make a folder for the video chunks with
sudo mkdir -p /var/www/hls, then hand it to the web server's user:sudo chown www-data: /var/www/hls. - Open
/etc/nginx/nginx.confand paste the first block at the very end, outside thehttp { }section. RTMP settings are not allowed inside it. - Save the second block as
/etc/nginx/conf.d/live.conf, put your own long random key where it says so, then make the file readable by root only withsudo chmod 600. - Check and apply:
sudo nginx -t, thensudo systemctl reload nginx. - In OBS, choose a custom service. Server:
rtmp://your-server/live. Stream key:show?key=followed by your key. - Press Start Streaming and open
http://your-server/hls/show.m3u8in VLC or a web player.
rtmp_auto_push on;
rtmp {
server {
listen 1935;
notify_method get;
access_log off;
application live {
live on;
on_publish http://127.0.0.1:8081/auth;
allow play 127.0.0.1;
deny play all;
drop_idle_publisher 10s;
hls on;
hls_path /var/www/hls;
hls_fragment 4s;
hls_playlist_length 20s;
}
}
}
server {
listen 127.0.0.1:8081;
access_log off;
location /auth {
if ($arg_key = "replace-with-a-long-random-key") {
return 204;
}
return 403;
}
}
server {
listen 80;
server_name your-server;
location /hls {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root /var/www;
add_header Cache-Control no-cache;
}
}
Replace your-server with your hostname. Before you embed the player on an https website, give that hostname a certificate, or the browser will refuse to load the stream.
Only your encoder gets to go live
Out of the box, anyone who finds port 1935 could broadcast through your server. The setup above closes that door with on_publish: before accepting a stream, nginx asks the small internal address on port 8081 whether to let it in. A 2xx answer lets the stream through and anything else drops it, as the module's directive reference describes. Whatever follows the ? in your stream key is passed along with that question, so the check sees your key while viewers only ever see the name show.
- Why logging is off: the key travels in the stream name and in the check request, so both the RTMP log and the auth server's log would store it in plain text. The setup turns off both.
- If your encoder has a fixed address, you can skip the key and write
allow publishwith that address followed bydeny publish all. nginx reads these rules top to bottom. - Nobody pulls your raw feed:
deny play allstops outsiders reading the full-quality RTMP stream straight off your port. - A crashed encoder lets go: with
drop_idle_publisher 10s, a connection that goes silent is cut after ten seconds, so you can reconnect straight away. - Firewall: let 1935 in from where you broadcast, and 80 and 443 in from everyone.
Offering a lighter version for phones
Viewers on weak mobile data will buffer on a 6 Mbps stream. The module can start ffmpeg for you each time a stream begins (exec_push) and stops it when you stop. ffmpeg reads your stream back, makes a 480p copy, and both versions go into a second application that publishes a single master playlist. The player then picks the version each viewer can handle.
application live {
live on;
on_publish http://127.0.0.1:8081/auth;
allow play 127.0.0.1;
deny play all;
drop_idle_publisher 10s;
exec_push /usr/bin/ffmpeg -i rtmp://127.0.0.1/live/$name
-c copy -f flv rtmp://127.0.0.1/show/$name_hi
-c:v libx264 -preset veryfast -b:v 1200k -s 854x480 -g 60 -c:a aac -b:a 96k -f flv rtmp://127.0.0.1/show/$name_lo;
}
application show {
live on;
allow publish 127.0.0.1;
deny publish all;
deny play all;
hls on;
hls_path /var/www/hls;
hls_nested on;
hls_variant _hi BANDWIDTH=6500000;
hls_variant _lo BANDWIDTH=1400000;
}
These two replace the live application in your first block; ffmpeg is written with its full path because nginx starts it with a cleared environment. Set _hi's BANDWIDTH to roughly what OBS sends, and keep -g 60 only if your stream runs at 30 frames per second (it means a keyframe every 2 seconds). Your viewers' address stays /hls/show.m3u8.
The server that fits
A home connection or a small shared virtual server struggles the moment a stream gets popular, because every viewer is a separate copy leaving the same uplink. Our dedicated streaming servers are built for exactly this job, and the service page names nginx-rtmp and FFmpeg among the software you can run with the root access you get.
- A whole machine for you alone, with nobody else's work on the processor or disks.
- An unmetered port that nobody else is on at the switch: ten of our eighteen server lines come with 1 Gbps and the rest with 500 Mbps, raised to as much as 100 Gbps when you need it. Nothing counts the traffic.
- Ready quickly: if a machine already sits in the rack, expect it roughly 30 minutes after your payment clears approval. Custom builds, and anything with a port faster than 1 Gbps, need 4 to 24 hours.
- Help at any hour: phone, live chat and tickets on every plan, plus a remote console on the blade, rack and larger cartridge lines.
- No contract: month to month, in any of five cities: Bucharest, Amsterdam, New York, Miami or San Francisco.
When building your own is the wrong call
If you simply want a stream on your site with nothing to maintain, our live video plans accept your RTMP feed and handle everything after it. If your audience is spread across continents, let the video CDN sit between your server and them. If your encoder only speaks SRT, the RTMP module will not take it; see our guide to an SRT streaming server. And the module's README lists running programs (so ffmpeg qualities) as unsupported on Windows, so build this on Linux.
Questions people ask
- Do I need to compile nginx to get RTMP?
- Not on Ubuntu or Debian. The module is packaged as libnginx-mod-rtmp and loads into the distribution's own nginx, so apt installs both. Compiling from source is only needed on systems without the package.
- What do I type into OBS?
- Pick a custom service, set the server to rtmp:// followed by your hostname and the application name (live in this guide), and use the stream name plus your key as the stream key. Keep the video codec on H.264 and audio on AAC, and set a 2 second keyframe interval.
- How far behind live will my viewers be?
- Several seconds, because a player waits for a few chunks before it starts. Shorter
hls_fragmentvalues trim the delay a little at the cost of more files. If you need a near real-time conversation, plain HLS is not the tool. - Can I record the stream as well?
- Yes. The module has its own record directives that save what you send as FLV files on the server's disk. Plan the disk for how many hours you keep, and convert the files to MP4 with ffmpeg afterwards if you want to upload them elsewhere.
- Is an unmetered port really free of traffic charges?
- On our dedicated servers, yes: the port is sold as a speed. There is no traffic allowance to run past and your invoice has no overage charge. What limits you is the speed itself, which is why the viewer arithmetic above matters.