Setting up OBS for Twitch ( and / or YouTube ) with Nginx rtmp relay

Everything you need to relay your stream from OBS via nginx to the interwebz

Prerequisites

  • Have a linux vm with nginx installed
  • Have knowledge on the following topics: linux commandline nginx rtmp streaming
  • You should have at least one twitch channel and your key ready

P.s. i know you can directly stream from your pc to twitch. But this is a technical in-depth guide. So i took the hard way.

Introduction

I’m a gamer, although the last couple of years i only played World of Warcraft and some Forza Horizon 4. The content creator and streamer business is booming and i figured i’d take a look at it from a technical perspective. In this guide i will setup everything to stream from OBS to twitch (and youtube) via an nginx rtmp VM.

Software used:

For gaming and streaming i use Windows 11 as a operating system. My streaming software is OBS (because it is opensource).
For the relay i’ve used nginx + the rtmp module

Windows installation stuff.

note: if u use AMD graphics, please make sure you have this AMD Encoder installed.
In addition make sure you have MS Visual C++ redistributable installed.

OBS can be downloaded here

Configuring obs to stream to your nginx rtmp:

Open OBS:

  1. Click settings
  2. Go to: Stream
  3. Use these settings:
  • Service: custom
  • Server: rtmp://<your internal ip of the nginx vm>/live (i.e: rtmp://192.168.1.123/live)
  • Stream key: <make one up>
  1. Output: (set output mode: advanced and View Mode: Expert)
  • Audio track: 1
  • Encoder: H264/AVC Encoder (AMD Advanced Media network) note: use either your NVIDIA or the standard x264 here, if you don’t have AMD
  • preset: leave empty
  • Quality preset: Quality
  • Profile: high
  • Profile level: automatic
  • Coding type: Automatic
  • Rate Control Method: Constant Bitrate (CBR)
  • Pre-Pass mode: Disabled
  • Target Bitrate: 0
  • Filler Data: Enabled
  • Frame skipping: Disabled
  • VBAQ: Disabled (Still experimenting with Enabled)
  • Enforce HRD: Enabled
  • High Motion Quality Boost: Enabled
  • VBV Buffer: Manual
  • VBV Buffer Size: 35000
  • Keyfram interval: 2.004
  • Deblocking Filter: Enabled
  • Motion Estimation: Quarter- & Half-Pixel
  • Video-api: Direct3D 11 ( I couldn’t choose anything else)
  • Video Adapter: <your graphics card>
  • OpenCL Transfer: Disabled
  • OpenCL Conversion: Disabled
  • Mutli-Threading: Enabled
  • View Mode Expert
  1. Press apply
  2. In the TAB audio
  • Set all Audio Bitrate to 160
  1. Press apply
  2. Go to AUDIO
  • Desktop Audio: Choose whatever you use or speakers.
    You can split audio. So that people on the stream can only hear gaming sounds, but you can still hear discord etc on your heaphones. I will write a guide on this in a future post.
  • Mic/Auxiliary Audio: <your microphone>
  1. Go To Video
  • Base (Canvas) Resolution: choose your native resolution (i.e: 2560x1440)
  • Output (scaled) Resolution: 1920x1080
  • Downscale Filter: Lanczos
  • Common FPS Values: 30

Please keep in mind that you might need to tune these settings to meet the capabilities of your own hardware

Nginx & rtmp

Rtmp is a protocol created by adobe to stream video to flash. Flash has seen it’s end of life some time ago. But the protocol is still used.
What we’re going to do here is send the stream from OBS directly to nginx.
In nginx we’re going to transmux the original stream to another format which meets the standards of twitch.
This will make it possible for you to stream locally to for example VLC and simultaniously to twitch and/or youtube.

I’m not going to explain how to install a linux vm with nginx. There are plenty of guides of that to be found.

Underneath a basic example of how to create an application within nginx.conf note: you might need to chown /etc/nginx/logs to www-data (depending on the OS you use) The standard port for protocol rtmp is 1935. Underneath we have our “live” application. Which we specified in obs earlier.

Here is the code snippet of creating an rtmp application to relay the stream locally:

user  www-data;
worker_processes 4;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

error_log  /etc/nginx/logs/error.log;
error_log  /etc/nginx/logs/error.log  notice;
error_log  /etc/nginx/logs/error.log  info;

events {
    worker_connections 1024;
}

rtmp {
    server {
            listen 1935;
            chunk_size 4096;

            application live {
                   live on;
                   record off;
                   allow publish 127.0.0.1;
                   allow publish 192.168.0/24;
                   deny publish all;

           }
    }
}

Let’s say we want to transmux our stream and push it to another local app called twitch_relay.

First we need to transmux:

exec ffmpeg -i rtmp://127.0.0.1/$app/$name -threads 2 -vcodec libx264 -profile:v high -b:v 6000k -preset ultrafast -c:a copy -b:a copy -a:r copy -tune zerolatency -s 1920x1080 -r 30 -bufsize 35000 -frames:v 30 -aspect "16:9" -f libx264 rtmp://127.0.0.1:1935/twitchrelay/${name};

ffmpeg is the tool we use to encode the stream with video codec x264.
The main profile is used. Bitrate is set to 6MB per second or 6000k (Kbps) The preset is for how much CPU dedication should go to transmuxxing and since i want to give it high priority to reduce latency i set it to ultrafast Now let’s focus on the audio codec:

  • aac is the amount of channels which we set to 2 ( stereo)
  • the audio bitrate is set to 160
  • Our sample rate is set to 44100, which means 44,1kHZ, but you can also set it to 48000 (48kHz) note: make sure the audo settings correspond to the ones in OBS
  • Twitch allows in some cases to have you stream your native resolution. But since bandwith is capped, the resolution is scaled to 1920x1280
  • Again we use the libx264 to send the new file in that format.

Then this new stream is sent to the twitch relay app. Please note that:

  • $app or ${app} is the application you are “in” at that moment
  • $name or ${name} is the key you specified in OBS at stream, you should keep using it to make sure there are no issues in pushing the streams
  • {{ twitchkeyvar }} is the key from twitch, put your live_blabla key here.
  • {{ youtubekeyvar }} is the key from youtube, put your youtube stream key here.

Example of the addition of transmux and push:

user  www-data;
worker_processes 2;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

error_log  /etc/nginx/logs/error.log;
error_log  /etc/nginx/logs/error.log  notice;
error_log  /etc/nginx/logs/error.log  info;

events {
    worker_connections 1024;
}

rtmp {
    server {
            listen 1935;
            chunk_size 4096;

            application streambak {
                   live on;
                   record off;
                   allow publish 127.0.0.1;
                   allow publish 192.168.1.0/24;
                   deny publish all;


                  # transmux the original stream
                  exec ffmpeg -i rtmp://127.0.0.1/$app/$name -threads 2 -vcodec libx264 -profile:v high -b:v 6000k -preset ultrafast -c:a copy -b:a copy -a:r copy -tune zerolatency -s 1920x1080 -r 30 -bufsize 35000 -frames:v 30 -aspect "16:9" -f libx264 rtmp://127.0.0.1:1935/twitchrelay/${name};
                 # push to twitchrelay local "app"
                  push rtmp://127.0.0.1:1935/relay/${name};
           }

And then now for the twitch relay “app”. This will send the transmuxed stream to twitch with just the right tuning

user  www-data;
worker_processes 2;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

error_log  /etc/nginx/logs/error.log;
error_log  /etc/nginx/logs/error.log  notice;
error_log  /etc/nginx/logs/error.log  info;

events {
    worker_connections 1024;
}

rtmp {
    server {
            listen 1935;
            chunk_size 4096;

            application streambak {
                   live on;
                   record off;
                   allow publish 127.0.0.1;
                   allow publish 192.168.0.0/24;
                   deny publish all;


                  # transmux the original stream
                  exec ffmpeg -i rtmp://127.0.0.1/$app/$name -threads 2 -vcodec libx264 -profile:v high -b:v 6000k -preset ultrafast -c:a copy -b:a copy -a:r copy -tune zerolatency -s 1920x1080 -r 30 -bufsize 35000 -frames:v 30 -aspect "16:9" -f libx264 rtmp://127.0.0.1:1935/twitchrelay/${name};
                 # push to twitchrelay local "app"
                  push rtmp://127.0.0.1:1935/relay/${name};
           }

           application relay {
                  live on;
                  record off;

                  allow publish 127.0.0.1;
                  deny publish all;

                  #twitch stream
                  push rtmp://live.twitch.tv/app/{{ twitchkeyvar }}; # change it to your key here, this var is here for saltstack
        }
    }
}

Duo streaming to both twitch and youtube:

In application relay add the following underneath the push to twitch rtmp:

                  push rtmp://a.rtmp.youtube.com/live2/{{ youtubekeyvar }};

note: Recording is out of the scope of this guide so i will not explain that

Local testing

If you want to test your stream in VLC or for example kodi you can use the following example:

rtmp://192.168.1.123:1935/streambak/test

Kodi: Kf you want to do this in kodi, make a file called teststream.strm and place the above rtmp url in it. Then place it in a directory which you can acces from the kodi gui.
VLC: In vlc, click file > open network file stream and enter the above rtmp url.

Documentation:

Hardware used:

PC Specs:

  • CPU: AMD Ryzen 7 3700X
  • CPU Cooler: Cooler Master MasterAir MA610P
  • Motherboard: Asus TUF Gaming B550M-PLUS
  • Graphics Card: Sapphire Radeon RX 5700 XT Pulse
  • Memory: Corsair Vengeance RGB Pro CMW16GX4M2C3200C16
  • NVME: Intel 660p 1TB
  • SSD: Samsung SM863 960GB
  • PSU: Gigabyte B700H
  • Case: Cooler Master NR400 (without ODD)
  • Case Coolers: Cooler Master MasterFan MF120 Halo, 120mm (4x)

VM specs:

  • agent: 1
  • boot: order=sata0
  • cores: 4
  • machine: q35
  • memory: 2048
  • name: Hermes-Streaming
  • net0: virtio=<some_mac_adres>,bridge=vmbr0
  • numa: 0
  • sata0: data:206/vm-206-disk-1.qcow2,size=20G
  • scsihw: virtio-scsi-pci
  • smbios1: uuid=<uuid_number>
  • sockets: 1
  • vmgenid: <somenumber>

Additional settings:
( i use an i6500 skylake)

  • Type: Skylake-Client
  • CPU-units: 10000
  • Enable-numa: checked
  • pcid: on
  • spec-ctrl: on

note: The vm is running on a proxmox 7.1-8 server with the following specs:

  • CPU: Intel Core i5-6500 Boxed
  • CPU Cooler: Alpenföhn Ben Nevis
  • Motherboard: Gigabyte GA-H170-HD3
  • NIC 2: Intel Gigabit CT Desktop Adapter
  • NIC 1: Intel Pro/1000 PT Dual Port
  • Memory: Corsair Vengeance LPX CMK16GX4M2A2133C13 (4x8GB)
  • SDD 1: Samsung 830 series SSD 128GB
  • SDD 2: Samsung SM863 960GB
  • PSU: Corsair Builder CX430 Bronze
  • CASE: Cooler Master Silencio 550