NGINX-RTMP – How to Receive RTMPS Stream on NGINX-RTMP

nginxrtmpssl

Standard practice for RTMP is still to have a plain text stream key out on the wires.

I want to acccept RTMPS streams from encoders to NGINX however the RTMP module does not yet have RTMPS.

I'm not interested in all the relay solutions to allow taking an RTMP stream and sending to a place like facebook over RTMPS because the same security flaw is still there because at some point you are passing the keys over plain text.

My question is where can I find the reference specs on RTMPS? I'd like to know what keys are needed to make a proper handshake between an RTMPS source such as OBS and NGINX and then I will use the connection with the RTMP module. Can normal keys and an authority like Let's Encrypt be used on a server so that it can make the handshake with a RTMPS encoder?

I've seen stunnel used to wrap RTMP in TLS. Is it possible to do the reverse — use stunnel to receive RTMPS and convert back to RTMP for the RTMP module?

Best Answer

UPDATE: This is my original answer that describes pretty well the issues one may face while implementing RTMPS with Nginx. However, I've added an improved version for more fine-tuned access control, and I recommend using the configuration from it, instead.


Yes, this is possible with stunnel, as RTMPS is just a RTMP session wrapped inside a standard TLS session. The examples on the Internet are mostly RTMP→RTMPS i.e. the stunnel is working as a plain text server and TLS client, which is configured with client = yes. Without that, the client defaults to no, which is the server mode.

The stunnel configuration could look like this:

[rtmps]
accept = 1935
connect = 127.0.0.1:1936
cert=/etc/letsencrypt/live/rtmp.example.com/fullchain.pem
key=/etc/letsencrypt/live/rtmp.example.com/privkey.pem

With this:

  • The Nginx should be listening for RTMP on local loopback, port 1936/tcp.
  • As you can't renew the Let's Encrypt ertificate using RTMP, you might need a HTTP server block for the HTTP-01 challenge, too.
  • As the connection to Nginx always comes from the stunnel i.e. from the 127.0.0.1, you can't use the allow/deny directives to limit connection based on IP addresses anymore. This means your access control would be limited to the key, alone, but at the same time it's less of a problem, as it's transmitted encrypted.

    However, this still causes problems, as you'd push the stream from the same IP than the clients that are using it, but you can't allow them to publish to your stream. Luckily, you don't have to push the stream from the application with the key, but you can also pull it from the public application (/live).

The following Nginx example configuration takes these considerations into account:

rtmp {
    server {
        listen 127.0.0.1:1936;
        chunk_size 4096;

        application app-secret-stream-key {
            live on;
            record off;
            allow publish 127.0.0.1;  # for streaming through stunnel
            allow play 127.0.0.1;     # for the pull from /live
        }

        application live {
            live on;
            record off;
            deny publish all;         # no need to publish on /live
            allow play all;           # playing allowed

            pull rtmp://127.0.0.1:1936/app-secret-stream-key;
        }
    }
}

http {
    server {
        listen 80;
        server_name rtmp.example.com;

        location ^~ /.well-known/acme-challenge/ {
            root /var/www/letsencrypt;
        }
        location / {
            return 404;
        }
    }
}

However, this is just an example, so you can and should modify it to fit your exact needs. (Also, I haven't tested this configuration but written it solely based on the documentation, so please feel free to correct, if I got something wrong.)