Setting up a multistream Server with Nginx

Setting up a Multistream Server with Nginx

Table of Contents

  1. Introduction
  2. Step 1 - Setup
  3. Step 2 - Additional
  4. Step 3 - Configure

Introduction

For a while when I've been streaming games to Twitch I have been wanting to stream to Facebook, Mixer and Youtube as well. Some services like Restream.io offer a stream to multiple services at once but some of the features such as streaming to Facebook are paid features and costing over £15 a month its quite expensive to add in.

I set out to set up a new server that would allow me to do all of the services I wanted at once. With a bit of research I was able to find out about installing an RTMP module with nginx and this meant with a bit of thought I could use nginx to push the stream to multiple sources at once.

Now that I've completed a local version of this I wanted to implement a live version that I could use, with the success of my tests I was able to reproduce a multistream service on a remote machine which I will use to now stream to all of the services I want and more.

Step 1: Setting up and configuring the server

So firstly you need to get a machine, I purchased a VPS from OVH as they offer up unlimited bandwidth on their VPS machines.

So once my machine was setup I was emailed a password and root access. I got logged into the machine and begin to setup what I needed.

You'll need to build nginx as you will be adding the custom RTMP module to the build so download the latest version for stable release from the nginx website. Go to the nginx downloads page and copy the url for the next command:

cd ~
wget http://nginx.org/download/nginx-1.12.2.tar.gz
wget https://github.com/arut/nginx-rtmp-module/archive/master.tar.gz

This will download the nginx and the module required to build rtmp for nginx.

Now untar the files:

tar -xzvf nginx-1.12.2.tar.gz
tar -xzvf master.tar.gz

With this you should now see that you have two directories and two tar files, go ahead and remove the tar files as you wont need these again:

rm nginx-1.12.2.tar.gz
rm master.tar.gz

Move into the nginx directory and configure the install:

cd nginx-1.12.2
./configure --with-http_ssl_module --without-http_gzip_module --add-module=../nginx-rtmp-module-master 

You should now start preparing the module for make. If there are any errors here you should find why you are unable to build, likely it will be missing dependancies but if you are running a relatively new install of an Linux distro you should be fine.

With that we need to now make and make install

make
make install

Nginx will be built with the default values and you'll find that nginx is built straight to the /usr/local/nginx directory.

cd /usr/local/nginx
ls

You'll hopefully see a conf folder and a html folder there, this means we are ready to configure the nginx to use. But before we do that we should add the init.d and allow nginx to start on boot!

First grab a init.d command and allow it to be executed, Jason Giedymin has a great script that will do the job on Github so I've used this for the server:

wget https://raw.githubusercontent.com/JasonGiedymin/nginx-init-ubuntu/master/nginx -O /etc/init.d/nginx
chmod +x /etc/init.d/nginx
update-rc.d nginx defaults 

Perfect, should now have a working service command available.

Step 2: Additional files

For this you may need to add a few more requirements, as we will be using FFmpeg later I installed some more software using apt:

apt-get install software-properties-common 
apt-get install ffmpeg

If ffmpeg isn't available you can add a custom source:

add-apt-repository ppa:kirillshkrogalev/ffmpeg-next
apt-get update

I also needed to install curl as well:

apt-get install curl

Step 3: Configuring nginx

Now that we have nginx ready we should configure nginx to allow rtmp and http requests I've copied my configuration I used for testing I have put comments explaining each line.

The file you will want to edit is /usr/local/nginx/conf/nginx.conf:

user www-data;
worker_processes  1;

events {
    worker_connections  1024;
}

# http requests allow checking that rtmp is working and being published to
http { 

    # turn off server tokens and hide what server version you are using
    server_tokens off;

    include mime.types;
    default_type application/octet-stream;
    sendfile on;
    keepalive_timeout 65;

    server {
        listen 80;
        server_name localhost;

        error_log /var/log/nginx_error.log warn;

        # allows you to view stats
        location /stat {
            rtmp_stat all;
            rtmp_stat_stylesheet stat.xsl;
        }

        # allow stat xml styling to be accessed
        location /stat.xsl {
            root html;
        }

        # make a internal server page and put it in html
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
            root html;
        }
    }
}

# rtmp server configuration
rtmp {
    server {
        # port to listen on, I've left this as a default
        listen 1935;
        chunk_size 8192;

        # this is what you will stream to
        application live {
            live on;

            # record off means no vod saving
            record off;

            # allow publishing from all (change this to your ip if you wish to lock to ip address)
            allow publish all;

            # uncomment this if you are going to deny every ip other than yours
            # deny publish all;

            # push to all sub applications we will create (one each for each application)
            push rtmp://localhost/youtube;
            push rtmp://localhost/facebook;
            push rtmp://localhost/mixer;

            # for twitch I'm being more specific so I can define how my stream looks on twitch
            exec ffmpeg -i rtmp://localhost/$app/$name -c:v libx264 -preset veryfast -c:a copy
                  -b:v 3500k
                  -bufsize 3500k
                  -maxrate 3500k
                  -s 1280x720 -r 30
                  -f flv rtmp://localhost/twitch/$name;
        }

        # example youtube app
        application youtube {
            live on;
            record off;

            # only allow this machine to publish
            allow publish 127.0.0.1;
            deny publish all;

            # push url, this will be your stream url and stream key together
            push rtmp://{youtube-stream-url};
        }

        # example twitch app
        application twitch {
            live on;
            record off;

            # only allow this machine to publish
            allow publish 127.0.0.1;
            deny publish all;

            # push url, this will be your stream url and stream key together
            push rtmp://{twitch-stream-url};
        }
          application facebook {
            live on;
            record off;

            allow publish 127.0.0.1;
            deny publish all;

            # push url, this will be your stream url and stream key together
            push rtmp://{facebook-stream-url};

        }

        application mixer {
          live on;
          record off;

          # only allow this machine to publish
          allow publish 127.0.0.1;
          deny publish all;

          # push url, this will be your stream url and stream key together
          push rtmp://{mixer-stream-url};
        }
    }
}

Next to be safe you should now chown the following folders for nginx to be able to run them as appropriate:

chown -R www-data:www-data /usr/local/nginx/html

With this configuration you should now be able to push to your server ip using obs with the url: rtmp://myserver.org/live

Doing this means you can publish to all of your stream locations without any authentication. If you are restricting by IP you can feel safer knowing that nobody else can stream to your channels.

Now that we have added this configuration, restart nginx and check that nginx is running:

service nginx restart

If nginx is running correctly (without an errors shown) you should be able to do:

curl localhost:80/stat

And see a response. Huzzah we have it so now we can start streaming right away.

Conclusion

Hurray! So now you should be able to stream to all of your services at once. Next article I will make will explain how to use PHP to authenticate your rtmp with a stream key which will make it more secure.

Posted in DevOps, Misc on Feb 17, 2018