使用nginx,在一个容器中实现RTMPS和HLS的播放(nginx + stream + rtmp)
由于某种原因,我们似乎需要建立一个使用nginx-rtmp-module自己搭建的RTMP视频传输平台。这篇文章是关于这个过程中的笔记。
实现的内容
这篇文章的结构如下所示。
正如标题所示,我们通过一个容器来实现视频传输和视频分发。
首先是视频传输的发送端。
我们使用OBS或者Microsoft Teams将视频传输到443端口。同时,使用RTMPS来防止窃听和篡改。首先,视频会通过nginx的stream模块接收,并且使用SSL通信进行终止。接着,通过SNI选择转发目标的后端,并最终被发送到nginx的RTMP模块,并保存为HLS文件(*.m3u8, *.ts)。
在接收端,我们使用网络浏览器通过HTTPS访问443端口。我们使用nginx的stream模块来终止SSL通信,并通过SNI将数据传输至HTTP的后端。通过加载HLS文件和HTML播放器,我们可以播放视频。
通过这种配置,可以使用具有RTMP视频传输功能的客户端,例如OBS或Microsoft Teams,将视频传送到远程地点。
关于stunnel的信息
如果使用nginx和RTMPS关键词进行搜索,可以发现一种使用stunnel终止来自OBS或Microsoft Teams的SSL的配置。但是,使用nginx的流模块可以实现相同的SSL终止,并且可以享受nginx访问控制的好处,并且可以集中配置。因此,最终不再使用stunnel。
nginx的Dockerfile
只需一种选择,以下是中文的原生改写版本:
Dockerfile对tiangolo/nginx-rtmp镜像进行了一些修改。由于这个镜像没有包含nginx的stream模块,因此我添加了–with-stream和–with-stream_ssl_module选项来配置它。
FROM buildpack-deps:bullseye
# Versions of nginx and nginx-rtmp-module to use
ENV NGINX_VERSION nginx-1.23.2
ENV NGINX_RTMP_MODULE_VERSION 1.2.2
# Install dependencies
RUN apt-get update && \
apt-get install -y ca-certificates openssl libssl-dev && \
rm -rf /var/lib/apt/lists/*
# Download and decompress nginx
RUN mkdir -p /tmp/build/nginx && \
cd /tmp/build/nginx && \
wget -O ${NGINX_VERSION}.tar.gz https://nginx.org/download/${NGINX_VERSION}.tar.gz && \
tar -zxf ${NGINX_VERSION}.tar.gz
# Download and decompress RTMP module
RUN mkdir -p /tmp/build/nginx-rtmp-module && \
cd /tmp/build/nginx-rtmp-module && \
wget -O nginx-rtmp-module-${NGINX_RTMP_MODULE_VERSION}.tar.gz https://github.com/arut/nginx-rtmp-module/archive/v${NGINX_RTMP_MODULE_VERSION}.tar.gz && \
tar -zxf nginx-rtmp-module-${NGINX_RTMP_MODULE_VERSION}.tar.gz && \
cd nginx-rtmp-module-${NGINX_RTMP_MODULE_VERSION}
# Build and install nginx
# The default puts everything under /usr/local/nginx, so it's needed to change
# it explicitly. Not just for order but to have it in the PATH
RUN cd /tmp/build/nginx/${NGINX_VERSION} && \
./configure \
--sbin-path=/usr/local/sbin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--pid-path=/var/run/nginx/nginx.pid \
--lock-path=/var/lock/nginx/nginx.lock \
--http-log-path=/var/log/nginx/access.log \
--http-client-body-temp-path=/tmp/nginx-client-body \
--with-http_ssl_module \
--with-threads \
--with-ipv6 \
--with-stream \
--with-stream_ssl_module \
--add-module=/tmp/build/nginx-rtmp-module/nginx-rtmp-module-${NGINX_RTMP_MODULE_VERSION} --with-debug && \
make -j $(getconf _NPROCESSORS_ONLN) && \
make install && \
mkdir /var/lock/nginx && \
rm -rf /tmp/build
# Forward logs to Docker
RUN ln -sf /dev/stdout /var/log/nginx/access.log && \
ln -sf /dev/stderr /var/log/nginx/error.log
# Set up config file
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 1935
CMD ["nginx", "-g", "daemon off;"]
获得证书
这次我们从Let’s Encrypt获取了证书。
虽然不详细说明步骤,但为了备忘,我会附上获取证书时使用的docker-compose.yml。
version: "3"
services:
certbot:
image: certbot/certbot:latest
volumes:
- type: bind
source: ./data/certbot/etc/letsencrypt
target: /etc/letsencrypt
- type: bind
source: ./data/certbot/var/lib/letsencrypt
target: /var/lib/letsencrypt
command: ["certonly", "--manual", "--agree-tos", "--no-eff-email", "--preferred-challenges", "dns"]
执行命令如下。
docker compose run -f docker-compose-certbot.yml --rm certbot
本次我们设置了 –preferred-challenges 为 dns,以获得WildCard证书。
此外,由于在本地进行了测试,所以名称指向将是内部IP地址。
以下是要在公共DNS上注册的记录示例。注意,example.com部分是虚构的,需要根据获得的域名进行更改。
建構
在此,我将解释一下构建步骤。由于我们没有在GitHub或其他地方公开文件,因此本文中写的内容将涵盖可展示的全部内容。
使用的背景/环境
-
- Windows 10
-
- Docker Desktop for Windows
-
- WSL2
- OBS 29.1.2
文件组织
在运行Docker的终端内创建以下类似的文件结构。
- data/
- nginx/
- hls/ # HLSファイル保存場所
- deployments/
- nginx/
- certs/
- certificate.crt # Let's Encrypt 証明書
- private.key # Let's Encrypt 秘密鍵
- etc/
- nginx/
- nginx.conf
- www/
- index.html # ビデオプレイヤー
- images/
- nginx/
- Dockerfile
- nginx.conf # イメージビルド用nginx設定
- docker-compose-certbot.yml
- docker-compose.yml
docker-compose.yml 的释义是 “Docker 组合文件”。
这次考试使用的 docker-compose.yml 文件在这里。
version: "3"
services:
nginx:
build:
context: ./images/nginx
volumes:
- type: bind
source: ./deployments/nginx/certs
target: /certs
- type: bind
source: ./deployments/nginx/etc/nginx/nginx.conf
target: /etc/nginx/nginx.conf
- type: bind
source: ./deployments/nginx/www
target: /www
- type: bind
source: ./data/nginx/hls
target: /hls
ports:
- "80:80"
- "443:443"
- "1935:1935"
正在公開端口80和1935,但由於僅用於測試,所以在正式部署時是不必要的。
nginx的配置文件
这次使用的nginx配置文件在这里。
worker_processes auto;
error_log /var/log/nginx/error.log info;
pid /var/run/nginx.pid;
rtmp_auto_push on;
events {
worker_connections 1024;
}
rtmp {
server {
listen 1935;
listen [::]:1935 ipv6only=on;
application live {
live on;
record off;
hls on;
hls_path /hls;
hls_fragment 10s;
}
}
}
stream {
map $ssl_server_name $backend {
www.local.live.example.com 127.0.0.1:80;
rtmp.local.live.example.com 127.0.0.1:1935;
}
server {
listen 443 ssl;
listen [::]:443 ssl ipv6only=on;
ssl_prefer_server_ciphers on;
ssl_certificate /certs/certificate.crt;
ssl_certificate_key /certs/private.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE:HIGH:!aNULL:!MD5;
proxy_pass $backend;
}
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
gzip off;
keepalive_timeout 65;
server {
listen 80;
location /hls/ {
alias /hls/;
}
location / {
alias /www/;
}
}
}
正如往常一样,example.com 是虚拟的,您需要根据自己拥有的域名进行更改。
总结这项设置的整体情况如下。
-
- stream
443 ポートで待ち受け
SSLを終端
SNIの名前に基づいて 80 か 1935 ポートに振り分ける
rtmp
1935 ポートで待ち受け
映像を受信するとHLSファイルを保存
http
80 ポートで待ち受け
HLSファイルとビデオプレイヤーを公開
HTML视频播放器
以下是播放HLS视频的HTML视频播放器。此次使用了Video.js。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Live</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="https://vjs.zencdn.net/8.3.0/video-js.css" rel="stylesheet" />
<style>
body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div style="height: 100vh">
<video
autoplay
id="player"
class="video-js"
style="width: 100%; height: 100%;"
controls
muted
preload="auto"
width="640"
height="360"
data-setup="{}">
<source src="/hls/hogehoge.m3u8" type="application/vnd.apple.mpegurl" />
</video>
</div>
<script src="https://vjs.zencdn.net/8.3.0/video.min.js"></script>
</body>
</html>
在这个文件名中写着“hogehoge.m3u8”,其中的“hogehoge”部分对应于输入到OBS或Microsoft Teams的流密钥。
执行 (shí
完成构建后,执行服务器。
$ docker compose up
rtmp-server-nginx-1 | 2023/07/27 04:58:21 [notice] 1#1: using the "epoll" event method
rtmp-server-nginx-1 | 2023/07/27 04:58:21 [notice] 1#1: nginx/1.23.2
rtmp-server-nginx-1 | 2023/07/27 04:58:21 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
rtmp-server-nginx-1 | 2023/07/27 04:58:21 [notice] 1#1: OS: Linux 5.10.102.1-microsoft-standard-WSL2
rtmp-server-nginx-1 | 2023/07/27 04:58:21 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
rtmp-server-nginx-1 | 2023/07/27 04:58:21 [notice] 1#1: start worker processes
rtmp-server-nginx-1 | 2023/07/27 04:58:21 [notice] 1#1: start worker process 7
rtmp-server-nginx-1 | 2023/07/27 04:58:21 [notice] 1#1: start worker process 8
rtmp-server-nginx-1 | 2023/07/27 04:58:21 [notice] 1#1: start worker process 9
rtmp-server-nginx-1 | 2023/07/27 04:58:21 [notice] 1#1: start worker process 10
rtmp-server-nginx-1 | 2023/07/27 04:58:21 [notice] 1#1: start worker process 11
rtmp-server-nginx-1 | 2023/07/27 04:58:21 [notice] 1#1: start worker process 12
rtmp-server-nginx-1 | 2023/07/27 04:58:21 [notice] 1#1: start cache manager process 13
然后,进行OBS的流媒体设置。
一旦在OBS上开始直播后,只要能够从https://www.local.live.example.com/显示视频播放器,并且视频能够正常播放,就可以了。
总结
好像没有对nginx + stream + rtmp 组合进行说明的文章呢,所以这次我来总结一下。
使用nginx-rtmp-module,似乎可以轻松地实现“只有在Microsoft 365的认证基础上认证的用户才能进行流媒体的发布和观看”的功能,也许以后我会尝试一下。