Launching your RTMP server for streaming

Sometimes YouTube or Twitch is not suitable as a streaming platform – for example, if you are sawing a portal with webinars or 18+ content, violate copyrights, or want to isolate your broadcast from the rest of the Internet as much as possible. They have many alternatives both in the form of services (the same cons, lack of control and unpredictable policies) and in the form of self-hosted solutions. The problem with open source streaming projects is that they all start with a tiny bundle of a couple of technologies, and then desperately try to grow into a service, adding complex web interfaces, chats, streaming libraries and ultimately moving away from the original goal: to give the world a tool that according to an understandable manual will allow you to start your broadcast server. What will happen to him next, in which systems this picture will be built – this is only your own business, and a self-written analogue of a twitch with lagging and falling off services and a periodically lying build is not needed by anyone except its developers. Therefore, in this article we will analyze the minimum chain of actions to start your own RTMP server with a player.


Everything is simple here: the Nginx RTMP module is responsible for receiving and encoding a stream from OBS. He puts the converted stream outside, where the HLS (HTTP Live Streaming) client picks it up in the browser and displays a ready-made picture in the player.


When choosing a server, the emphasis should be on the processor. I took epic server with two cores and tried to increase the bitrate in order to determine the boundary conditions – at 11-12k the load began to hang around 96-100%, so for processing a really heavy stream it is better to take capacities with a margin:

We will need Docker to install the containerized nginx-rtmp with FFmpeg and any web server (including the same Nginx) to serve up the page with the player. I installed on Ubuntu 20.04:

$ sudo apt-get update

$ sudo apt-get install 

$ curl -fsSL | sudo apt-key add -

$ sudo apt-key fingerprint 0EBFCD88

$ sudo add-apt-repository 
  "deb [arch=amd64] 
  $(lsb_release -cs) 

$ sudo apt-get update

$ sudo apt-get install docker-ce docker-ce-cli

We start the container with forwarded ports:

docker run -d -p 1935:1935 -p 8080:80 --rm alfg/nginx-rtmp

Then, in OBS on the client, we specify our server with an arbitrary stream key (key = stream identifier):

Now you can start broadcasting and make sure that the stream went, for example, to demo hls.js or in any other HLS player.

It remains to configure the server. In nginx.conf specify the path to your page:

location / {                                                    
  root /var/www/;                                                  
  index index.htm index.html;                                 
  autoindex on;                                
sudo nginx -s reload

In index.html, just copy and paste the code from the hls.js example:

  <script src=""></script>
  <!-- Or if you want a more recent alpha version -->
  <!-- <script src=""></script> -->
  <video id="video"></video>
    var video = document.getElementById('video');
    var videoSrc="";
    if (Hls.isSupported()) {
      var hls = new Hls();
      hls.on(Hls.Events.MANIFEST_PARSED, function() {;
    // hls.js is not supported on platforms that do not have Media Source
    // Extensions (MSE) enabled.
    // When the browser has built-in HLS support (check using `canPlayType`),
    // we can provide an HLS manifest (i.e. .m3u8 URL) directly to the video
    // element through the `src` property. This is using the built-in support
    // of the plain video element, without using hls.js.
    // Note: it would be more normal to wait on the 'canplay' event below however
    // on Safari (where you are most likely to find built-in HLS support) the
    // video.src URL must be on the user-driven white-list before a 'canplay'
    // event will be emitted; the last video event that can be reliably
    // listened-for when the URL is not on the white-list is 'loadedmetadata'.
    else if (video.canPlayType('application/')) {
      video.src = videoSrc;
      video.addEventListener('loadedmetadata', function() {;

Now on port 8080 of our server, a creepy cartoon about a hare is being heard:

It remains only to change the path to http://server_ip:8080/live/stream-key.m3u8 and go watch the broadcast!

You can check the real-time load with the docker stats command:


When placing a streaming client on your server, it is important to remember that all traffic from all viewers will pass directly through it – which means that if you have more than 1-2 people online at the same time, it is worth studying ways to distribute the load (after all, transcoding significantly puts pressure on the CPU). To launch a full-fledged cluster, there is an enterprise (but open source) solution – SRS aka Simple Realtime Server (Github, 10k stars, huge wiki, complex architecture). It is worth delving into if you need streams to solve real problems, and not to play with a private video stream.


Servers for rent for any task – this is about our epic! All servers are protected from DDoS attacks, automatic installation of multiple OSes or using their ISO image. Better to try it once!

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *