用go2rtc统一接入RTSP摄像头:Docker部署与WebRTC低延迟播放实践
家里摄像头一多,问题就来了:海康的走RTSP、大华的走私有SDK、树莓派那边可能还在出MJPEG,手机上看个实时画面还得装三四个App,浏览器里根本没法直接打开RTSP流。我折腾过Mediamtx,也试过ZLMediaKit,最后固定下来用的是go2rtc——一个能把RTSP、RTMP、HLS、WebRTC、MJPEG这些协议全部打通的小工具,配合Docker跑起来,一台普通小主机就能把所有摄像头统一成一个流媒体出口,浏览器直接看、Home Assistant直接接、手机端不用装额外播放器。这篇就完整记录我怎么用Docker部署go2rtc,把手头各路摄像头接进来,以及这几个月踩过的坑。
1. 方案选型:为什么是go2rtc而不是其他流媒体服务
1.1 流媒体中间层的核心矛盾
摄像头本身不会输出浏览器能直接播放的协议。RTSP是监控领域事实标准,但浏览器不认,手机浏览器也不认;HLS延迟太高,看监控画面会感觉像在看“延时摄影”;MJPEG虽然万能但带宽浪费严重。这就需要一个中间层把摄像头原有的协议转换成浏览器、App、智能家居平台都能消费的格式。
我最早用的Mediamtx(前身是RTSP-Simple-Server),功能纯粹,但配置摄像头流时得手动给每路流指定协议和端口,摄像头一多配置就冗长。ZLMediaKit功能强,但部署和调优成本高,对只想把摄像头“接进来就能看”的场景有点杀鸡用牛刀。
go2rtc的定位很明确:不重复造轮子,而是做协议转换和流分发的中枢。它原生支持RTSP、RTMP、HLS、MJPEG、WebRTC、SIP,还能直接拉取ONVIF设备,甚至可以反向把流推给其他服务。最关键是它对WebRTC的支持做得非常顺滑——浏览器里看监控画面,延迟能压到几百毫秒,这才叫“实时监控”。
1.2 go2rtc的差异化优势
它的核心设计是“会话中按需拉流”。传统流媒体服务器会一直从摄像头拉流再分发,占带宽也占摄像头连接数;go2rtc可以配置成按需启动,有人看的时候才去拉摄像头流,没人看就断开,对摄像头和网络的压力都小很多。实测下来,家里3路摄像头全天挂着,路由器后台看流量,只有在打开网页看监控的时候才会出现持续带宽占用,这点非常友好。
另一个让它胜出的点是配置格式。go2rtc的配置直接用YAML定义流名称和源地址,支持通配符、模板变量,还能通过API动态添加流。比如你有一台NVR,下面挂了几十路摄像头,go2rtc可以直接对接NVR的RTSP端口,也可以用
[name]:[password]@[ip]
的格式统一拼接地址,不用每路都手写一行完整URL。
1.3 选型时的对比清单
| 方案 | 部署复杂度 | 浏览器播放支持 | 延迟表现 | 配置管理 |
|---|---|---|---|---|
| go2rtc | 低(单容器/单二进制) | 原生WebRTC+HLS+MSE | 极低(百毫秒级) | YAML+API,动态管理 |
| Mediamtx | 低 | 需配合HLS或WebRTC相关配置 | 中低 | 配置较繁琐,适合轻量 |
| ZLMediaKit | 高 | 需配合前端播放器 | 低 | 接入复杂,运维成本高 |
| 传统NVR/平台 | 取决于硬件 | 基本靠专用App或插件 | 中 | 封闭生态,扩展差 |
如果你的需求是“我有一堆杂牌摄像头,想在一个网页里全部实时看到,还希望接入Home Assistant之类的智能家居中枢”,go2rtc就是性价比最高的一条路。如果只是单纯要把一路RTSP转成HLS推送,那Mediamtx就够了,没必要上go2rtc。选型的本质是先分清自己的核心需求是“协议转换”还是“规模化管理”,go2rtc两者兼备,但它的优势场景明显偏向后者。
2. Docker部署go2rtc:从安装到Web界面
2.1 安装前的准备:几个必须要确认的点
部署之前先确认三件事:Docker环境是否正常、端口是否可用、以及摄像头是否支持RTSP或ONVIF。
Docker环境不多说,Linux上用包管理器装docker-ce,Windows上装Docker Desktop,需要确保能正常拉取镜像。端口方面,go2rtc默认用
1984
端口同时提供Web管理界面和API,WebRTC还需要一组UDP端口用于媒体传输。这里有个容易踩的坑:很多人只改了Web端口,忘了WebRTC端口也需要映射到宿主机,结果网页能看到画面列表,但一点“播放”就卡住转圈。
摄像头那边,尽量先去摄像头管理后台把RTSP功能打开。海康、大华、TP-LINK这类主流牌子一般都有RTSP开关,有的需要设置RTSP认证账号密码。如果你的摄像头不支持RTSP但支持ONVIF,go2rtc也能通过ONVIF自动发现设备并拉流。注意ONVIF只是“设备发现和管理协议”,真正的视频流还是走RTSP,所以设备至少要能提供RTSP流。
2.2 docker run快速部署
官方镜像名是
alexxit/go2rtc
,带平台标签,x86和ARM架构都能跑。我最开始是在一台x86小主机上跑的,部署命令如下:
docker run -d \
--name go2rtc \
--restart unless-stopped \
-p 1984:1984 \
-p 50000-50010:50000-50010/udp \
-v /opt/go2rtc/go2rtc.yaml:/config/go2rtc.yaml \
alexxit/go2rtc:latest
这里给几个参数解释:
-
-p 1984:1984:Web界面和API端口,浏览器访问http://宿主机IP:1984就是管理界面。 -
-p 50000-50010:50000-50010/udp:WebRTC媒体传输端口范围。这个范围不是固定的,可以自己定,但一定要和后面容器内配置保持一致。如果防火墙开着,记得同时放行这段UDP端口。 -
-v /opt/go2rtc/go2rtc.yaml:/config/go2rtc.yaml:把配置文件挂载出来。挂载的好处是改配置不用进容器,直接编辑宿主机文件,然后重启容器即可生效。
启动之后,先浏览器打开
http://192.168.1.100:1984
,看到go2rtc自带的“Streams”页面就说明部署成功了。页面上现在应该空空如也,因为还没添加任何流。
2.3 docker compose方式:适合一次配置长期复用
如果机器上同时跑了很多容器,我更推荐用docker compose管理。下面是我实际在用的
docker-compose.yml
:
version: "3.8"
services:
go2rtc:
image: alexxit/go2rtc:latest
container_name: go2rtc
restart: unless-stopped
network_mode: host
volumes:
- ./go2rtc.yaml:/config/go2rtc.yaml
注意我这儿用了
network_mode: host
,也就是主机网络模式。这个改动很重要:go2rtc需要动态创建WebRTC端口,如果用bridge模式,得把所有可能的UDP端口都映射出来,容易漏;host模式下容器直接共享宿主机网络,端口不用映射,WebRTC端口也能随意分配,省心很多。代价是容器不再有独立网络栈,端口占用直接打在宿主机上,适合一台机器只跑一个实例的场景。如果你有多个容器需要做端口隔离,或者跑在群晖这类NAS的Docker里,还是老老实实用bridge模式加端口映射。
2.4 配置文件格式:go2rtc.yaml从零开始
go2rtc的配置是一个YAML文件,最核心的
streams
段定义所有摄像头流。先给个最简可用的示例:
log:
level: info
api:
listen: ":1984"
webrtc:
listen: ":50000"
streams:
bedroom:
- rtsp://admin:password@192.168.1.20:554/Streaming/Channels/101
living_room:
- rtsp://admin:password@192.168.1.21:554/cam/realmonitor?channel=1&subtype=0
每个流名称底下跟一个或多个源地址,多个源可以写成一串列表,go2rtc会自动做故障切换或负载均衡。比如你有一台摄像头支持主码流和子码流两个地址,可以配两个源,让go2rtc在播放时根据客户端能力选择,或者主码流断了自动切子码流。
2.5 在Home Assistant里直接使用go2rtc
如果你的智能家居中枢是Home Assistant,go2rtc可以无缝对接。在HA的配置里加入go2rtc的地址,HA就能把go2rtc里的每一路流直接识别为摄像头实体,然后你就能在HA的仪表盘里看到实时画面、录制、人脸识别都可以接。我在配置文件中加了一行:
homeassistant:
url: "http://192.168.1.100:8123"
token: "你的长期访问令牌"
这让go2rtc主动连接HA,功能上等价于把go2rtc当作HA的“摄像头网关”。如果你不想让go2rtc主动连HA,也可以反过来在HA的
configuration.yaml
里用
camera
和
stream
平台指向go2rtc的API地址。
3. 多协议摄像头接入实操:从RTSP到树莓派
3.1 RTSP直连:海康/大华/TP-LINK的通用配置方法
绝大多数IP摄像头都支持RTSP协议,只是URL路径各家不一样。海康威视常见的RTSP地址格式是:
rtsp://用户名:密码@IP:554/Streaming/Channels/101
其中
101
表示第1通道的主码流,
102
是第1通道的子码流。大华的RTSP地址一般是:
rtsp://用户名:密码@IP:554/cam/realmonitor?channel=1&subtype=0
channel
是通道号,
subtype=0
主码流,
subtype=1
子码流。TP-LINK的较新固件地址类似
rtsp://用户名:密码@IP:554/stream1
。
在go2rtc的
streams
里加流时,建议不要直接写明文密码。YAML配置里可以用环境变量替换,比如:
streams:
front_door:
- rtsp://${CAM_USER}:${CAM_PASS}@192.168.1.20:554/Streaming/Channels/101
然后在启动容器时通过
-e CAM_USER=admin -e CAM_PASS=xxx
传入环境变量。这样配置文件即使被传到网上,也不会泄露摄像头密码。
接入之后,在go2rtc网页的Streams页面,点击流名称下的“play”按钮,浏览器会通过WebRTC直接播放,此时观察延迟,走局域网的RTSP源一般延迟在300毫秒以内,这是普通HLS方案很难做到的。
3.2 ONVIF自动发现:适合“不知道地址”的摄像头
有些摄像头是二手收来的,账号密码不知道,或者压根不清楚厂商默认的RTSP路径。go2rtc支持ONVIF自动发现和拉流,你只需要提供摄像头的IP和ONVIF账号密码,go2rtc就能自动探测设备的媒体地址。
配置方式很简单:
streams:
new_cam:
- onvif:admin:password@192.168.1.30
go2rtc会去设备支持的ONVIF服务里查找Media2或Media1接口,拿到Profile信息后组装RTSP地址。这个功能我实际试过几次,成功率很高,不过前提是设备确实开启了ONVIF服务,并且摄像头固件没那么魔改。
如果你不知道ONVIF账号密码,可以先去摄像头Web管理后台重置,或者查出厂默认账号。大部分摄像头默认的ONVIF账号和Web登录账号是同一套,个别设备需要单独开启“ONVIF用户”开关。
3.3 树莓派上跑go2rtc:把OV5647摄像头模块变成网络摄像头
树莓派加OV5647摄像头模块是很多折腾玩家的标配组合,但树莓派自带摄像头输出的是CSI接口信号,不是RTSP流。想接入go2rtc,得先在树莓派上跑一个RTSP推流服务,把摄像头画面包装成RTSP协议。
我的做法是用树莓派上的
libcamera-vid
把CSI摄像头数据流转成H.264,然后通过
mediamtx
(或者go2rtc自带的
rtsp
模块)把流转成RTSP服务。实测下来,树莓派4B上跑一条
libcamera-vid
命令就能稳定输出主流RTSP:
libcamera-vid -t 0 --codec h264 --width 1280 --height 720 --framerate 15 --bitrate 1500000 -o - | ffmpeg -fflags nobuffer -f h264 -i - -c:v copy -f rtsp rtsp://localhost:8554/pi
这里
ffmpeg
的作用是把stdin输入的H.264裸流封转成RTSP推给Mediamtx的8554端口。树莓派上跑Mediamtx也很轻,实测CPU占用在20%左右,不影响其他任务。
然后在go2rtc的配置里添加:
streams:
raspberry_pi:
- rtsp://192.168.1.31:8554/pi
这样就实现了“树莓派摄像头 -> RTSP -> go2rtc -> 浏览器WebRTC播放”的全链路。这套方案比直接买一个网络摄像头便宜很多,代价是要折腾一下系统服务和开机自启,我用systemd服务把上面那条命令行封装成开机自动运行,一直很稳定。
3.4 USB摄像头和v4l2设备的接入思路
普通USB摄像头,或者像ESP32-S3摄像头这类自带UVC输出的设备,常见做法也一样:先借助v4l2抓帧,封装成RTSP推给go2rtc。关键是要保证长时间稳定推流,USB摄像头和树莓派官方摄像头不同,有的会在低光照条件下自动调整帧率,导致推流抖动。
我自己用OBS加虚拟摄像头插件做过一个“电脑屏幕流”的场景:开个OBS虚拟摄像头,然后用OBS的RTSP推流功能推到go2rtc,再把go2rtc接到Home Assistant。结果我发现,电脑性能不好时推流会掉帧,但go2rtc对掉帧容忍度很高,播放端只是稍微卡一下,不会整个断流。
3.5 萤石/小米这类云摄像头如何接入
很多消费级摄像头,比如萤石、小米的云台版,默认不支持RTSP,它们优先走自己的云平台。想接入go2rtc,第一件事是去摄像头的App里打开“局域网RTSP”或“开发者模式”。
小米摄像头在米家App里打开“局域网RTSP”后,会显示RTSP地址和账号密码,地址一般是
rtsp://用户名:密码@IP:554/stream1
。萤石则需要设备开启“RTSP认证”后,使用SDK或者直接通过
rtsp://用户名:密码@IP:554/h264/ch1/main/av_stream
之类的路径。
麻烦的是这些消费级设备时不时会通过固件更新调整RTSP行为,可能出现昨天能拉流今天断流的情况。我的经验是,这类摄像头只适合做“非关键”监控,比如看猫主子、看快递,不适合做安防关键路径。关键路径上,老老实实用支持标准RTSP/ONVIF的摄像头更靠谱。
3.6 多路并发推流:go2rtc接到NVR或录像机
如果你已经有海康录像机(NVR),录像机的RTSP端口通常以
554
对外提供服务。go2rtc可以直接把NVR当作一个大的RTSP源来拉,比如:
streams:
nvr_camera1:
- rtsp://admin:password@192.168.1.240:554/Streaming/Channels/101
nvr_camera2:
- rtsp://admin:password@192.168.1.240:554/Streaming/Channels/201
这里
101
、
201
分别是NVR第一、第二通道。有个细节:NVR的码流路径不一定每个牌子都一样,但大部分兼容海康的通用路径规则。如果拉不通,去NVR的Web管理后台,找到“网络服务 -> 平台接入”或“RTSP配置”里的默认地址模板,通常能照抄。
如果你只是想统一用go2rtc做在线播放层,录像仍然让NVR自己干,也完全没问题。go2rtc不负责录像,它只做转发和协议转换。录像持久化建议还是交给NVR或者另外挂一个Frigate之类的NVR软件。
4. 常见问题与排查技巧实录
4.1 网页能看列表但播放黑屏/转圈
这是最普遍的坑。播放黑屏九成是WebRTC的UDP端口没有正确映射或防火墙没放行。我排查的固定套路是:
-
先确认容器日志里有没有
webrtc: listen on :50000这类信息。 -
在宿主机上测试UDP端口是否通:
nc -u -z 宿主机IP 50000-50010。不通就查防火墙。 - 确认浏览器是否支持WebRTC。Chrome、Edge、Firefox都没问题,Safari老版本可能对WebRTC支持不完整。
- 如果用了Nginx之类的反代,记得配置HTTP/2和WebSocket支持,WebRTC的信令走HTTPS和WS,不能用普通HTTP反代替代。
4.2 摄像头连接“闪断”
症状是画面能出,但过一会儿就断,然后自动重连。排查下来最常见的原因是摄像头端最大连接数限制。很多家用摄像头限制同时只能有2路或4路RTSP连接,如果有NVR、手机App、go2rtc同时连接,就会触发上限。
解决思路也很直接:
- 给go2rtc配置子码流拉流,而不是主码流。子码流码率低,对连接数和带宽压力都小,go2rtc负责把子码流转发给客户端,主码流留给NVR或者录像用途。
-
开启go2rtc的
rtsp.transport设置。有的摄像头对TCP/UDP传输方式敏感,这边配置成tcp可以降低半开连接导致的断流:
streams:
main_cam:
- rtsp_transport: tcp
url: rtsp://admin:password@192.168.1.20:554/Streaming/Channels/101
4.3 浏览器里没有音频
go2rtc会按需转码音频,但有些浏览器对AAC、PCMU等编码支持有限。摄像头原始音频如果是G.711,浏览器不一定直接支持,go2rtc会自动做音频转码为AAC或Opus。
如果发现“有画面没声音”,先确认摄像头那边打开了音频开关——很多摄像头默认连音频采集都是关闭的。然后在go2rtc的流详情里查看音频媒体信息,确认是否有音频轨。如果确认有但播放无声,试试在流配置里强制指定音频编码:
streams:
office_cam:
- ffmpeg:rtsp://admin:password@192.168.1.40:554/Streaming/Channels/101#audio=aac
这个
ffmpeg:
前缀是go2rtc内置的FFmpeg转码模块,可以把源流的音频转成AAC再输出。注意转码会增加CPU负载,但单路音频转码基本可以忽略。
4.4 播放画面是“花屏”或者马赛克
这个通常不是go2rtc的问题,更多是摄像头码流传输过程中丢包。排查顺序是:
- 看摄像头到go2rtc之间是有线还是Wi-Fi,Wi-Fi容易出现码流不稳定。
-
在go2rtc日志里搜索
lost packets或discard,如果有,把RTSP传输改成TCP。 - 有些老摄像头主码流是MJPEG或者H.265,浏览器不支持会花屏或黑屏。go2rtc支持转码,但转H.265到H.264会消耗CPU,建议直接用子码流(通常是H.264)。
4.5 延迟越来越高
go2rtc默认WebRTC播放延迟很低,但如果中间走了HLS,延迟就会高起来。HLS通常有几秒到十几秒的延迟,这是切片机制决定的,不是故障。
如果想把延迟控制在1秒内,优先用WebRTC播放;如果客户端是iPhone的Safari,Safari对WebRTC支持没那么完善,可以改用MSE模式,go2rtc会通过Media Source Extensions提供接近WebRTC的延迟体验。
4.6 go2rtc容器日志刷屏,都是“connection refused”
日志高频出现
connection refused
基本就是配置里的RTSP地址不对、端口不通、或账号密码错了。拿配置里的URL单独在宿主机上用FFmpeg拉一下:
ffmpeg -i rtsp://xxx
,能通就说明源没问题,不通就一个个排查IP、端口、路径、协议。
4.7 内存泄漏还是普通缓存增长?
go2rtc连续跑一周,内存占用有波动是正常的,因为要缓冲媒体数据。但如果持续攀升不回落,看下是不是有播放会话没断开。可以调用它的API接口查看活跃会话数:
curl http://localhost:1984/api/streams
返回的JSON里有
clients
字段,如果长时间不为0且有异常IP,检查是不是有人或某个自动化脚本一直挂着一个没释放的连接。正常使用下,go2rtc的常驻内存一般稳定在100~200MB左右,按需拉流模式下空闲时内存会降下来。
5. 进阶玩法:go2rtc还能干什么
5.1 把go2rtc变成“推流分发枢纽”
除了从摄像头拉流,go2rtc也能直接接流再转推给其他地方。比如把一路RTSP同时推给HLS切片器、WebRTC客户以及另一个NVR。这在做直播或者跨平台分发时很好用。
YAML里的写法大致是:
streams:
mixed:
- rtsp://192.168.1.20:554/Streaming/Channels/101
- ffmpeg:rtsp://192.168.1.40:554/Streaming/Channels/201#video=copy#audio=copy
两路源放在同一个流名下,go2rtc会把它们合并成一个聚合流输出。这种“混流”一般需要借助FFmpeg,具体编码参数按需求调。
5.2 接入动态发现,自动添加海量摄像头
go2rtc支持从外部API动态管理流,你可以用脚本扫描局域网的摄像头,然后调用
/api/streams
接口把发现到的新设备自动加入配置。爬虫式扫描可以用Nmap先找出开放554端口的设备,再逐个用ONVIF探测,把拿到的媒体地址POST到go2rtc的API。
这样管理几十路摄像头的场景就轻松很多,不用每加一台摄像头都去手改YAML然后重启容器。
5.3 配合Home Assistant做“有人检测”
如果想让摄像头流具备简单的人形检测能力,可以搭配Frigate使用。Frigate负责从go2rtc拉取RTSP进行AI识别,识别结果回传给Home Assistant触发自动化。go2rtc在这条链路里做的事情只是“提供一个统一的、稳定的RTSP源”,但正是这个统一的源,让多路摄像头接入Frigate时不用每个都单独配地址和密码,管理成本大幅下降。
5.4 简易录像方案
go2rtc本身不负责录像,但它可以把任意一路流转推到支持录像的服务。组合组常见的是:go2rtc转推RTSP给Mediamtx,Mediamtx按天切片存储文件;或者直接用go2rtc的FFmpeg模块定时落盘。
这里我更推荐让“录像”这种事交给专门的NVR软件做,go2rtc专注做它擅长的“连接”和“转化”。架构上职责分离,后续排查问题也更有头绪。
6. 实操体验总结与经验建议
6.1 一些部署上的“卫生习惯”
我在多次部署和重装中总结出几个能避免很多破事的小习惯:
- 挂载配置时,先用一个临时配置启动容器确认能正常读取,再替换成正式配置,避免一次写错整个配置导致容器启动失败。
- 配置文件里不要写明文密码,用环境变量注入,至少能在配置泄漏时少一层直接伤害。
- 给Web界面加个访问控制,最简单的是在前面挂一层带基础认证的反代。go2rtc本身就设计成内网服务,裸奔在公网上风险太大,容易被扫描器拿去当跳板。
- 升级go2rtc之前先备份YAML和容器配置,虽然新版一般向后兼容,但个别大版本对配置的字段有过调整。
6.2 我最满意的一个使用场景
我现在家里有三路摄像头:海康的门口机、大华的庭院机、树莓派做的阳台摄像头。它们三个的观看方式在以前是三个App,现在全部接到了go2rtc,浏览器打开一个页面就能同时看到三路实时画面。另外我用Home Assistant做了个简单联动——树莓派摄像头检测到有人移动,自动把对应画面推送到手机通知。
这套方案最大的价值不是某个单独的功能,而是把所有东西统一到了一起。摄像头厂商的App一更新就可能改变交互逻辑,但go2rtc只关心你出不出RTSP流,只要底层协议不变,上层怎么折腾都不影响我的统一入口。
以后如果再添摄像头,我的第一反应也不再是“这牌子能不能用”,而是看它支不支持RTSP或ONVIF。只要支持,go2rtc就能接;不支持,我就用树莓派加个USB摄像头自己造一个。这种“不被厂商绑定”的自由度,才是这套方案让我最上瘾的地方。
更多推荐

所有评论(0)