Self-hosting a Live Stream Server

Published 2022-06-15 on Cara's Blog - Permalink

This Sunday, I will be running the technical side of an online Pride event hosted by my partner. Part of this includes live music performances that all need to go to the same stream output. I also need to be able to scale and transcode the streams appropriately. There are, of course, commercial options available, but that wouldn’t be very fun (or cheap!). What fun is having servers if I can’t also mess around with them?

The specific final destination has particular codecs and resolutions, and they recommend something like Oven Media Engine to take in all the streams and allow them to be rebroadcasted into their intake server. I spent most of today trying to make it work, and while I was able to successfully send to it, I couldn’t get anything out of it, no matter how much I tried. This was mostly because of a lack of understanding on my part, but also the relatively confusing-to-newcomers way that the configuration and documentation is presented.

That’s not to say that it’s unfriendly to new users, just that it requires a lot more prior knowledge and research than I expected or was capable of dealing with in the moment. I’m sure it’s a wonderfully useful software, it just didn’t fulfill my need for something that could be set up and tested for this weekend.

Eventually I remembered an old post by Drew DeVault that talked about self-hosting his own live-streaming server with nginx. In it, he streams a screengrab of an X11 window via ffmpeg1 into a DASH2 sink using the nginx-rtmp module.

This looks great! Streaming into nginx that then can be republished and pulled into OBS for transcoding and restreaming. I ended up installing the RTMP module on one of my servers, and wrote the following configuration:

rtmp {
	server {
		listen 1935;
		chunk_size 4096;
		
		application live {
			live on;
			record off;
		}
	}
}

That’s really all it takes. 1935 is used because it’s the standard RTMP port, but really any one can be used. This lets me send streams to rtmp://<my-server>:1935/live/<key or name>. Where it says <key or name>, that’s the bit where you can separate each stream. Then, I can add a Media Source to OBS or VLC with that same URL, and it will automatically pull the stream down. By managing stream keys, you can have multiple people streaming in at once, and then switch between them using software like OBS.

I’m mostly using the stock OBS settings, but I’m making sure to use the x264 encoder and the veryfast encoder preset, which is easier on web browsers. There’s no noticable difference in quality, so in my opinion there’s no need to go any higher.

The RTMP module also lets you use the nginx allow and deny directives, for access control based on IP addresses or subnets. For example, if I only wanted to be able to stream from within my VPN, I could set

allow publish <my-laptops-vpn-ip>;
deny publish all;

which would only let my laptop (or any other IP I wanted) broadcast. I’m sure there’s some way to do this better, like predetermining which stream keys are able to play, but I haven’t been able to find it yet, so I’ve just been disabling the module when I don’t need it.

To recap, the general steps I took were:

  1. Install and configure the nginx RTMP module
  2. Configure OBS to stream to the RTMP URL
  3. Add a media source to VLC with that same URL to play

I hope this was able to help! I plan on looking into this more, especially the access control bits, so I’ll be sure to update this post with anything I find.

Update 2022-06-19:

I should’ve known this was too good to be true. RTMP does not do well with cross-continent streaming. The last act was delayed 30 minutes by technical audio difficulties from the extreme delay.

A better alternative would be SRT3, via nginx-srt-module. It uses UDP as the underlying protocol, so it’s more error-resistant. Part of the issue was a delay in tech checks and the network quality of the remote talent, but this was an issue that could have also been prevented by not using a protocol that’s not designed for cross-continent use.


  1. Which, if you didn’t know, is a really wonderful tool that can do basically anything related to A/V including transcoding and streaming. ↩︎

  2. Dynamic Adaptive Streaming over HTTP ↩︎

  3. Secure Reliable Transport ↩︎


Articles from my webring

Clippy: Deprecating `feature = "cargo-clippy"`

Since Clippy v0.0.97 and before it was shipped with rustup, Clippy implicitly added a feature = "cargo-clippy" config1 when linting your code with cargo clippy. Back in the day (2016) this was necessary to allow, warn or deny Clippy lints using attrib…

via Rust Blog February 28, 2024

Status update, February 2024

Hi! February is FOSDEM month, and as usual I’ve come to Brussels to meet with a lot of other FOSS developers and exchange ideas. I like to navigate between the buildings and along the hallways to find nice people to discuss with. This edition I’ve been invol…

via emersion February 20, 2024

Why Prusa is floundering, and how you can avoid their fate

Prusa is a 3D printer manufacturer which has a long history of being admired by the 3D printing community for high quality, open source printers. They have been struggling as of late, and came under criticism for making the firmware of their Mk4 printer non-…

via Drew DeVault's blog December 26, 2023

Generated by openring