Docker部署go2rtc:统一RTSP/WebRTC/HLS多协议流媒体网关指南
1. 为什么先把 go2rtc 拉进 Docker:多协议拆解
1.1 RTSP、RTMP、HLS、WebRTC、MJPEG 到底各管什么
如果你和我一样同时接触过安防摄像头、直播推流、Web 播放器这三类东西,会很快意识到一个尴尬:摄像头最擅长的是 RTSP,但浏览器不直接支持 RTSP;直播平台习惯收 RTMP 推流,但监控头又不会自己推 RTMP;手机浏览器里 HLS 能放,延迟却又高得离谱;至于 MJPEG,虽然老设备喜欢用,但码率爆炸、画质一般。于是你不得不在各个协议之间来回搭桥。
go2rtc 解决的就是这件事,它把这些协议的“翻译”工作集中到一个轻量进程里。它本身不是转码工具,而是一个多协议流媒体网关——往里看,可以接 RTSP 摄像头、RTMP 直播流、HTTP-FLV、HLS、MJPEG、WebRTC 源;往外看,又能以任意一种你想要的协议把同一路视频分发出去。这一点非常关键,去看 go2rtc 的文档时会发现它的核心概念只有一个:stream。一个 stream 就是一路视频源,你给它取个名字,比如
front_door
,之后所有客户端都通过这个名字来拿流,至于拿的时候想要 RTSP 还是 HLS 还是 WebRTC,由 go2rtc 处理。
我在部署之前最担心的是“协议转换会不会要 CPU 重编码”,实际跑起来才发现大部分情况它只做 remux(转封装),也就是把 H.264/H.265 的裸流从 RTSP 容器里拆出来,再装进 WebRTC 或 HLS 的容器里,视频编码不做二次压缩。摄像头是什么编码,输出就是什么编码,所以 CPU 占用低得不像一个实时转码服务。只有当浏览器不支持原始编码(比如某些安卓 WebView 不认 H.265)时,才需要走 ffmpeg 转码,这个你可以选择在 go2rtc 里让它自动调用,也可以自己单独开一个 ffmpeg 进程处理,灵活度很高。
1.2 和 ffmpeg / mediamtx / 成品NVR 有什么本质区别
网上讲流媒体服务器,经常会被几个名字绕晕:ffmpeg、mediamtx(原 rtsp-simple-server)、gstreamer、ZoneMinder、Frigate、go2rtc。我刚开始也以为它们都是同类,其实分工差别很大。
ffmpeg 是“瑞士军刀”,几乎什么都能做,但它是命令行工具,本身不常驻监听端口,也缺少给客户端动态分配流的能力。你用它做流媒体服务,需要自己写一大堆进程管理、流状态判断、端口分配逻辑,复杂度一下子上去了。
mediamtx 更接近“纯 RTSP/RTMP 服务器”,它能收流、能分发,但有协议覆盖没有 go2rtc 广,尤其在 WebRTC 和 HLS 上,需要配合其他组件才能做到低延迟浏览器播放。
NVR(比如成品录像机、Synology Surveillance Station)解决的是录像、回放、告警、用户权限管理,它更重,也更偏存储,而不是灵活输出。你要把摄像头流接给 Home Assistant 或自研 Web 页面,NVR 往往给不出一个干净的
rtsp://
地址让你随便消费。
go2rtc 的定位正好卡在中间:不抢 NVR 的录像饭碗,不做重转码,但它把“摄取多路源”和“多协议分发”这件事做到极简。举个例子,我有一只摄像头同时要被 Home Assistant 抓实时流、被一个老旧的 NVR 拉存储流、被家里人用手机浏览器看,放在以前得分别配置三套路径,在 go2rtc 里只需要配置一个流名称,三种消费端自己去选协议。这个“一份源、多协议分发”的模型,是我最终留下来的主要原因。
1.3 go2rtc 不适合干的事
我也要泼一点冷水,它不是万能的。第一,它默认不带录像回放 UI,你可以拿它配合 ffmpeg 落地录像文件,但没有漂亮的时间轴回放界面;第二,它没有用户权限体系,登录、多用户、摄像头权限隔离这些都得靠外部的反向代理或认证网关来做;第三,如果需要广电级大规模分发、多节点调度,它同样不是这个方向。
所以比较恰当的使用姿势是:go2rtc 做流媒体接入与协议汇聚的那一层,录像、告警、权限交给其他更专业的系统。把这个边界想清楚,后面才不会出现“装了 go2rtc 之后发现少了一堆功能”的落差感。
2. 部署前的规划:网络模式、端口和摄像头选型一起说
2.1 摄像头侧最常见的前置条件
我踩过最大的坑其实发生在部署 go2rtc 之前:有一台家用摄像头压根不提供 RTSP 地址,只给手机 App 看,问客服也只丢过来一个“云平台专用”的说法。这种设备无论用什么流媒体服务器都接不进去,所以选摄像头时第一条原则就是确认支持 RTSP/ONVIF 标准协议。海康、大华、TP-Link、宇视这些安防品牌的主流型号基本都支持,但一些纯互联网品牌的低成本云台摄像头很可能不支持主动拉流。
另一件容易被忽略的事是摄像头是否需要先“激活”。新买的海康/大华设备,第一次通电后必须用官方工具或浏览器激活并设置密码,否则 RTSP 地址就算写对了,也会返回 401 或连接被拒绝。很多刚接触的人卡在“扫到设备但拉不到流”,其实不是 go2rtc 的问题,而是摄像头还没有完成初始化。先把摄像头通过官方 App 或浏览器后台激活,再进到“网络-高级设置”里打开 RTSP 服务,接下来才有得谈。
2.2 端口规划与 network_mode: host 的原因
go2rtc 默认监听这几个端口:
| 端口 | 协议 | 用途 |
|---|---|---|
| 1984/TCP | HTTP | Web 管理界面、API、HLS、MJPEG 输出 |
| 8554/TCP | RTSP |
RTSP 拉流端口,客户端用
rtsp://IP:8554/流名称
访问
|
| 8555/UDP | WebRTC | WebRTC 信令与媒体传输的默认入口 |
我在 Docker 里给 go2rtc 用的网络模式是
network_mode: host
,而不是默认的 bridge。原因很直接:WebRTC 要同时走 UDP 和 TCP,端口协商比较活跃,如果用桥接网络再手动映射端口,遇到 ICE 候选地址取不到正确 IP 的情况会非常痛苦。host 模式下容器直接复用宿主机网络栈,go2rtc 能拿到真正的局域网 IP,WebRTC 通话建立的稳定性高很多。代价就是端口隔离没了,宿主机上其他服务要避开这三个端口,尤其是 8555 这种 UDP 端口冲突时不太容易察觉。
如果是在 Windows 上用 Docker Desktop,host 网络的支持有限,那就只能老老实实用端口映射,把
1984/TCP
、
8554/TCP
、
8555/UDP
映射出去,同时确认 Windows 防火墙放行对应端口。局域网内自用没问题,但不要指望 WebRTC 在所有复杂网络环境里都一次成功。
2.3 资源你想多了:其实省得很
我用一台只有 2 核 CPU、2GB 内存的老迷你主机跑了 8 路 1080p 摄像头,全部走 H.264 直通、不做转码的情况下,内存占用长期在 200MB 上下,CPU 占用在 5% 到 15% 之间波动,主要消耗在 WebRTC 打包和 HTTP 分发。真正吃 CPU 的是 ffmpeg 转码,尤其是 H.265 转 H.264,那个开销能瞬间吃满好几个核。所以如果预算有限,路线很明确:优先保证摄像头输出 H.264,go2rtc 只做 remux,资源问题基本不存在。
3. Docker Compose 部署 go2rtc 的完整过程
3.1 目录结构与 compose 文件
我的宿主机上专门建了一个目录
/opt/go2rtc
,所有文件都放在里面,方便后续备份配置和查看日志。目录结构很简单:
mkdir -p /opt/go2rtc
cd /opt/go2rtc
touch go2rtc.yaml
go2rtc.yaml
是它的核心配置文件。初次部署时不需要写太多,先留一个最小配置让它跑起来,确认服务正常后再慢慢加摄像头流。最小配置大概长这样:
log:
level: info
api:
listen: ":1984"
rtsp:
listen: ":8554"
webrtc:
listen: ":8555"
如果你用的是 Docker Compose,
docker-compose.yml
可以这样写:
services:
go2rtc:
image: alexxit/go2rtc:latest
container_name: go2rtc
restart: unless-stopped
network_mode: host
volumes:
- ./go2rtc.yaml:/config/go2rtc.yaml
注意这里的挂载路径是
/config/go2rtc.yaml
,不是随意指定的,go2rtc 镜像默认从
/config
目录读取配置。漏掉这个路径,启动后你会发现自己写的配置完全没生效。另外官方镜像名是
alexxit/go2rtc
,在 Docker Hub 上可以直接拉取;如果网络拉镜像慢,设置一下 Docker 的镜像加速器会省心很多。
3.2 启动与验证
一切都准备好后,执行:
docker compose up -d
docker compose logs -f go2rtc
日志里没有报错后,先验证 HTTP 服务是否正常:
curl http://localhost:1984/api/streams
刚启动时没有配置任何流,这条命令会返回一个空数组或空的 JSON 对象,那就说明服务已经在跑了。接着打开浏览器访问
http://宿主机IP:1984
,会看到 go2rtc 自带的 Web UI。这个界面虽然朴素,但非常实用,既能实时预览流,也能直接在里面测试添加摄像头。
到这一步已经完成了 80%,剩下的时间基本都花在配摄像头上。如果你是第一次跑,建议先别急着加很多路流,就加一路最熟悉的摄像头,把“从 Web UI 点击预览”这条链路打通,再批量接入剩余设备。
3.3 Windows/macOS 用 Docker Desktop 时的桥接替代
如果你没有 Linux 服务器,只能用 Docker Desktop,host 网络方案在 Windows 上并不好用。这时候改为端口映射模式:
services:
go2rtc:
image: alexxit/go2rtc:latest
container_name: go2rtc
restart: unless-stopped
ports:
- "1984:1984"
- "8554:8554"
- "8555:8555/udp"
volumes:
- ./go2rtc.yaml:/config/go2rtc.yaml
这种模式下,Web UI 访问
http://localhost:1984
没问题,RTSP 播放一般也能通,WebRTC 预览则可能因为 NAT 和防火墙问题出现“一直连接中”。我的建议是:Windows 上如果只是临时调试,用 bridge 模式足够;要长期当家庭流媒体中心用,还是弄一台 Linux 小主机或者直接用 WSL2 里的 Docker 更省事。
4. 接入摄像头的正确姿势:从已知 URL 到可用流
4.1 主流摄像头 RTSP 地址规则
写 go2rtc 配置之前,最关键的是搞到摄像头的真实 RTSP 地址。这个地址不是随便猜的,不同品牌有固定的 URL 风格。
海康威视系设备常见格式:
rtsp://用户名:密码@摄像头IP:554/Streaming/Channels/101
其中
101
表示第一通道的主码流,
102
是第一通道的子码流。如果摄像头是多通道的,依次是
201
、
202
这样。萤石云设备如果已经开放了 RTSP,也沿用类似的路径。
大华系设备常见格式:
rtsp://用户名:密码@摄像头IP:554/cam/realmonitor?channel=1&subtype=0
这里的
channel=1
是通道号,
subtype=0
表示主码流,
subtype=1
表示子码流。子码流通常只有 720p 甚至更低,码率也小,适合多人预览和网页低延迟播放;主码流则留给录像或需要在电视上全屏看高清的场景。
还有一部分摄像头支持 ONVIF 标准,但 ONVIF 自己并不定义绝对的 RTSP 路径,它只告诉你的客户端“RTSP URL 在哪个地址”。用 ONVIF Device Tool 或 VLC 的“打开网络串流”功能,输入设备的 IP 和账号密码,有时候能直接探测到。但要注意,扫到 URL 不代表能一直稳定用,很多固件会把 RTSP URL 动态调整,所以我还是建议进入摄像头后台的“媒体设置”页面里查看官方给出的地址示例,那个最靠谱。
4.2 把多路摄像头写进 streams 配置
有了地址后,在
go2rtc.yaml
里的
streams
段中逐条写入即可:
streams:
gate:
- rtsp://admin:密码@192.168.1.64:554/Streaming/Channels/102
yard:
- rtsp://admin:密码@192.168.1.65:554/cam/realmonitor?channel=1&subtype=1
workshop:
- rtsp://admin:密码@192.168.1.66:554/Streaming/Channels/102
这里我给
gate
、
yard
、
workshop
分别起了容易记的名字,后面所有客户端都按名字取流,不用再记一大串带账号密码的 RTSP URL。注意我特意用了子码流(海康
102
,大华
subtype=1
)来做日常预览,因为这几路只是需要“能看”,子码流已经足够,还能大幅节省带宽和并发压力。
改完配置后重启容器让配置生效:
docker compose restart go2rtc
然后回到 Web UI,你应该能看到这三条流出现在列表里,点击任意一条就能实时播放。如果播放失败,先别急着改配置,用后面的 ffprobe 方法验证一下原始地址究竟通不通。
4.3 临时摸流:Web UI 和 ffprobe 配合
go2rtc 的 Web UI 上有一个输入框,可以直接临时添加流,不需要编辑配置。这个功能对调试特别友好,你可以先在 UI 上写一条
test: rtsp://...
,点击连接看看能不能出画面。但临时加的流不会保存到配置文件里,重启后会消失,确认没问题后还是要写进
go2rtc.yaml
。
如果想从命令行侧确认摄像头地址是否正确,用 ffprobe 是最快的:
ffprobe -rtsp_transport tcp "rtsp://admin:密码@192.168.1.64:554/Streaming/Channels/102"
如果能够打印出视频流信息,说明地址和账号密码都没问题。如果卡住不动或报错,大概率是地址格式错了、账号密码不对、摄像头没有启用 RTSP,或者摄像头和 go2rtc 之间跨了网段导致 RTSP 握手失败。我遇到过一台摄像头在 VLAN 的另一个网段里,VLC 能看,go2rtc 却连不上,最后发现是交换机上限制了该网段的 RTP 媒体端口,放行后立刻就好了。像这种跨网段问题,最好先临时把 go2rtc 网段和摄像头网段打通,或者通过交换机出口放行 UDP/TCP 端口,不要指望纯软件层能解决。
5. 多协议分发实战:一部流给所有端
5.1 浏览器低延迟预览靠 WebRTC
go2rtc 最惊艳我的部分是它内置的 WebRTC 能力。以前要在 Web 页面上看 RTSP 监控,常见方案是后端用 ffmpeg 转 HLS,延迟随随便便两三秒,而且每增加一个观看者就要多开一路转码进程。go2rtc 的浏览器预览走的是 WebRTC,协商好后可以直接点对点传媒体流,延迟通常在几百毫秒左右,而且不需要额外装插件。
在 Web UI 里点击某个流名称,go2rtc 会尝试用 WebRTC 建立连接。如果几秒内出画面,说明端口和网络都正常。如果一直转圈,优先排查 8555/UDP 端口是否被防火墙拦截、宿主机的网络是否为 NAT 多层环境。WebRTC 对 NAT 穿透的要求比较苛刻,在公司网络或手机热点环境下,偶尔会因为 UDP 被限制而失败,这时可以退回 HLS 模式看,只是延迟会变高。
5.2 统一输出给 ffplay、VLC、HLS、MJPEG
摄像头接入 go2rtc 后,一个流名称就可以对应多种播放方式。比如我在客厅的电视盒子上用 VLC 看门口摄像头,VLC 里填的就是:
rtsp://go2rtc主机IP:8554/gate
如果是在公司电脑上临时网页查看,直接访问:
http://go2rtc主机IP:1984/gate.m3u8
go2rtc 会根据路径后缀自动把流转成对应协议。
gate.m3u8
就是 HLS 播放列表,
gate.mjpeg
就输出 MJPEG 流,一些老的嵌入式设备或低版本浏览器可以通过 MJPEG 方式拿到画面。命令行下想快速验证流是否正常,可以:
ffplay -rtsp_transport tcp rtsp://127.0.0.1:8554/gate
这种“同一个流名称,后缀决定协议”的设计,几乎不需要学习成本,对集成开发特别友好。我在给自己的小面板写监控页面时,只需要把
http://go2rtc主机IP:1984/gate.mjpeg
塞进
<img>
标签,页面立刻就有画面了。
5.3 一份输入多份输出:推到 RTMP/其他系统
go2rtc 的 streams 配置支持把同一个源同时输出到多个目标。写法是把源地址和输出地址写成一个数组:
streams:
gate:
- rtsp://admin:密码@192.168.1.64:554/Streaming/Channels/102
- rtmp://127.0.0.1:1935/live/gate
这样 go2rtc 会先拉取摄像头 RTSP,再以 RTMP 客户端身份推给本地另一个流媒体服务或直播平台。以前要做这种“一边本地看、一边推直播平台”的操作,得自己写一个 ffmpeg 循环脚本,还要处理断流重连;go2rtc 这里把输入和输出当成同一个流,断流后会自动重连,省了很多事。
如果你有多个下游系统,继续往数组里加即可。不过要提醒一点:每个输出目标都会增加一路会话,虽然 go2rtc 不转码,但网络带宽和连接数还是会线性增加。我的经验是,下游在局域网内就优先用 RTSP 或 WebRTC,跨公网就用 RTMP 或 HLS,不要所有目标全都用同一种协议。
5.4 想要录像文件?go2rtc 不做 NVR 但能配合
go2rtc 自身不带录像管理界面,但它输出的 RTSP 流非常适合被外部工具消费。我自己用了一个很轻量的方案:写一个定时 ffmpeg 命令,从 go2rtc 拉一路 RTSP,按小时切片保存成 MP4。
ffmpeg -rtsp_transport tcp -i rtsp://127.0.0.1:8554/gate -c copy \
-f segment -segment_time 3600 \
"/video/gate_%Y%m%d_%H%M%S.mp4"
这段命令的关键是
-c copy
,不转码,只做封装切片,CPU 占用几乎为零。只要磁盘够大,就能按小时生成一段录像。配合 cron 定期清理过期文件,一个轻量录像系统就搭起来了。回放体验虽然不如专业 NVR,但对家庭用、只求留痕来说是性价比极高的方案。
如果家里有 Frigate 这类 AI 检测系统,也可以让它直接连 go2rtc 的
rtsp://127.0.0.1:8554/流名称
,这样前端预览统一走 go2rtc 的 WebRTC,后端检测分析走 Frigate,两不耽误。
6. 跑了一段时间后踩到的坑,能少走就少走
6.1 花屏/延迟高:先怀疑传输而不是转码
我刚开始接入某台 TP-Link 摄像头时,Web UI 预览花屏严重,画面还经常卡住。第一反应是 go2rtc 转码不行,后来用 ffprobe 直接连原始 RTSP 地址也同样花屏,才意识到是摄像头和主机之间的网络传输问题。这种花屏大概率是 RTSP 默认使用 UDP 传输,跨交换机或 WiFi 环境下丢包导致的。
解决方法有几个方向:一是到摄像头后台把 RTSP 传输方式改成 TCP,很多摄像头默认是 UDP;二是降低码率,主码流如果设成 8Mbps 以上,普通 WiFi 的稳定性很难扛住;三是尽量用有线连接摄像头和 go2rtc 主机。go2rtc 这边的配置也可以加参数强制走 TCP,但不同品牌对参数的支持不太一样,最稳妥还是在摄像头后台直接设置。
还有一个小技巧:同一路摄像头,日常预览用子码流,需要截图或录像时才切主码流,这样花屏概率会小很多。我用海康的
102
子码流和主码流做过对比,子码流在弱网下的表现明显稳定,画面清晰度也足够手机观看。
6.2 并发连接多了之后 UDP 端口不够用
go2rtc 的 WebRTC 默认监听 8555/udp,但实际的媒体流离不开 RTP 端口分配。当多个客户端同时通过 WebRTC 看不同摄像头,或者一个页面开了多个画面时,偶尔会出现“连接建立成功但画面一直黑”的情况,看日志会发现是 UDP 端口资源不足。这个问题在 host 网络模式下相对少见,但如果你用的是 bridge 映射模式,Docker 的端口隔离会加剧这个现象。
我的处理方式是:如果 WebRTC 并发要求高,优先回到 host 网络模式;在宿主机防火墙里放行 8555/udp,以及可能需要的高位 UDP 端口段。因为 go2rtc 在不同版本里对 WebRTC 端口的使用策略有调整,最直接的办法是启动后查看日志里有没有 “Failed to listen” 之类的报错,根据日志提示去放行对应端口,比照着旧文档猜省力得多。
6.3 私有协议摄像头“扫到地址也拉不动”的真实原因
有些摄像头虽然可以被 ONVIF 工具扫到,甚至显示出一个 RTSP 地址,但填到 go2rtc 里就是连不上。我遇到过两种典型情况:一种是通过 ONVIF 扫出来的地址里带的是 ONVIF 服务端口,而非 RTSP 媒体端口,需要手动改成
554
;另一种是摄像头固件限制只有特定来源 IP 可以发起 RTSP 拉流,比如只在“可信 IP”里加白名单,go2rtc 所在主机的 IP 不在名单里就会被静默拒绝。这类问题排查起来很费时间,我的建议是直接进摄像头后台找“RTSP 认证”或“访问策略”相关选项,把 go2rtc 主机 IP 加进允许列表。
另外,如果你手头有“只支持主动推流的云摄像头”,也就是设备只会定时往厂商云平台推流,不支持外部主动拉 RTSP,那么任何流媒体服务器都拉不到它。这种情况只能放弃接入,或者换支持 RTSP 推送的设备。不要被“扫到端口”这个表象迷惑,连接不上就是连接不上,别再耗时间。
6.4 默认零认证:千万别把 1984 直接暴露到公网
go2rtc 默认没有任何认证机制,这是它保持轻量的一部分原因,但也意味着只要你的 1984 端口暴露在公网,任何能访问到的人都可以看到全部摄像头的画面,甚至可以往里面添加自己的流的地址,完全失控。这个安全隐患比“录像被偷看”更严重,因为攻击者可以利用它做跳板。
我的安全原则很明确:
- go2rtc 的端口只允许局域网或受信任的内网网段访问,公网防火墙直接丢弃外部到 1984 的请求;
- 如果确实需要远程观看,前面要套一个带身份认证的反向代理,用 Basic Auth 或更复杂的登录认证都行,不要在 go2rtc 本身上面裸奔;
- 不要为了方便直接做端口转发,修改 go2rtc 默认端口也改变不了什么,攻破扫描器对常见端口的探测易如反掌,真正要解决的问题是“谁能访问它”,而不是“它在哪个端口”。
最后分享一个我的使用习惯:我会把所有摄像头的子码流都以
流名称_sub
的形式接入,浏览器和 Home Assistant 预览统一用子码流,只有需要回看细节时才切到主码流。这样既保证了多端并发的流畅性,又不会因为带宽压力影响整个网络。go2rtc 这套东西不复杂,但它把“多协议流媒体平台”的门槛降低了非常多,如果你手上正好有一堆规格参差不齐的摄像头,很值得花一个晚上部署起来。
更多推荐
所有评论(0)