Re-encoding a live-stream using nginx-rtmp on Ubuntu 20.04


I started live-streaming my gaming sessions a few months ago and have been using the NVENC encoding. I found that the quality wasn’t that great and I had a Ubuntu server around and I wanted to try to find out what I could do with it to help have better quality on my stream, and maybe record all my sessions with a higher quality.

I also didn’t want to buy a capture card or a Windows license for my server since I’m very comfortable with Ubuntu Server and didn’t have more usable hardware around.

The setup

Ubuntu server

Ubuntu Server 20.04 LTS.
On it is installed nginx-rtmp and FFmpeg.

Main computer

I use this computer for pretty much everything I do.
I use OBS with NVENC encoding.

Settings for the main computer

In OBS, I use NVENC encoding @ 50 Mbps bit rate and I use my monitor’s native resolution (1080p). I do not record on this computer, for some reasons OBS seems to slow down after a few hours while recording (When the recording file is about 100 GB).

Settings for the server

Installing FFmpeg

sudo apt install ffmpeg

Compiling and installing nginx with the rtmp module

You need to install the prerequisite libraries, download and unpack the latest nginx and the rtmp module. Then you need to build nginx including the nginx-rtmp module.

sudo apt install build-essential libpcre3-dev libssl-dev zlib1g-dev
tar -zxvf nginx-1.19.1.tar.gz
tar -zxvf v1.2.1.tar.gz
cd nginx-1.19.1/
./configure --add-module=../nginx-rtmp-module-1.2.1 --with-cc-opt="-Wimplicit-fallthrough=0"
sudo make install

Startup script

Create a new file at /lib/systemd/system/nginx.service with this content:

Description=The NGINX HTTP and reverse proxy server

ExecStartPre=/usr/local/nginx/sbin/nginx -t
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID


To enable nginx on startup:

sudo systemctl enable nginx
sudo systemctl start nginx

NGINX configuration

The default location for the nginx configuration file is /usr/local/nginx/conf/nginx.conf.

At the end of the file, add the following:

rtmp {
	server {
		listen 1935;
		chunk_size 4096;

		application livein {
			live on;

			exec ffmpeg -i "rtmp://” -vb 1800k -minrate 1800k -maxrate 1800k -bufsize 1800k -s 1280×720 -c:v libx264 -preset faster -r 60 -g 120 -keyint_min 60 -x264opts “keyint=120:min-keyint=120:no-scenecut” -sws_flags lanczos -tune film -pix_fmt yuv420p -c:a copy -f flv -threads 8 -strict normal “rtmp://";

			record_path /your/path;

			recorder allin {
				record all;
				record_suffix -allin-%F-%H-%M-%S.flv;
				record_interval 15m;

		application liveout {
			live on;
			record off;
			push rtmp://TWITCH_ADDRESS;

Basically what will happen here is that you will stream to the livein application, it will execute the FFmpeg command (That we will see in details further down the page) that re-encodes the stream using libx264 with good quality, constant bit rate and the right key interval for Twitch. (Those settings gives an “Excellent” rating by Twitch)

The entry stream will also be recording everything with video files that lasts 15 minutes each (To get highlights it’s usually better to work with smaller files).

Also, please note that this configuration is for 60 FPS streaming. If you want to lower it to 30 FPS you will need to keep all the key-frame settings in par.

General rtmp settings explained

All possible directives explained

  • record_path: Set this to the path at which you want to record everything.
  • recorder: This is a recorder set
  • record: This is set to all so we get both audio and video into the files.
  • record_suffix: I set it like that so I can easily identify the files using the hour of the day.
  • record_interval: This is set to 15 minutes, it will restart recording each times this interval is reached.

You may want to play with the Access settings (Allow/Deny) to only allow your local network to have access to your “In” stream. You can read more in the nginx-rtmp wiki here.

FFmpeg settings explained

  • -i: This is the input (Your stream, using the right STREAM_KEY)
  • -vb, -minrate, -maxrate, -bufsize: I found out that my stream was a lot more stable when all of those where the same size. -vb is the video bit rate, -minrate and -maxrate needs to be the same for Twitch (Constant bit rate).
  • -s: This is the output resolution you want. Here I transcode from 1080p to 720p.
  • -c:v libx264: The encoder you want to use (I strongly recommend to use libx264)
  • -preset: You can play around with this setting depending on your server. I use the faster preset and it works fine. You could try fastest (To use less CPU) or fast (To use more CPU).
  • -r, -g, -keyint_min 60, -x264opts-r is your FPS. -g needs to be double your FPS (To have 2 seconds key-frame interval as requested by Twitch). -keyint_min is set to the same as my FPS. The content of -x264opts is to do the same thing about the key-frame interval.
  • -sws_flags: I use this to have a better down-scale quality.
  • -tune: I played around a few of this settings, and had the best experience with film you might need to play around this setting, but film is a safe choice.
  • -pix_fmt: This is the picture format, yuv420p seems to be the most supported/popular one.
  • -c:a: The audio codec is set as copy so it won’t re-encode the stream’s audio.
  • -threads: The number of CPU cores/threads you want to use. I have 8 on my server.

The output needs to be your liveout application with the right STREAM_KEY.

Running the server

You can start the nginx server by running the following command:

sudo systemctl start nginx

Setting up the main computer

Using OBS, in your broadcast settings you need to use the “Custom” streaming service. The FMS URL will be something like rtmp:// (Use your own server’s IP). Your Stream Key needs to be the same you used in your nginx configuration.

In the Encoding part I use Nvidia NVENC (Since it doesn’t use a lot of CPU). I do not have CBR checked and the quality balance is set to 10. My Max bit rate is set to 50000 Kb/s (Since it’s only going to communicate on my local network). You may need to adjust your max bit rate according to your needs and capabilities.

As for Audio encoding, I use the AAC codec, 160 bit rate and a Format of 48 Khz.


I hope that I covered everything that was required for this setup to work. If you feel like I forgot anything, please add a comment.

If you have any questions, feel free to add a comment on this blog post, I will be reading and answering them.