nginx

A 1-post collection

RTMP Streaming Server

We all know Twitch and Youtube streaming, and some may know Hitbox. But what if you wanted to implement your own streaming server?

So what are the actual benefits to just using the mentioned services?

  • Private streams, no one can see them, no one can find them
  • Record everything without additional cost
  • Define which qualities the stream will be transcoded to
  • Embed streams on your own websites
  • May run "offline" just in your home for surveilance uses.

But there are disadvantages too:

  • Needs to run on a rented or owned box (so does probably cost something)
  • Machine with the server needs to be powerful
  • Probably does not scale to many viewers

So my intended purposes were watching my 3D printer from work (or even mobile when not at home) to be able to shut it down if it produces garbage and for some friends that stream to Twitch. So what? They stream to Twitch and need an own streaming server, why? That's easy: They play games together and wanted to show both screens side by side. So one of them bounces their stream to my server and the other one imports that stream in XSplit to send it to Twitch. You could probably do that with two Twitch streams but the latency is bad then. Over the setup I provide the latency is about 2-4 seconds, via Twitch it is more like 30 seconds.

What i tried

The first thing I tried was to search the APT repositories on Ubuntu for streaming servers, I found two:

  • crtmpserver
  • red5-server

While trying to set up crtmpserver I gave up after trying to get documentation for it (all websites and the Trac were down)

Red5 is Java so it fell out of consideration because I don't know my way around Java and Maven.

So I was standing there searching for alternatives. I found one, one that is really straightforward but it seemed the Git repo was abandoned some time ago. Then I looked if there were any forks that are in development. Oh boy there were many, about 1600, Github just gave up displaying the network graph and I had to search the most active and stable fork myself.

Github Screenshot

Then I found one: https://github.com/sergey-dryabzhinsky/nginx-rtmp-module

Thanks sergey :)

How to get it running

The project is an extension module to nginx. I know my way around nginx configuration so you can feel my joy!

The bad thing is that you have to recompile the complete nginx server, but as I only wanted to use it for streaming and run the Ubuntu default nginx for my web needs, that was no problem. Both nginx instances can coexist on the same machine. (There are 3 now, one for web, one from gitlab and one for streaming)

So let's build the thing:

# create a user
addgroup --system rtmp  
adduser --system --home /srv/stream --group rtmp rtmp

# prepare build dir
mkdir -p src  
cd src

# use stable nginx, the module does not compile with mainline
wget https://nginx.org/download/nginx-1.10.1.tar.gz  
git clone https://github.com/sergey-dryabzhinsky/nginx-rtmp-module.git

# build new nginx
tar xvzf nginx-1.10.1.tar.gz  
cd nginx-1.10.1  
./configure \
    --prefix=/opt/nginx-stream \
    --conf-path=/etc/nginx-stream/nginx.conf \
    --pid-path=/run/nginx-stream/nginx.pid \
    --lock-path=/run/nginx-stream/nginx.lock \
    --http-log-path=/var/log/nginx-stream/nginx.log \
    --error-log-path=/var/log/nginx-stream/error.log \
    --user=rtmp \
    --group=rtmp \
    --with-threads \
    --with-ipv6 \
    --with-http_ssl_module \
    --with-http_flv_module \
    --with-http_mp4_module \
    --with-http_gzip_static_module \
    --with-stream \
    --with-stream_ssl_module \
    --add-module=$HOME/src/nginx-rtmp-module
make  
sudo make install  

Configuration

We replace the complete configuration that is installed in /etc/nginx-stream/nginx.conf:

Attention: This allows everyone to publish streams to your server, call control endpoints and see the status page, if you want authentication you'll have to configure it, see nginx documentation for details. I omitted the authentication stuff because it is another source of error when testing the setup.

We use the path /srv/stream/ for the user's home directory and for storage of needed html and media files (when recording).

To display the status page in a browser we have to give it a XSLT script to convert the XML the streaming server uses to something a browser can handle. We put the file into /srv/stream/html/style.xsl:

I know it is not the most elegant XSLT (neither is the HTML/CSS it generates) but it works for me.

Test-Run it

Just call sudo /opt/nginx-stream/sbin/nginx to start the server. You may kill the server by calling sudo pkill -F /run/nginx-stream/nginx.pid.

Of course you may write configuration or a start-script for your prefered init system now, but for testing purposes the two commands from above should do it.

Publish a stream

To test the system I used OBS Studio as it is available for all major OSes.

OBS screenshot of streaming settings

Now click on Start streaming:

OBS start streaming

When everything went right no error message should pop up and the status bar should change to display the current bandwidth usage.

To check if everything is right on the server, go to http://streaming.example.com:8080/stat/, it should look like this:

Stat page screenshot

As you can see you'll have some links you may click on. The first one (Drop) cancels the stream (but OBS won't know and keep sending UDP packets to your server which is unfortunate), the second (Start Recording) switches on recording mode. When you click on the record link the answer will be the path that will be recorded to.

Subscribe to a stream

We have two applications defined:

  • Live stream
  • Video on demand

How to watch a live stream

Via RTMP, use the following URL (in VLC for example): http://streaming.example.com:1935/live/<stream key>

Via HLS (HTML5 browser variant), fetch the playlist here: http://streaming.example.com:8080/live/<stream key>.m3u8

How to watch a recorded stream

Currently you may only watch a recorded stream via RTMP, HLS variants would mean to prepare a split up playlist before. The nginx module does not do that for permanent storage. (Watch the blog for a future article about transcoding/hls)

When you click the record link (to either start or stop recording) the file name, to which it will record, will be displayed, just use the last part (without the path) in the RTMP VOD url to play that file: http://streaming.example.com:1935/vod/<filename>

Wrap up

It's not that complicated to run a simple streaming server, and the version I described here does not even use a lot of CPU as it does no transcoding. All you need is bandwidth and a streaming source that is configured to send a stream everyone can use.

Watch the blog for another article on transcoding and how to really trash your CPU performance on a streaming server ;)