手机里为了几个摄像头装了四五个 App,客厅一个监控用专用客户端,公司那台海康球机又要单独装插件,光是把画面统一起来这件事就足够让人头疼了。go2rtc 就是专门解决这类问题的开源流媒体工具,它把 RTSP、RTMP、ONVIF、WebRTC、HLS、MJPEG 这些协议集于一身,能把不同品牌、不同协议的摄像头统一接入,再以你需要的协议转发出去。我推荐用 Docker 来部署它,不用折腾依赖和编译,一条命令就能拉起一个轻量的多协议流媒体平台。这篇文章写给那些手里有摄像头、又不想被厂商 App 绑架的人,读完你可以把家里或办公室的摄像头全部接进同一个平台,用浏览器直接看实时画面。

1. 为什么是 go2rtc 而不是自己做转码

1.1 多协议转换才是核心痛点

摄像头厂商最擅长的事,是让你用他们自己的 App 看画面。但实际监控场景里,设备可能是不同时期买的:客厅一个品牌,门口一个品牌,仓库里还有几台别人淘汰下来的旧机器。每个品牌都有自己的客户端,有的甚至只支持 IE 浏览器加 ActiveX 插件,换台电脑就没法看,这种体验极其难受。

流媒体协议也是个问题。摄像头向外输出通常走 RTSP,这是安防行业的事实标准,但具体到 URL 路径,海康有海康的写法,大华有大华的写法。而到了前端播放环节,浏览器原生又不支持 RTSP,你要么装插件,要么先把 RTSP 转成 HLS 或 WebRTC 再播放。这个“转换”步骤,就是 go2rtc 存在的意义。

go2rtc 本质上是一个中间人。它把摄像头的 RTSP、RTMP 流拉过来,统一管理,再按客户端需要的协议吐出去。浏览器想看实时低延迟画面,你用 WebRTC 输出;手机浏览器要兼容性好的地址,你给它 HLS;老系统里嵌个网页,你用 MJPEG。后端再多协议、再多品牌差异,对前端只暴露一个 go2rtc 地址,开发和管理成本都直线下降。

1.2 go2rtc 和传统方案(FFmpeg、Nginx-RTMP)有什么不一样

接触过流媒体的朋友应该都试过 FFmpeg 或 Nginx-RTMP 模块。FFmpeg 转码能力确实强,但把 FFmpeg 变成长期稳定的服务,是一件很麻烦的事:进程掉了谁拉起来?摄像头断线了怎么自动重连?多路流如何统一管理?这些都需要你自己写脚本、写守护进程,维护成本并不低。

Nginx-RTMP 模块则是另一条路,它更擅长做 RTMP 直播分发,而不是把 RTSP 转换成浏览器能看的格式。要用它搭一个摄像头多协议平台,你需要自己处理协议转换、鉴权、前端播放器适配,配置写起来很长,调试也不直观。

go2rtc 把这些问题在原生层面解决了。它用 Go 语言写成,编译出来就是单个可执行文件,启动快、内存占用低,内部自带自动重连、流状态管理、Web 管理界面和多协议对外输出能力。我不用写一行业务代码,只在配置文件里把摄像头地址列进去,它就能把整件事跑起来。对做集成的人来说,这节约的不是一两个小时,而是好几天。

1.3 为什么用 Docker 来部署

go2rtc 提供了编译好的二进制文件,直接下载也能跑。但如果目标机器是群晖 NAS、树莓派、软路由或一台经常装软件的家庭服务器,我强烈建议走 Docker。原因很现实:二进制文件放在系统里,时间久了容易跟其他软件的依赖冲突;卸载也卸不干净,升级还得手动替换文件。

Docker 的优势是环境隔离和声明式管理。镜像拉下来,容器起起来,所有依赖都在镜像里,你不用关心宿主机装了什么乱七八糟的环境。升级时换个镜像 tag 重新 up 一下就行,出问题还能一键回滚到旧版本。跟 docker-compose 配合,配置文件、数据目录、启动参数都固化成文本,换台机器直接复制过去就能复现。

另一个实际好处是开机自启。Docker 容器通过 restart: unless-stopped 策略,宿主重启后容器自动拉起来,摄像头平台这种需要长时间挂机的服务,这一点非常重要。再加上 Docker 日志统一走 docker logs ,排查问题也比翻 systemd 日志或直接看屏幕输出方便得多。

2. Docker 部署 go2rtc 的完整步骤

2.1 出发前的环境准备

部署之前先把基础环境确认清楚。机器上需要 Docker,版本建议 20.10 以上,用 docker -v 可以快速确认。如果还没有安装,不同系统的安装方式差异较大,网上资料也很多,这里就不展开了。我假设你已经有了一台能跑 Docker 的主机,无论是 Linux、NAS 还是 Windows Docker Desktop,思路都一样。

接下来规划目录。我习惯把 go2rtc 的相关文件集中放在 /opt/go2rtc 下,里面建一个 go2rtc.yaml 作为配置文件,再建一个 data 目录留给后续可能用到的临时数据。目录结构清晰了,后面迁移和备份都很方便。

还有一个关键选择:网络模式。go2rtc 要跟局域网里的摄像头通信,默认 bridge 网络也能用,但我更推荐直接用 host 网络。原因是 go2rtc 的 WebRTC 功能依赖 UDP 端口,bridge 模式下端口映射会带来额外的 NAT 层,容易导致跨网段或跨设备播放时连不通。host 网络下容器直接共享宿主机网络栈,各种协议通信都少一层中转。

2.2 一条命令先跑起来:docker run 参数逐个说

先用一条 docker run 把服务跑起来,快速验证效果。

docker run -d \
  --name go2rtc \
  --restart unless-stopped \
  -p 1984:1984 \
  -p 8554:8554 \
  -v /opt/go2rtc/go2rtc.yaml:/config/go2rtc.yaml \
  alexxit/go2rtc:latest

这条命令里每个参数都有讲究。 -p 1984:1984 暴露的是 go2rtc 的 Web 管理界面和 API 端口,浏览器访问 http://你的服务器IP:1984 就是管理后台。 -p 8554:8554 暴露的是 RTSP 对外服务端口,你在播放器里拉流时,走的地址就是 rtsp://你的服务器IP:8554/流名称 。

-v /opt/go2rtc/go2rtc.yaml:/config/go2rtc.yaml 这行尤其重要。go2rtc 容器默认从 /config/go2rtc.yaml 读取配置文件,如果不把宿主机文件挂载进去,你后续改配置就得进入容器操作,容器一升级配置就全没了。所以配置文件从第一天起就必须放在宿主机上。

启动完成后,先访问 http://你的服务器IP:1984 ,看到管理界面就说明服务已经跑起来了。这时候界面里还没有任何摄像头,下一步就是把摄像头地址填进配置文件。

2.3 认真跑服务:用 docker-compose 管理

docker run 适合快速验证,但要长期维护,我建议改用 docker-compose,把配置固化成文件。我在 /opt/go2rtc/docker-compose.yml 里写的就是这样一份配置:

version: "3.8"

services:
  go2rtc:
    image: alexxit/go2rtc:latest
    container_name: go2rtc
    restart: unless-stopped
    network_mode: host
    environment:
      - TZ=Asia/Shanghai
    volumes:
      - /opt/go2rtc/go2rtc.yaml:/config/go2rtc.yaml
      - /opt/go2rtc/data:/data

这里我把网络模式改成了 network_mode: host ,所以不再写 ports 映射。用 Compose 管理的好处是重启服务只需 docker compose restart ,改造型后 docker compose up -d ,查看日志用 docker compose logs -f ,一套命令全部搞定。

TZ=Asia/Shanghai 是时区设置,不加上这个,容器里记录的日志时间会差 8 小时,排查问题时会很困惑。 /data 目录也会用到,比如某些协议临时缓存或后续配合录像任务使用。

启动命令也很简单:

cd /opt/go2rtc
docker compose up -d

看到 Started 字样,服务就起来了。之后的日常维护基本就是改配置、重启容器这两个操作。

3. 把摄像头接进来:多协议接入实战

3.1 摄像头 RTSP URL 规律

不同品牌摄像头的 RTSP 地址格式差异很大,我整理几个最常见的品牌。注意密码里如果包含 @ 、 : 或 / ,需要进行 URL 转义,这是个非常容易踩的坑。

品牌 RTSP 地址规则
海康威视 Hikvision rtsp://用户名:密码@IP:554/Streaming/Channels/101
大华 Dahua rtsp://用户名:密码@IP:554/cam/realmonitor?channel=1&subtype=0
TP-LINK rtsp://用户名:密码@IP:554/stream1
其他品牌 可通过 ONVIF 工具扫描获取真实流地址

海康的路径里 101 代表主码流第一通道,102 是子码流,想用低码流预览就把最后两位改成 02。大华的 subtype=0 是主码流,改成 1 就是子码流。TP-LINK 不同型号差别比较大,实际以摄像头页面显示的为主。

拿到 RTSP 地址后,打开 go2rtc.yaml ,添加 streams 配置:

streams:
  front_door: rtsp://admin:your_password@192.168.1.64:554/Streaming/Channels/101
  backyard: rtsp://admin:your_password@192.168.1.67:554/cam/realmonitor?channel=1&subtype=0

这里 front_door 是自定义的流名称,等会儿访问时用得到。文件名保存后,执行 docker compose restart go2rtc 重启服务。再次打开管理界面,应该能看到对应的流卡片,点击即可预览画面。

3.2 ONVIF 自动发现和现场踩坑

如果不想一个个去猜 RTSP URL,可以先用 ONVIF 发现。ONVIF 是安防设备的通用标准协议,多数现代摄像头都支持。go2rtc 内置了对 ONVIF 的支持,在管理界面里可以扫描局域网内的 ONVIF 设备,省去手工折腾地址的麻烦。

实际操作时有几个问题需要注意。第一,摄像头和运行 go2rtc 的主机必须处于同一个局域网网段,跨网段 ONVIF 广播经常扫不到。第二,ONVIF 需要摄像头开启相关权限,有些摄像头的 ONVIF 功能默认是关的,要去 Web 管理页面里打开。第三,如果摄像头没有激活或者处于初始密码状态,ONVIF 也连不上,这时候需要先用厂商工具把摄像头激活并设置好密码。

ONVIF 扫不到时,我常用的备选方案是用 ONVIF Device Tool 这类桌面工具,单独设置摄像头的 ONVIF 账号,再回来手动填 RTSP。这个方法慢一点,但确定性强,不会在“为什么扫不到”上死磕。

3.3 浏览器播放:WebRTC、HLS、MJPEG 怎么选

摄像头接进来之后,最大的问题就是浏览器怎么播放。RTSP 浏览器不认,必须转成浏览器能理解的协议,go2rtc 一次给了好几种选择。

输出协议 延迟表现 兼容性 适用场景
WebRTC 几百毫秒 桌面浏览器原生支持,需要 UDP 网络通畅 局域网实时预览、对延迟敏感的场景
LL-HLS 1到3秒 iOS、Android、浏览器都支持 跨设备通用播放、有移动观看需求
HLS 5到15秒 兼容性最好 对延迟不敏感的场景、公网分享
MJPEG 画面可见但带宽占用高 任何浏览器、甚至 img 标签都能看 嵌入式页面、老系统集成

局域网里我优先用 WebRTC,它的延迟低到让人几乎感觉不到,适合监控场景。操作方式也很简单,在 go2rtc 管理界面里点击流名称,页面会直接尝试用 WebRTC 拉流播放,不需要额外安装任何播放器插件。

如果把服务暴露到公网,WebRTC 的 UDP 穿透成功率会明显下降,这时候就退回到 LL-HLS 或 HLS。虽然延迟高一些,但胜在稳定,浏览器直接打开就能看。

4. 常见问题与排查技巧实录

4.1 画面黑屏或一直转圈

接入摄像头后最常遇到的情况,是管理界面里流显示在线,但点开一片黑。按我的排查经验,先看流状态,再检查编码格式。

很多摄像头默认输出 H.265 编码,而 Chrome、Edge 这些浏览器对 H.265 的支持一直很差。go2rtc 走的是“尽量不转码”的思路,所以流是通的,但页面解不了码,表现就是黑屏或转圈。解决方式有两个:一是到摄像头后台把编码改成 H.264,这是最省事的;二是如果不想改摄像头设置,这时就需要引入 FFmpeg 转码了,让 go2rtc 用 FFmpeg 拉流,先把 H.265 解码再编码成 H.264 发给浏览器。

还有一种常见情况是 RTSP 地址里的密码写错了。密码出错时流状态会显示 disconnect,日志里会有认证失败的记录。检查时重点看密码里有没有特殊字符, @ 和 : 这两个字符最常见,建议对密码做 URL 编码再填入。

4.2 延迟高、画面卡顿的调优顺序

延迟问题的排查顺序很重要,我一般按照“输出协议、摄像头参数、网络条件”三步来走。

第一步确认输出协议是不是选错了。HLS 默认延迟 5 秒以上是正常的,你不能拿它做实时操作。想低延迟先换 WebRTC,同局域网下基本能做到接近实时。如果必须跨公网看,选 LL-HLS 比传统 HLS 好不少。

第二步看摄像头码流设置。主码流默认动辄 4Mbps 甚至 8Mbps,对于本地看没问题,但如果访问端网络一般,就会卡。我习惯给 go2rtc 同时接入主码流和子码流,预览用子码流,需要看细节时再切主码流。摄像头后台的帧率和 GOP 设置也会影响延迟,把帧率固定成 15 到 25,GOP 尽量小一点,画面会更流畅。

第三步检查 Docker 网络模式。如果用了 bridge 网络加端口映射,WebRTC 的 UDP 包要通过 Docker 的 NAT 转发,延迟和成功率都会受影响。遇到卡顿或连不上,先把容器改成 host 网络试试,能解决不少问题。

4.3 Docker 部署的几个坑

用 Docker 跑 go2rtc 本身不复杂,但有些细节不注意会让你白忙活半天。第一个坑是配置文件挂载权限。宿主机上 go2rtc.yaml 的权限不对,容器里读不了,服务会一直重启。遇到容器反复重启,第一条命令永远是 docker logs go2rtc ,看日志比瞎猜快得多。

第二个坑是 host 网络模式下写端口映射。Compose 文件里如果同时写了 network_mode: host 和 ports ,映射会被忽略,但并不会报错。新手可能以为端口没暴露,折腾半天,其实是网络模式的问题。host 模式下端口直接监听得宿主机上,本来就不需要映射。

第三个坑是镜像版本漂移。我一直用 latest tag,图省事,但 go2rtc 迭代很快,某次升级后配置格式可能有变化。长期稳定运行的话,建议固定一个版本号,比如 alexxit/go2rtc:1.9.1 ,确认没问题了再手动升级。

5. 进阶玩法:接入 HA、录像、访问控制

5.1 把 go2rtc 变成 Home Assistant 的摄像头源

如果你的智能家居平台是 Home Assistant,go2rtc 几乎是一个必装的组件。HA 里接入摄像头的方式有多种,但不少摄像头协议在 HA 原生支持上有各种限制,而 go2rtc 往往能把问题绕过去。

常规做法是在 HA 里通过 generic camera 平台,把 go2rtc 输出的 HLS 或 MJPEG 地址作为摄像头源。你只需要在 go2rtc 里把摄像头流管理好,HA 侧填一个拼接好的 URL 就行。这样后续如果摄像头厂商改了协议,或者增加新摄像头,都只需要在 go2rtc 配置文件里改,HA 里的实体完全不用动。

go2rtc 和 HA 的配合还有一个额外好处,就是可以利用 HA 的自动化能力。比如检测到有人经过时,HA 自动调用 go2rtc 的 API 取一张当前帧,或者把视频片段推到通知里,这些场景在纯硬件监控里想都不敢想。

5.2 录像和定时保存

go2rtc 本身负责流媒体分发,不做录像,但你可以用它提供的稳定 RTSP 输出配合 FFmpeg 完成录像任务。我的做法是让 go2rtc 统一管理摄像头,然后 FFmpeg 从 go2rtc 拉流落盘。

ffmpeg -i "rtsp://你的服务器IP:8554/front_door" \
  -c copy \
  -f segment \
  -segment_time 3600 \
  -strftime 1 \
  "/opt/go2rtc/recordings/front_door_%Y%m%d_%H%M%S.mp4"

这里 -c copy 是不重新编码,直接复制流,CPU 占用极低。 -segment_time 3600 表示每小时切一个文件, -strftime 1 让文件名按时间自动生成。把这个命令放进计划任务或 systemd timer,就是一套简单的循环录像方案。

如果摄像头本身支持 SD 卡或 NVR 录像,可以保留原有方案,go2rtc 主要负责实时观看和多协议分发。但如果摄像头分布在多个品牌、多个网段,用 go2rtc 统一拉流再录像,管理起来会舒服很多。

5.3 加一层访问控制

把摄像头流接入 go2rtc 后,默认情况下只要知道地址就能看,这在局域网里问题不大,但如果有公网访问需求,就必须处理访问控制问题,尤其是隐私场景,不能裸奔。

go2rtc 的配置里支持启用账号认证,可以在 Web 管理界面和流媒体服务上设置用户名密码。不同版本的字段名略有差异,配置页面和官方文档会标注清楚,配置好之后重启容器即可生效。公网访问时,优先走带密码的 HLS 地址,WebRTC 暴露的 UDP 端口在公网环境下很难做到安全可控,不建议直接开放。

如果有多路流,也可以考虑单独在网关层做访问限制,比如只允许特定 IP 段访问,或者配合 HTTPS 加密传输。总之,凡是涉及摄像头的服务,第一次上线前就把认证打开,这是我踩过若干次坑之后养成的习惯。

我自己长期用下来的体会是,go2rtc 解决的不只是“看画面”这个点,而是把各种摄像头、各种协议的碎片化问题收拢成一个平台。用 Docker 部署之后,升级、备份、迁移都变得很干净,这套组合在各类小型监控项目里已经非常成熟了。最后再分享一个小技巧:配置 go2rtc 时,给每个流起一个英文短名字,比如 front_door 、 backyard ,别贪图方便不写名字。后期无论是接 Home Assistant、写 FFmpeg 录像还是做 API 调试,短名字能省下你大量敲键盘的时间。

Logo

火山引擎视频云技术社区,是面向 AI 音视频开发者的技术交流平台。这里汇聚源自抖音、豆包等亿级 DAU 产品的 RTC、直播、点播、AI 媒体处理、音视频互动技术,提供接入指南、最佳实践、性能调优、场景案例、Demo 代码、开源项目、白皮书和 API 文档。社区汇聚官方工程师与一线开发者,为 AI 视频通话、数字人、AI 视频处理等应用的开发与落地提供技术支持。

更多推荐