Part5 - HLS Streaming with Nginx Rtmp Module

RTMP is not supported by most of the devices and most of the browsers anymore. At the time of this writing I found out the best streaming choice would be HLS to support most of the devices and browser. HLS not only added video support for iOS devices, but its stateless HTTP delivery method enables us to leverage caching and have the full benefits of load balancing, with a huge impact on performance and scalability. 

Incoming stream must be in H264/AAC for HLS streaming, we will set this on OBS and FFMpeg.

Before streaming HLS make sure FFMpeg is installed. Just run the command below to check if it is installed

ffmpeg -v

If it is not installed you can check my article named Installing FFMPEG with Extra Encoding and Decoding Libraries.


This is my IP camera settings:

I will be recording while I do the streaming. Recording must be high quality (1280x720) and stream will be 640x480.


 While I was testing HLS stream, I had problems with Windows version of OBS. The hls index file and ts fragments were not updated and hls files were deleted automatically and hls stream was stuck. I tested Mac and Linux version of OBS with the same Nginx config and hls stream worked just fine. The OBS version I am using is OBS for MAC 0.16.2.


The OBS Settings:

On General section, check "Automatically record when streaming" (if you need to record the stream)

On Stream section, enter stream server info in the following format 


Streamkey: this can be anything that you wanna specify, for test purpose just type: test










Because I am using IP Camera as source, I need to select channels as "Mono." When channels field is selected as stereo, I experienced problems with audio. So, selecting it as "Mono" solved the problem with audio. 




 I also changed file name formatting as below.



 Nginx Configuration for HLS:

First create the folder for hls files under /tmp. Then change nginx.conf file according to your info. I removed the comments from nginx.conf in this article  for readability's sake. You need to modify YourNginxIPAddress field with your own server. 

mkdir /tmp/hls
sudo nano /usr/local/nginx/conf/nginx.conf 
#user  nobody;

user nginxadminusername;

worker_processes  1;

events {

    worker_connections  1024;


http {

    include       mime.types;

    default_type  application/octet-stream;

sendfile        on;

  server {

        listen       80;

        server_name  YourNginxIPAddress;

location /hls {

        # Serve HLS fragments

        types {

            application/ m3u8;

            video/mp2t ts;                


        root /tmp/;

        add_header Cache-Control no-cache;

        add_header 'Access-Control-Allow-Origin' '*';


location / {

            root   html;

            index  index.html index.htm;


error_page   500 502 503 504  /50x.html;

        location = /50x.html {

            root   html;





rtmp {

 server {

    listen 1935;

    application live {

        live on;

#What's happening here is we're telling ffmpeg that we want the keyframe interval to be every 40 frames (which is

#two seconds based on OBS's output frame rate of 20fps), and then we're telling nginx to split every 3 keyframes

#(6 seconds). This means that everything fits within the correct second boundaries


        exec ffmpeg -i rtmp://YourNginxIPAddress/$app/$name -vcodec libx264 -vprofile

baseline -x264opts keyint=40 -acodec aac -strict -2 -f flv rtmp://YourNginxIPAddress/hls/$name;


  application hls {

        live on;

        hls on;

        hls_path /tmp/hls/;

        hls_fragment 6s;

        hls_playlist_length 60s;






Restart Nginx Service

sudo service nginx restart

 Test your HLS on VLC:




It works fine.

The above ffmpeg line encodes the video and audio one more time which you may find unnecessary. You can just copy video and audio from the input to output like this:



exec ffmpeg -i rtmp://YourNginxIPAddress/$app/$name -vcodec copy -map 0:a -map 0:v -acodec copy -f flv  rtmp://YourNginxIPAddress/hls/$name;


-vcodec copy: tells ffmpeg that we don't want to change the video codec and can copy what's already in the file
-map 0:a : tells ffmpeg that we want to include all audio streams
-map 0:a : tells ffmpeg that we want to include all video streams
-acodec copy
: tells ffmpeg that we don't want to change the audio codec and can copy what's already in the file



Securing your Streaming Server:

At the beginning I disabled the firewall and now I want to enable it and open the required ports. 5900 and 5500 are required if you use VNC for remote connection.

sudo ufw allow 80
sudo ufw allow 1935
sudo ufw allow 5900
sudo ufw allow 5500
sudo ufw enable


I also want to limit the access to my streaming server. Edit nginx.conf. 

allow play all;
allow publish;
allow publish nginxserveripaddress; 
allow publish obsencoderipaddress;
deny publish all;


Restart nginx service 


sudo service nginx restart

I noticed that If I reboot the server, the ownership of /tmp/hls changes and nginx can not write to that folder and hls file can not be created.  I added the line below at the top of nginx.conf file.

user mynginxadminusername; 

Then run the command below to change the ownership of hls folder to modify the permissions.

 sudo chown mynginxadminusername /tmp/hls

 Finally change the permission like below.