Introduction
HLS stands for HTTP live streaming. It’s an HTTP based media streaming protocol developed by Apple. Unlike UDP based protocols like RTP it can’t be blocked by firewalls that only allow HTTP traffic. It can be delivered by HTTP servers such as Nginx and can distributed through CDNs.
The default install of Nginx doesn’t come complied with an HLS module; but there’s an open source Nginx module that supports HLS. We would need to compile Nginx from source and add the module during compilation.
This tutorial shows you how to install Nginx and use it as a video live streaming server.
Prerequisites
To follow along with this tutorial please ensure the following are present on the target machine:
- git, wget, gcc, gcc-c++, perl, gd, gd-devel, perl-ExtUtils-Embed, geoip, geoip-devel and tar
- A non root user with sudo capabilities
If you don’t have the build utilities you would need to install them. Run this to do so:
$ sudo yum update
$ sudo yum install epel-release
$ sudo yum install git wget gcc gcc-c++ tar gd gd-devel perl-ExtUtils-Embed geoip geoip-devel
Step 1 - Download and Compile Nginx With It’s Dependencies
We need to download the dependency libraries for Nginx; including the open sorce nginx-rtmp module used to provide Nginx with HLS capabilities. First off we download the PCRE module required by Nginx Core and Rewrite modules. Run this to do so:
$ wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.42.tar.gz
$ tar -zxf pcre-8.42.tar.gz
$ rm -rf pcre-8.42.tar.gz
$ cd pcre-8.42
$ ./configure
$ make
$ sudo make install
$ cd
Next we download the zlib module required by the Nginx Gzip module of nginx and install it. Run this to do so:
$ wget http://zlib.net/zlib-1.2.11.tar.gz
$ tar -zxf zlib-1.2.11.tar.gz
$ rm -rf zlib-1.2.11.tar.gz
$ cd zlib-1.2.11
$ ./configure
$ make
$ sudo make install
$ cd
Up next, we download the openssl module required by the Nginx SSL module. Run this to do so:
$ wget http://www.openssl.org/source/openssl-1.0.2q.tar.gz
$ tar -zxf openssl-1.0.2q.tar.gz
$ rm -rf openssl-1.0.2.tar.gz
$ cd openssl-1.0.2q
$ ./config
$ make
$ sudo make install
$ cd
We then download the open source nginx-rtmp module from its github repository. To do that run:
$ git clone git://github.com/arut/nginx-rtmp-module.git
Finally we download the Nginx source. We would be downloading the latest stable version, which as of this writing is 1.14.2, from nginx.org. Run this to do so:
$ wget https://nginx.org/download/nginx-1.14.2.tar.gz
$ tar zxf nginx-1.14.2.tar.gz
$ rm -rf nginx-1.14.2.tar.gz
$ cd nginx-1.14.2
Now that we have the necessary dependencies, we can compile Nginx. Now we need to configure the build options. This is done by running the “./configure” script in the directory with a host of options for Nginx to compile. The options include the paths to the open source module, zlib module, pcre module and openssl module all previously downloaded and installed. We also need to specify which in built Nginx modules we want compiled. We run this to get the desired build option:
$ ./configure --add-module=../nginx-rtmp-module \
--sbin-path=/usr/sbin/nginx \
--lock-path=/var/run/nginx.lock \
--conf-path=/etc/nginx/nginx.conf \
--pid-path=/run/nginx.pid \
--with-pcre=../pcre-8.42 \
--with-zlib=../zlib-1.2.11 \
--with-openssl=../openssl-1.0.2q \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--user=nginx \
--group=nginx \
--with-http_auth_request_module \
--with-http_degradation_module \
--with-http_geoip_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_image_filter_module \
--with-http_mp4_module \
--with-http_perl_module \
--with-http_realip_module \
--with-http_secure_link_module \
--with-http_slice_module \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_v2_module \
--with-stream_ssl_module \
--with-stream \
--with-threads \
--prefix=/etc/nginx
Finally compile and build Nginx.
$ make
$ sudo make install
To check if it was installed properly run:
$ nginx -V #The output should be the Nginx version, compiler version, and configure script parameters.
We need to install the Nginx man pages, to do that run this:
$ sudo cp ~/nginx-1.14.2/man/nginx.8 /usr/share/man/man8
$ sudo gzip /usr/share/man/man8/nginx.8
Now we clean up the libraries previously downloaded.
$ rm -rf nginx-1.14.2 nginx-rtmp-module openssl-1.0.2q pcre-8.42 zlib-1.2.11
Step 2 – Setup and Configure Nginx
Now that the Nginx binary is installed in our search path, we need to setup an nginx user. To setup the nginx user, run:
$ sudo useradd --system --home /var/lib/nginx --shell /sbin/nologin --comment "nginx system user" nginx
We also need to create the directory where Nginx logs are stored and make user nginx the owner. For that we run:
$ sudo mkdir /var/log/nginx && sudo chown nginx:nginx /var/log/nginx
With that done, it’s time to create the nginx systemd service unit file. It’s contents should be something like this:
[Unit]
Description=nginx - high performance web server
Documentation=https://nginx.org/en/docs/
After=network.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=process
PrivateTmp=true
[Install]
WantedBy=multi-user.target
We now paste the above contents in the nginx service file:
$ sudo vim /lib/systemd/system/nginx.service # You can replace vim with whichever editor you prefer
Now we reload systemctl daemon and start Nginx.
$ sudo systemctl daemon-reload
$ sudo systemctl start nginx
$ sudo systemctl enable nginx
Now we need to configure Nginx to stream videos. Our nginx.conf file; located in the /etc/nginx/ directory, should look like this:
user nginx;
worker_processes auto;
server_tokens off;
events {
worker_connections 1024;
}
# We need to setup an rmtp server to stream video from client devices
rtmp {
server {
listen 1935;
chunk_size 4096;
ping 30s;
notify_method get;
allow play all;
# rmtp handler our clients connect to for live streaming, it runs on port 1935. It converts the stream to HLS and stores it on our server
application app {
live on;
hls on;
hls_path /var/www/hls/live;
hls_nested on; # create a new folder for each stream
record_notify on;
record_path /var/www/videos;
record all;
record_unique on;
}
application vod {
play /var/www/videos;
}
}
}
http {
include 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"';
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
gzip on;
server {
listen 80;
server_name _;
location / {
root html;
index index.html index.htm;
}
# the http end point our web based users connect to see the live stream
location /live {
types {
application/vnd.apple.mpegurl m3u8;
}
alias /var/www/hls/live;
add_header Cache-Control no-cache;
}
}
We need to also create the directory where our video stream is stored.
$ sudo mkdir -p /var/www/hls/live
Now we can restart nginx to reload the new configuration file.
$ sudo systemctl restart nginx
Step 3- Stream and Publish Videos
Now to live stream videos from a client machine, assuming the client has the video stored locally and ffmpeg installed, we run this to publish to our server:
$ ffmpeg -i /path/to/video -c:v h264 -c:a aac -strict -2 -f flv rtmp://server_ip:1935/app/unique_stream_name #the name of the stream has to be unique
Our viewers can watch the video on vlc media player by streaming the url: http://server_ip/live/unique_stream_key/index.m3u8
. It is also possible to publish video from webcam from a Linux client machine by running:
$ ffmpeg -f video4linux2 -i /dev/video0 -c:v libx264 -an -f flv rtmp://server_ip:1935/app/unique_stream_name
From a mac book, it’s this way
$ ffmpeg -f avfoundation -framerate 30 -i "0" -c:v libx264 -an -f flv rtmp://server_ip:1935/app/unique_stream_name
Conclusion
And thats how to setup HLS with Nginx. To go further we could write an application in our favorite programming language to handle user authentication and maybe store videos on a media server. The key thing is that our users can live stream videos with regular HTTP.