From the Terminal

Configuring an RTMP streaming server for VRChat with Nginx

I recently picked up a Valve Index and I've started to explore the music community

One of the most compelling aspects of VRChat as a platform is how you can use it as a way of discovering music. A vast and diverse community of individuals with varied musical tastes and backgrounds already exists. In VRChat, you can attend music festivals, explore custom-built music worlds, and interact with other users who share your passion for various musical genres. This environment encourages discovery and exposes you to a wide range of genres, artists, and tracks that you may not have encountered otherwise. It's a melting pot of musical creativity waiting to be explored.

Moreover, VRChat offers a unique opportunity for musicians, DJs, and producers to hone their craft and experiment with performing, mixing, and DJing in a virtual setting. Through the integration of streaming music into VRChat, you can curate and share playlists, perform live DJ sets, and even create your own virtual music venues. The interactive nature of VRChat enables you to receive immediate feedback from your audience, allowing you to refine your skills, experiment with new techniques, and build a dedicated following.

While Twitch and YouTube have transformed the streaming landscape, they do have limitations that can impact the quality and control of your stream. These platforms often inject ads into your content, disrupting viewer engagement, and they impose restrictions on bitrate, limiting the stream's video quality. To overcome these challenges, many streamers are turning to Nginx for RTMP. By configuring Nginx to stream directly to your audience, you regain control over your stream, eliminate unwanted ads, and achieve higher bitrates for an uninterrupted, high-quality viewing experience.

This reference should let you quickly set up a public facing site.

nano /etc/nginx/sites-enabled/stream.conf 
server {
        listen  443 ssl;

        server_name stream.yourdomain.example;
        ssl_certificate /etc/letsencrypt/live/stream.yourdomain.example/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/stream.yourdomain.example/privkey.pem; # managed by Certbot

        include sites-available/include-ssl.conf;

        server_tokens off;

        # rtmp stat
        location /stat {
                rtmp_stat all;
                rtmp_stat_stylesheet stat.xsl;
        }
        location /stat.xsl {
                root /var/www/stream/rtmp;
        }

        # rtmp control
        location /control {
                rtmp_control all;
        }

        location /hls {
                # Serve HLS fragments
                types {
                        application/vnd.apple.mpegurl m3u8;
                        video/mp2t ts;
                }
                root /tmp;

                add_header Cache-Control no-cache;

                add_header 'Access-Control-Allow-Origin' '*' always;
                add_header 'Access-Control-Expose-Headers' 'Content-Length';
                if ($request_method = 'OPTIONS') {
                        add_header 'Access-Control-Allow-Origin' '*';
                        add_header 'Access-Control-Max-Age' 1728000;
                        add_header 'Content-Type' 'text/plain charset=UTF-8';
                        add_header 'Content-Length' 0;
                        return 204;
                }
        }


}

Make sure to add this global rtmp config.

sudo nano /etc/nginx/rtmp.conf
rtmp {
  server {
    listen 1935; # this is the port, you may change it if necessary.
    chunk_size 4096;

    application live { # "live" may be changed to whatever you'd like, this will affect the URLs we use later, though.
      live on;

      allow publish 0.0.0.0; # put your IP here.
      deny publish all; # denied if none of the above apply.

      # -- HLS --
      hls on;
      hls_path /tmp/hls; # this is where all of HLS's files will be stored.
                         # They are a running replacement so disk space will be minimal. 
                         # Adjust other HLS settings if necessary to level it out if it's a problem.


      hls_playlist_length 60s;
      hls_fragment 1s;

      # optionally,
      hls_continuous on;
    }
  }
}

Add this to the bottom of /etc/nginx/nginx.conf

include rtmp.conf;

The URL will actually be rtmp://stream.yourdomain.example/live/random-stream-key but in OBS we will actually put in rtmp://stream.yourdomain.example/live and the second field in OBS is our key.

Finally the stream link we will put into VRC will look like this.

https://stream.yourdomain.example/live/random-stream-key.m3u8