你开放一个摄像头端口,把播放器指向它,然后以为互联网问题已经解决。然后手机放不了,浏览器放不了,而摄像头的管理页面距离公网边缘只差一个输错的路径。你选择的交付模型——RTSP 还是 HLS——在任何防火墙规则写下之前就已决定其中大部分。VPN 只提供私有那一段。

VPN 修复的是源路径,不是观看者路径

一台通过隧道接入摄像头局域网的 VPS 可以用摄像头的私有地址访问它,这确实有用。这意味着摄像头不需要自己的入站端口,家庭路由器保持关闭。它并不告诉你会话观看者将使用什么协议。桌面播放器、浏览器、手机和智能电视支持不同的协议,每一种对 TLS、身份验证和编解码器都有自己的预期。

这里有一个值得抛弃的假设:发布意味着让源可达。发布实际上意味着给一个明确定义的受众一种受支持的消费方式。已发布的流有格式、有受众、有凭据;可达的摄像头三样都没有。可达性是隧道解决的那一部分,而观看者入口是你仍然必须设计的那一部分。

RTSP 是协商,不是单个端口

RTSP 承载会话控制:客户端请求描述,建立一个或多个媒体轨道,然后播放。媒体本身的传输在建立过程中协商,所以仅用一个转发的 TCP 端口无法很好地描述该协议。那次协商正是人们比较防火墙规则时漏掉的部分。

取决于端点,RTP 可能到达单独的 UDP 端口,也可能复用在控制连接上。只转发 554、并假定其余部分会正常工作的中继,往往产生一个能连接、能报告轨道、随后却什么也不显示的会话。在为其编写规则之前,先确认你的摄像头实际协商的是哪种传输。在私有侧抓一次包一分钟就能回答,而猜测要花掉一个晚上。

对于规模小、已知且播放器兼容的受众,刻意配置的 RTSP 中继可能是正确答案。限制它可以拉取的源,并在中继上要求身份验证。把你测试过的播放器写下来,因为在 VLC 里能用的 RTSP 流在浏览器里仍可能失败。

HLS 是一个播放列表加资源

HLS 观看者先取一个播放列表,然后取该列表所指定的媒体分片。HLS 规范定义了这个资源模型,而重要的运维细节是播放列表会引用其他 URL。相对引用按播放列表的位置解析,所以重写路径的代理必须一致地重写它们。

如果摄像头已经提供可用的 HLS,公网前端可以跨隧道转发这些播放列表和分片请求。注意应用生成的密钥、重定向和 URL。任何指向私有主机的绝对 URL,都会在 LAN 之外的观看者跟随它的那一刻失效。相对路径才是能在代理重写后存活的路径,所以只要你能控制生成的输出,就优先使用它们。

如果摄像头只会说 RTSP,就必须有东西把源转换成观看者格式。重新封装和转码是不同的工作:重新封装保留编解码器,而转码为了兼容性重新编码,只有后者会消耗大量 CPU。仅因路径上存在 VPN 并不会让其中任何一个成为必需。

围绕分发发生的位置来规划上行链路。一个私有采集供给一个公共媒体服务,与每个观看者各自跨隧道拉流的行为完全不同。第二种模式通常以家庭连接饱和、摄像头看似随机故障告终。

把身份验证放在你发布的边缘

TLS、观看者身份验证和访问日志属于公网入口,而不属于摄像头。这使摄像头的凭据与流的凭据保持分离。它还给你一个地方,在受众成员离开时撤销访问。把这些控制放在摄像头上,反而意味着每次受众变动都变成对一台本就不该公网可达的设备的行政变更。

把 VPN 和摄像头的管理权限与发布路径分开。一台能够访问摄像头 Web 界面来拉流的 VPS,不应当同时是暴露该界面的机器。受众永远不应该知道摄像头的地址。

然后验证你实际构建的两端,而不是假定整条链能工作:

$ ffprobe -v error -rtsp_transport tcp rtsp://10.50.0.9:554/stream1
$ curl -sI https://stream.example.net/live/index.m3u8
HTTP/2 200
content-type: application/vnd.apple.mpegurl

对私有源的成功探测和在公网边缘成功获取播放列表,证明了设计的两半。分别测试它们。用与你的受众相同类型的客户端播放,才是覆盖整条链的唯一测试。

你最终得到的是一条每个环节都有用途的链:私有源、受限采集、选定的封装、获授权的观看者入口。这些环节没有一个是可选的,也没有一个是靠开放端口创造出来的。

相关文章