Streaming HLS with Nginx’s RTMP Module

In this post I’m going to show you how to use Nginx’s RTMP module to stream a live video (over RTMP) from your desktop and then play it back with HLS. I’ll also cover how to encrypt the video.

RTMP was initially a proprietary protocol by Adobe for streaming video and audio between a Flash player and a server but is still widely used today for broadcasting video despite the demise of Flash.

Installation

I built the RTMP module on Ubuntu 18.04 but the installation instructions should work for any Debian-based Linux distribution.

The first thing to do is install Nginx if you haven’t already. You can install it from your distribution’s default package repositories but the provided version is usually outdated. A better option is to install it from the official Nginx repository. The current stable version is 1.18.

To install Nginx, run the following command: $ sudo apt install nginx

To build the RTMP module, first install the required dependencies then check out the source code of the module. We also need the source code of the version of Nginx that is installed. To build the module, run the following commands:

$ sudo apt install build-essential dpkg-dev libpcre3 libpcre3-dev libssl-dev zlib1g zlib1g-dev
$ git clone https://github.com/arut/nginx-rtmp-module.git
$ apt-get source nginx
$ cd nginx-1.18.0/
$ ./configure --with-compat --add-dynamic-module=../nginx-rtmp-module
$ make modules
$ sudo cp objs/ngx_rtmp_module.so /etc/nginx/modules/

This will build the RTMP module as a dynamic module. To load the module at runtime, add the following line to the Nginx configuration file (/etc/nginx/nginx.conf):

Now that Nginx has been installed and the RTMP module has been built, we need to configure it.

Configuring RTMP

The first thing we need to do is define an RTMP section in the Nginx configuration file:

The server will listen for connections on port 1935. Within the server block, we define an application called live. (You can call it whatever you like, I just happened to called it live.) We’ll refer back to this later on when we start streaming. To enable HLS, set hls to on. The next two parameters determine the location where the playlist and the segments will be written and the segment duration. In this instance, the playlist and segments are written to the /srv/www directory and the segment duration is set to 6 seconds.

To enable encryption (optional) set hls_keys to on. The next two values specify the directory where the keys will be written, and the base URL of the keys. Finally, we specify the key rotation period. This determines how many segments are encrypted with a key before a new key is generated. For example, if hls_fragments_per_key is set to 10 and the segment duration is 6 seconds, the encryption key will be rotated every minute.

The next step is to configure Nginx to serve the HLS playlist and segments. We do that by defining an http block in the configuration file:

The root location is set to /srv/www, which you’ll recall is the same location where the playlist and segments are written to. The expires parameter (line 48) specifies how long the playlist and the segments can be cached for, which is determined by looking up the value from a map based on the content type (line 38). In this case, the expiry time of the playlist (application/vnd.apple.mpegurl) is set to some time in the past (epoch) so it won’t be cached. Segments can be cached for 24 hours.

Note: Everything is served over HTTP. If you are encrypting the video then you should serve the keys over HTTPS. This is left as an exercise for the reader.

To start Nginx, run the following: $ sudo nginx

The next step is to prepare the live stream.

Preparing the Live Stream

If you want to stream the output of a webcam, I suggest downloading and installing OBS Studio. Alternatively, you can use ffmpeg to “live” stream a video.

However you decide to set-up your live stream, the format of the RTMP URL is the same. It must be in the following format: rtmp://<host>/<application name>/<stream key>

The host is either the IP address or the name of the server. As we are running it locally, it will be localhost.The application name must match the name in the Nginx configuration file, which in this example is live. The stream key can be anything – we’ll use test – and is used by the RTMP module to name the playlist and the segments. For example, if the stream key is test the playlist will be called test.m3u8 and the segments will be test-0.ts, test-1.ts, test-2.ts, and so on.

Setting the RTMP URL in OBS

Here’s an example of how to use ffmpeg to stream a video over RTMP:
$ ffmpeg -re -i big_buck_bunny_720p_h264.mov -c copy -f flv rtmp://localhost/live/test

Start the live stream. After a few seconds you should see some files in /srv/www.
Next, copy the following HTML and save it as index.html in the /srv/www directory:

(If you are using a different stream key, you’ll need to change the name of the playlist in the HTML.)

To play the live video, open up a browser and navigate to http://localhost/.

If you have any questions, feel free to leave a comment.

9 thoughts on “Streaming HLS with Nginx’s RTMP Module

  1. walder

    finally! someone that shows it’s possible for nginx-rtmp-module to be configured as a dynamic module and not just copy-pasting the same old crap being passed around that has everyone compiling and installing nginx by source?@ imagine!

    so thank you, really!

    Reply
  2. Cyril

    Hello,
    It’s a great tutorial, everything worked like a charm
    Is there a way to make the player autostart, immediately after loading or after a short predefined delay.
    Thank you

    Reply
  3. Gibson

    Hello,
    This is a great tutorial I have been searching for, thank you very much.
    Please my question is, how do I separate the Html file from the root directory? I’m asking this question because am using django as my backend so I want to connect the backend to the streaming server. Thank you.

    Reply
    1. Simon Post author

      Create the HTML page in your Django application and then change the URL to the location of the playlist on your streaming server, e.g. <source src="https://<your streaming server>/test.m3u8" type="application/vnd.apple.mpegurl"/>.

      Reply
  4. Kathirvel

    Hello,

    Very Good Article. Its really useful.

    I have facing the below issues. Kindly suggest your thoughts.

    How we can give the external rtmp url below along with key, instead of 1935. And also how we can pass this external rtmp url dyanmically?.

    rtmp {
    access_log /var/log/nginx/rtmp.log;

    server {
    listen 1935; #rtmp://restream.io

    Reply
  5. Dan

    Is there a way to do it so that the stream key isn’t revealed in final URL? Some kind of rewrite or anything? I know you can validate the stream key with an `on_publish` hook, but then by default the stream key is revealed in the filename of the playlist.. so anyone can stream to the URL by default

    Reply

Leave a Reply