资讯详情

资讯详情

PixelStreamingInfrastructure HTTPS 部署指南:信令服务器与 Nginx 配置

去年接了一个数字孪生项目对方用 UE5 做场景前端要内嵌到 Web 管理后台里我这边负责把 PixelStreamingInfrastructure 部署起来。刚开始为了省事直接跑 HTTP连上半天发现摄像头给不了权限浏览器控制台里全是被拦的报错。折腾一圈才明白这套像素流送的基础设施不支持 HTTPS 就是不行而且不是“锦上添花”是一切音视频 API 能用的前提。今天这篇就把 PixelStreamingInfrastructure 支持 HTTPS 这件事从头到尾讲清楚从基础设施里有哪些组件、需要哪些证书到信令服务器到底怎么改配置、Nginx 怎么反代、常见坑怎么排全部按我实际操作的顺序来。你无论是已经跑通了 HTTP 版的像素流送想补上 HTTPS还是准备从零搭一套都可以直接把这篇文章当操作手册用。1. 先搞明白 HTTPS 在 PixelStreamingInfrastructure 里管的是哪一段1.1 这套基础设施是由什么组成的PixelStreamingInfrastructure 严格说是 UE 像素流送的配套后端组件它解决的是“浏览器端拿到视频流数据”之前的那些连接管理问题。整套东西通常分三块一是信令服务器Signalling Server负责浏览器和 UE 渲染节点之间的控制信息交换比如“我要开始连接”“分辨率改成多少”“连接断开”这些消息走的都是 WebSocket二是转发单元SFU负责把 UE 端编码好的视频流通过网络转发给浏览器端同时把浏览器端的音频、鼠标键盘控制指令回传给 UE三是前端连接脚本也就是你在网页里用来建立连接、控制播放的那部分 JavaScript。三者配合起来才算一个完整的像素流送基础服务。在实际部署里信令服务器与 SFU 往往部署在同一台服务器上浏览器先通过 WebSocket 和信令服务器协商再由信令服务器指导浏览器与 SFU 建立 WebRTC 连接。所以这里牵扯到两类网络通道一类是页面到信令服务器之间的 WebSocket另一类是浏览器到 SFU 之间的 WebRTC 媒体通道。HTTPS 对它们的影响不是平均的WebSocket 是最先出问题的。1.2 浏览器把“非加密连接”管得很死很多第一次接触的人都会问我就是内网部署又没有传输敏感数据为什么要上 HTTPS根源不在“数据是否敏感”而在于浏览器对 WebRTC 和音视频 API 有硬性的安全上下文Secure Context要求。所谓安全上下文简单说就是页面的访问协议必须是 HTTPS 或者是 localhost。否则像 getUserMedia摄像头和麦克风权限、RTCPeerConnection 这些接口根本不会正常响应浏览器直接在源头给你卡住。我那次踩坑的报错非常典型getUserMedia() is not allowed in insecure context这意味着就算把 UE 的像素流送到了浏览器页面不能请求摄像头和麦克风权限远程操作时语音对话和视频通话部分就是废的。更麻烦的是 WebRTC 连接本身也会被浏览器限制有些设备上直接抛错有些设备上则是静默失败排查起来特别折磨。除了安全上下文还有个“混合内容”的问题。你的页面如果已经是用 https 打开的页面内部再去发起ws://或http://请求会被浏览器视为混合内容Mixed Content在 Chrome 和 Edge 里默认拦截。偏偏像素流送的前端脚本一定会主动建立 WebSocket 连接如果信令服务器没有启用 HTTPS前端在 https 页面下就等于没法和后端握手整个像素流送直接废掉。所以结论很明确PixelStreamingInfrastructure 支持 HTTPS 不是可选项而是让浏览器愿意配合你的前置条件。2. HTTPS 落地的整体选型证书、端口、代理层一起规划2.1 证书方案怎么选域名证书、内网自签还是临时证书动手改配置之前先解决证书问题。像素流送服务器正常部署时需要三类选择有公网域名的服务器、纯内网服务器、以及本地调试环境。有公网域名时最省事的方案是 Lets Encrypt 的免费证书。利用 certbot 之类的工具可以自动申请并定期续期。证书签发后拿到两个文件一个是fullchain.pem里面包含站点证书和中间证书另一个是privkey.pem是私钥文件。这两个文件在 SignallingServer 的 SSL 配置里要直接用到。纯内网环境没有公网域名你可以自建 CA然后给内网服务器签发一张证书。但这有个前提所有访问像素流送页面的客户端机器都得安装并信任你自建的根证书。否则浏览器一样会给一个红色警告并且依然会被当成不安全上下文。公司内部管理员统一分发根证书的话这种方式完全可行而且成本为零。本地调试还有一种偷懒办法直接用自签名证书临时顶一下。Chrome 和 Edge 在访问自签名证书站点时如果用户手动点击“继续前往”页面仍然处于安全上下文WebRTC 相关接口可以正常工作。但这种方案只能用于开发机调试不能拿到生产环境因为让用户每次都要在浏览器里点“仍然继续”显然不现实。用 IP 地址直接访问也是常见做法。需要注意证书里的 SAN 必须包含对应 IP不能只在 Common Name 里写。现在的浏览器基本不认 CN 字段只认 SAN。2.2 两种部署方式直接开启 TLS 与 Nginx 反向代理拿到证书后接着要决定在哪里终结 TLS。PixelStreamingInfrastructure 的 SignallingServer 本身支持在配置里指定 SSL 证书也就是可以直接让信令服务器自己启用 HTTPS。SFU 的配置里也支持 SSL 参数可以单独开启 TLS 监听。这种方式配置简单适合信令服务器直接暴露在客户端网络里、且端口使用没有被限制的环境。另一种更常见的做法是加一层 Nginx 反向代理。Nginx 监听 443 端口并终结 TLS然后把解密后的流量转发到本地跑在 HTTP 端口上的 SignallingServer。这样做的好处很多证书续期可以集中在一起后续如果想配置访问控制、限流、日志分析在 Nginx 层做就行不用改信令服务器的代码遇到同时部署多套 UE 像素流送实例时通过不同的 location 路由也更灵活。我实际操作中比较推荐生产环境用 Nginx 反向代理。不是因为 SignallingServer 原生的 HTTPS 不行而是后期运维成本和排查体验差距太大。随便举个例子如果同时跑信令服务器和 SFU原生配置 SSL 时每个组件的配置里都要放证书路径一旦证书更新得逐个改而统一在 Nginx 层处理只改一个 server 块。2.3 端口规划HTTP、HTTPS 与媒体 UDP 端口的配合像素流送涉及的端口比普通网站多一些。除了网页服务的 80/443信令服务器还会监听自己的 WS/WSS 端口SFU 还要占用 UDP 媒体端口。默认情况下SignallingServer 配置里可以同时设置 HTTP 端口和 HTTPS 端口也可以只开其中一个。如果走 Nginx 反代我习惯的做法是Nginx 监听 443处理 HTTPS 页面访问和 WSS 请求。SignallingServer 只监听内网地址的 HTTP 端口例如 127.0.0.1:8080不给外网直接访问。SFU 的媒体端口保持 UDP 映射该暴露还是要暴露因为 WebRTC 媒体流走的是 UDP不走 Nginx 代理。这里有个经常被忽略的点。UE 像素流送的播放页面几乎都需要加载快照图和信令地址页面会向前端脚本注入信令服务器的地址。如果你在网页里用的是https://yourdomain.com那么前端脚本里拼接的 WebSocket 地址后面一定要跟上对应的路径且协议要变成wss://。很多配置失败往往就是把端口改成了 443但 WebSocket 路径还停留在ws://。3. 实操记录一步一步给 PixelStreamingInfrastructure 加上 HTTPS3.1 准备证书文件并按标准格式放置先按我常用的目录结构来做证书文件不建议散落在根目录。我在信令服务器目录下建一个certs文件夹把证书统一放进去同时设置文件权限避免私钥被其他进程读取。PixelStreamingInfrastructure/ SignallingServer/ certs/ fullchain.pem privkey.pem如果用的是 certbot 申请的证书fullchain.pem和privkey.pem在/etc/letsencrypt/live/你的域名/目录下也有现成的。复制到项目目录后可以用下面的命令快速确认证书有效期和基本信息openssl x509 -in fullchain.pem -text -noout | grep -A 1 Subject Alternative Name这个命令会输出证书的 SAN 列表确保证书里包含你实际访问用的域名或 IP。这一步跳过的话后面大概率会碰到浏览器说不安全、证书不匹配的问题。3.2 修改 SignallingServer 配置文件开启 HTTPSPixelStreamingInfrastructure 的 SignallingServer 核心配置在config.json里。不同版本字段名多少有点差异但大体是下面这个结构{ httpPort: 8080, httpsPort: 443, ssl: { key: ./certs/privkey.pem, cert: ./certs/fullchain.pem } }这里有几点要注意。如果你希望 HTTP 和 HTTPS 都能访问就同时保留httpPort和httpsPort如果只想要 HTTPS可以把httpPort删掉或设为 0但我不建议直接删因为本地排查时 HTTP 入口还是很有用的。比如我习惯留着httpPort监听在内网 IP 上用于快速验证服务是否正常。ssl配置里指定的路径是相对当前工作目录的。如果你是从其他目录启动服务器建议直接用绝对路径或者在启动前cd到配置目录。我见过很多次“配置明明写了证书路径但启动就报 ENOENT”的情况基本都是相对路径没对上。修改完成后启动 SignallingServer看日志里有没有 TLS 相关的输出。正常启动后可以用以下命令检查端口是否在监听netstat -tunlp | grep 443然后再用curl测试 HTTPS 协议是否正常返回curl -v https://127.0.0.1:8443/3.3 使用 Nginx 反向代理时的关键配置我自己生产环境用的方案是 Nginx 反代。这里贴一份比较典型的配置信令服务器跑在 127.0.0.1:8080Nginx 监听 443。server { listen 443 ssl http2; server_name pixelstream.example.com; ssl_certificate /etc/letsencrypt/live/pixelstream.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/pixelstream.example.com/privkey.pem; location / { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 3600s; proxy_send_timeout 3600s; } }这里最核心的是三行proxy_http_version 1.1、proxy_set_header Upgrade $http_upgrade、proxy_set_header Connection upgrade。WebSocket 协议要求基于 HTTP/1.1 的连接升级机制如果没有这三行浏览器和信令服务器的 WebSocket 握手会失败页面里只会报 WebSocket 连接错误但你不一定能立刻想到是 Nginx 没配好。proxy_read_timeout和proxy_send_timeout建议调大。像素流送的信令连接不是一次请求就结束而是长时间保持的 WebSocket 连接。Nginx 默认超时只有 60 秒左右如果不调大用户隔一会儿不动信令连接就被 Nginx 强制断开随后前端脚本会疯狂重连症状看起来像像素流送时断时续。如果还希望 HTTP 的 80 端口自动跳转到 HTTPS可以在 Nginx 里加一个额外的 server 块做 301 跳转server { listen 80; server_name pixelstream.example.com; return 301 https://$host$request_uri; }3.4 验证链路是否真正加密配置完成后不要急着关控制台我会先做一轮链路验证。在浏览器用https://pixelstream.example.com打开像素流送页面按 F12 打开控制台切到 Network 面板刷新页面后找 WebSocket 连接。如果连接状态是 101 Switching Protocols并且请求地址是wss://pixelstream.example.com/...说明信令链路已经走 WebSocket over TLS。然后在控制台的权限部分确认是否出现了摄像头和麦克风权限请求。如果浏览器正常询问权限说明安全上下文这件事解决了。接下来可以再验证信令服务器与 SFU 之间的连通性。在服务器上执行lsof -i -P -n | grep -E Signalling|SFU|node看看信令服务器是否成功连接到了 SFU 的端口。如果 SFU 配置也要求 TLS信令服务器与 SFU 之间的 WebSocket 也需要加 wss 前缀。这个要看具体配置但大多数情况下两者在同一内网继续用 ws 问题不大。4. 实战踩坑HTTPS 接入过程中的典型问题4.1 混合内容拦截看到 ws:// 报错先查协议最常见的问题就是页面是 HTTPS但前端脚本里的信令地址还是ws://。浏览器控制台会给出非常明确的提醒Mixed Content: The page at https://... was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint ws://.... This request has been blocked.这种问题处理起来不难但很烦人因为报错出现在前端而很多人先想到的是信令服务器是不是挂了。排查思路应该是先打开前端脚本看它生成 WebSocket 地址的地方有没有依赖当前页面协议。如果前端脚本用window.location.protocol判断页面是 HTTPS 时它会自动生成wss://如果是写死的ws://那就要改代码或改配置。我在接入 SFU 时也遇到过类似情况。PixelStreamingInfrastructure 前端不仅要连信令服务器有时候还要从 SFU 获取额外配置如果这些配置里写死的是 HTTP 地址同样的混合内容拦截还是会出现。4.2 证书链不完整导致的握手失败另一个高频问题是证书链不完整。用 certbot 签发的证书如果直接把cert.pem而不是fullchain.pem配置上去看起来证书文件是存在的但浏览器检查证书链时会发现缺少中间证书导致握手失败。对应的浏览器报错一般是NET::ERR_CERT_AUTHORITY_INVALID排查方法很简单用 openssl 查看证书链openssl s_client -connect pixelstream.example.com:443 -showcerts如果返回的证书链里只有站点证书没有中间证书那就要换用fullchain.pem。需要注意在某些配置里官方模板只给了cert一项很多人习惯性地把 Lets Encrypt 的cert.pem填进去结果就是握手失败。4.3 SFU 连接异常信令通了媒体流还是起不来有次我把页面和信令服务器的 HTTPS 都配好了页面能打开权限也能正常请求但点连接后一直卡在等待状态。排查到最后发现是 SFU 配置里没有启用 TLS导致信令服务器转发给 SFU 的连接被拒绝。SFU 的配置文件和 SignallingServer 类似同样有ssl配置项。如果整个链路都要求加密SFU 也要配置证书。不过这里有个取舍如果信令服务器和 SFU 部署在同一台机器它们之间走内网 ws 其实风险很小但 SFU 对外提供 WebRTC 媒体流时浏览器端实际使用的是另外一套 DTLS 证书机制与 HTTPS 证书无关。所以不管 SFU 的 WebSocket 是否走 TLS媒体流本身都是加密的。我的建议是内网之间使用 ws 保持简单公网之间必须使用 wss。如果 SFU 和信令服务器跨机房部署又没走专线那就把这两者之间的连接也加密否则信令内容会在网络上明文传输。4.4 公网 IP 直连时出现的证书域名不匹配公网 IP 直连也是常见部署方式。证书里写了 IP 的 SAN但页面访问时用户直接用https://1.2.3.4/看起来没问题。但实际会遇到一个更隐蔽的问题前端脚本或信令服务器配置里填写的 public IP 和浏览器实际访问的域名不一致。比如用户用https://pixelstream.example.com/访问页面但信令服务器配置里的publicIp写的是公网 IP。这时发送给浏览器的 WebRTC 连接信息里的 candidate 地址是公网 IP浏览器照样能连接因为 WebRTC 本身不校验 HTTPS 证书域名。但信令服务器返回给前端用于建立 WebSocket 的地址如果是 IP浏览器访问的是域名这个地址在证书验证或者 Host 头校验那一层就容易被挡下来。对付这个问题最简单的方式是让全局配置统一使用域名不要混用 IP 和域名。尤其到了 Kubernetes 这类环境里如果部署参数写得乱七八糟到处拼接不同 host最后排查起来相当头疼。5. 性能影响与调优别让 TLS 拖慢像素流送的连接建立5.1 HTTPS 对连接时长的影响到底有多大很多人担心加了 TLS 会让像素流送的连接建立变慢实际上这个担忧在绝大多数场景下不成立。像素流送的连接建立过程本身就不快浏览器要加载页面、建立 WebSocket 信令、发起 WebRTC 连接、SDP 交换、ICE 协商一套流程下来几百毫秒很正常。HTTPS 的 TLS 握手也就增加一次或两次额外往返放在整个像素流送建连过程里占比其实很小。而且 WebRTC 媒体流本身已经通过 DTLS 加密了所以画面传输的延迟不会因为额外加了 HTTPS 而变高。真正影响像素流送延时的往往是编码参数和网络带宽TLS 那点握手开销基本可以忽略不计。5.2 握手优化Session Cache、OCSP Stapling 与 HTTP/2如果你还是要优化一下 TLS 握手速度可以考虑三件事。第一是启用 TLS Session Cache 或 Session Ticket让同一个浏览器多次连接时能跳过完整的握手过程。Nginx 里可以增加ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d;第二是启用 OCSP Stapling让服务器在握手阶段直接把证书的吊销状态发给浏览器省去浏览器再去访问证书吊销服务器的额外请求。Nginx 配置片段如下ssl_stapling on; ssl_stapling_verify on;第三是启用 HTTP/2在listen 443 ssl http2里已经包含。HTTP/2 会把多个页面资源请求合并到一个连接上对像素流送页面这种包含大量前端脚本的场景首屏加载能快不少。5.3 部署位置与资源开销的一个提醒TLS 加密和解密需要消耗 CPU但像素流送的主要压力根本不在信令服务器上而是在 SFU 转发视频流和 UE 端头的编码。信令服务器本身处理的只是 JSON 格式的小消息加上 TLS 后 CPU 占用基本无感。如果非要在性能上较真真正值得优化的是把 Nginx 反代放在靠近用户的地方减少 TLS 握手阶段的网络延迟。特别是用户跨地域访问时很大一部分时间消耗在来回握手和 WebSocket 连接建立上这个比证书选型影响大得多。从实际运维角度看PixelStreamingInfrastructure 支持 HTTPS 后给我带来的最大改变是不用再去和浏览器打架了。以前用 HTTP 时用户打开页面总有奇怪的小问题权限弹窗不出来WebSocket 被拦甚至某些手机上白屏。加上 HTTPS 这些问题基本消失后面的工作重心就回到了像素流送的画面质量和延迟调优而不是和浏览器安全策略较劲。如果条件允许我建议在项目一开始就规划好域名和证书策略。申请一个正式域名配上自动续期的证书部署脚本里顺手把 Nginx 反代和端口规划一起写进去省得后面再来补课。这套东西补起来不难难的是排查问题的时候分不清是协议问题、证书问题还是网络问题。提前把 HTTPS 做扎实后面跑 UE 像素流送能省掉一大半的麻烦。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →