go2rtc搭配Docker,统一管理RTSP/WebRTC多协议摄像头流媒体网关
家里摄像头牌子一多,事情就变得很烦:海康的用海康的App,TP-Link的用TP-Link的App,大华的又要单独装一个客户端,电脑上想同时看几路画面,得开好几个窗口。后来我接触到 go2rtc 这个项目,才算真正把这个问题解决掉。它就是一个用 Go 写的多协议流媒体网关,配合 Docker 部署,一条命令就能把 RTSP、RTMP、HLS、WebRTC 这些协议统一起来,内置网页管理界面,还能把视频流直接喂给 Home Assistant、Frigate 这些智能家居平台。这篇文章我会从 Docker 部署讲到摄像头接入、多协议播放、常见问题排查,尽量把每一步都讲透。无论你是刚接触 Docker 的新手,还是已经折腾过一阵子智能家居的老玩家,这篇应该都能帮到你。
1. 为什么偏偏选 go2rtc
1.1 它的核心能力:把视频源和播放端解耦
先理解一下 go2rtc 到底解决了什么问题。摄像头这东西,协议五花八门,很多安防设备只支持 RTSP,但浏览器播放 RTSP 又很费劲,手机 App 也未必直接支持。你可能会想:那我直接用 FFmpeg 转一下不就行了?确实可以,但 FFmpeg 是命令行工具,转出来的流单路用还行,多路管理、动态切换、按需拉流、失败自动重试这些需求,它就很难受。
go2rtc 的定位是一个中间层,它把“视频源”和“播放端”彻底解耦。视频源可以是 RTSP、RTMP、HTTP-FLV、MJPEG,甚至是某些只支持私有协议的摄像头;播放端可以是浏览器里的 WebRTC、HLS、MJPEG,也可以是 VLC 里的 RTSP、RTMP 地址,还可以是 Home Assistant 的 stream 组件。go2rtc 在你配置好之后,会自动做协议转换,你不需要关心每个播放端到底支持什么格式,只要给它一个统一的入口就行。
举个例子。我家里有一台老海康摄像头,只支持 RTSP 和 H.264,另外一台新买的支持 H.265。用 go2rtc 之后,我可以在 Web 界面里同时预览这两路画面,浏览器不需要装任何插件,因为 go2rtc 会把 H.265 的流自动转成浏览器能解码的格式。这种“屏蔽底层差异”的能力,正是它叫“gateway”的原因。
1.2 和其他方案对比,为什么它更适合家庭场景
有段时间我也折腾过别的方案,踩了不少坑,简单说一下对比结果:
| 方案 | 优点 | 缺点 | 适合人群 |
|---|---|---|---|
| FFmpeg 命令行 | 万能,几乎所有格式都能处理 | 多路管理繁琐、没有 Web UI、状态不可视 | 临时转一下流的人 |
| Nginx + RTMP 模块 | 稳定、可以对外分发 RTMP/FLV | 配置复杂、HLS 切片要自己调、调试痛苦 | 有服务器运维经验的人 |
| Zoneminder | 功能完整、有检测和录像 | 太重了,配置学习曲线陡峭 | 需要完整 NVR 方案的人 |
| Frigate | AI 检测很强、Docker 化程度高 | 本身不是流媒体网关,需要外接视频源 | 主要做检测、录像的人 |
| go2rtc | 轻量、配置简单、有 Web UI、HA/Frigate 深度兼容 | 不能替代 NVR 做长时间录像 | 想把摄像头流统一管理和分发的人 |
我自己最后选择 go2rtc,核心原因就三个:第一,镜像很小,Docker 部署一条命令搞定;第二,内置 Web 界面,所见即所得;第三,如果你玩 Home Assistant 或者 Frigate,它几乎是它们最顺手的流媒体源,官方都默认推荐用它。它不是万能的,不会做录像存储和事件检测,但“把各路摄像头协议理顺”这件事,它做得极其漂亮。
2. Docker 装好之前,先把这些坑填了
2.1 Windows 上 Docker Desktop 装不上或者启动失败怎么办
不少人是在 Windows 上玩 Docker,装 Docker Desktop 的时候经常卡壳,最常见的报错就是:
Docker Desktop failed to start because virtualization support was not detected.
看到这个不用慌,本质就是虚拟化没开或者没开全。先按
Ctrl + Shift + Esc
打开任务管理器,切到“性能”标签页,看右下角“虚拟化”这一栏是不是“已启用”。如果是“已禁用”,那就需要进 BIOS/UEFI 开启
Intel VT-x
或者
AMD-V
,具体入口每个主板不一样,但名称通常带 Virtualization、VT-x、SVM 之类的字样。开机按
Del
或
F2
进 BIOS,找到后改成 Enabled,保存重启。
如果虚拟化已经开了,但还是报错,那就是 Windows 功能没启用。去“控制面板 -> 程序 -> 启用或关闭 Windows 功能”,把这三样都勾上:
-
Hyper-V -
适用于 Linux 的 Windows 子系统 -
虚拟机平台
勾完后重启系统,再打开 Docker Desktop。还有一个坑是旧版本 WSL1 和 WSL2 混用导致 Docker 起不来,这时在管理员 PowerShell 里执行
wsl --update
、
wsl --set-default-version 2
基本能解决。实测下来,Windows 下 Docker 启动失败九成以上逃不出这几个原因。
2.2 Linux 下装 Docker 和镜像拉取慢的问题
如果你用的是 Ubuntu 或 Debian,装 Docker 最省事的方式是用官方脚本:
curl -fsSL https://get.docker.com | sh
CentOS 的话可以看官方文档装 docker-ce 源。装完记得把当前用户加入 docker 组,不然每条命令都要 sudo:
sudo usermod -aG docker $USER
newgrp docker
另一个高频问题是拉镜像特别慢。Docker Hub 在国内访问经常抽风,解决方案是给 Docker 配置镜像源。编辑
/etc/docker/daemon.json
:
{
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://dockerproxy.com"
]
}
改完之后重启 Docker:
sudo systemctl daemon-reload
sudo systemctl restart docker
如果你用的是群晖 NAS、树莓派这类 ARM 设备,记得拉镜像的时候看清楚架构。go2rtc 的官方镜像
alexxit/go2rtc
是同时发布 amd64 和 arm64 版本的,树莓派 4、群晖大部分型号都能直接跑,不需要手动编二进制。
3. Docker 部署 go2rtc,两种方式都给你
3.1 docker run 一条命令快速跑起来
验证环境没问题之后,最快的方式是一条 docker run 把它拉起来:
docker run -d \
--name go2rtc \
--restart unless-stopped \
-p 1984:1984 \
-v /opt/go2rtc/config:/config \
alexxit/go2rtc:latest
几个参数挨个说明一下:
-
-d:后台运行。 -
--name go2rtc:给容器起名字,方便后面docker logs go2rtc。 -
--restart unless-stopped:容器崩溃或服务器重启后自动拉起。这个参数很重要,不然无故退出后你都不知道它什么时候挂的。 -
-p 1984:1984:把容器里的 1984 端口映射到宿主机,这是 go2rtc 的 Web 界面和 API 端口。 -
-v /opt/go2rtc/config:/config:挂载配置目录。go2rtc 的配置文件是go2rtc.yaml,放在挂载目录里,容器内外都能改。
跑起来之后,浏览器直接访问
http://服务器IP:1984
,如果看到 go2rtc 的 Web 界面,说明部署成功了。这个界面自带播放器和配置功能,后面接入摄像头时非常直观。
3.2 用 docker compose 部署,升级更舒服
如果你觉得 docker run 参数太长,或者想固定版本方便回滚,我更推荐用 docker compose。先建目录:
mkdir -p /opt/go2rtc/config
cd /opt/go2rtc
然后创建
docker-compose.yml
:
services:
go2rtc:
image: alexxit/go2rtc:latest
container_name: go2rtc
restart: unless-stopped
ports:
- "1984:1984"
# 如果需要对外提供 RTSP 回放,解除下面这行的注释
# - "8554:8554"
volumes:
- ./config:/config
environment:
- TZ=Asia/Shanghai
启动命令:
docker compose up -d
后续版本升级也简单:
docker compose pull
docker compose up -d
顺带一提,如果你的服务器上跑了很多容器,建议在 compose 里给 go2rtc 加一个资源限制,防止它转发高码流时把宿主机内存吃满:
deploy:
resources:
limits:
memory: 512M
这里多说一句:go2rtc 的 1984 端口是主入口,默认就够用了。RTSP 对外端口默认没有开启,如果你需要让 VLC 等外部播放器通过 RTSP 拉流,再在配置里写上
rtsp.listen: ":8554"
,然后在 compose 里把 8554 映射出去就行。
3.3 配置目录挂载和日志排错
很多人第一次部署完,修改
go2rtc.yaml
后重启容器,发现配置没生效,然后开始怀疑人生。多半是因为挂载目录不对。我自己习惯把配置放在
/opt/go2rtc/config
下,容器里统一映射到
/config
,然后 go2rtc 默认读取
/config/go2rtc.yaml
。这样直接编辑宿主机的文件就行,改完执行
docker restart go2rtc
即可。
如果容器一直重启,最快的方式是看日志:
docker logs go2rtc --tail 50
yaml 配置格式稍微写错一点,go2rtc 可能直接退出,但日志里一般有明确的报错行,比如
yaml: line 5: mapping values are not allowed in this context
。看到这种提示,去配置文件对应行附近检查缩进和冒号就行。
4. 让摄像头“开口”:接入与转码
4.1 手写配置文件,接入 RTSP/RTMP/MJPEG 摄像头
go2rtc 的配置文件结构非常简单,核心就是
streams
这个字典,key 是流的名字,value 是源地址。下面是一份实际可用的
go2rtc.yaml
:
log:
level: info
streams:
living_room:
- rtsp://admin:123456@192.168.1.64:554/Streaming/Channels/101
garage:
- rtsp://admin:123456@192.168.1.65:554/cam/realmonitor?channel=1&subtype=0
front_door:
- rtmp://192.168.1.66/live/door
old_camera:
- mjpeg://admin:123456@192.168.1.67/video.mjpg
这里有几个要注意的点:
第一,RTSP 地址里的用户名密码如果包含特殊字符,比如
@
、
:
、
/
等,必须做 URL 编码。比如密码是
abc@123
,要写成
abc%40123
,否则 go2rtc 会把地址解析错。第二,海康和大华的 RTSP 路径不一样,海康常见的是
/Streaming/Channels/101
,大华常见的是
/cam/realmonitor?channel=1&subtype=0
。别问我怎么知道的,都是一个个试出来的。第三,配置里如果用多个源,go2rtc 会按顺序尝试连接,相当于做个简单的故障切换。
4.2 不想写配置文件,Web 界面点点点就行
如果你觉得手写 yaml 还是麻烦,go2rtc 的 Web 界面其实已经内置了流管理功能。打开
http://IP:1984
,页面上方有
Streams
区域,可以直接点击“Add”按钮添加。输入流名称和源地址,它会立即尝试连接,并且在浏览器里开始预览。
这个 Web 界面还有一个很实用的功能:自动发现局域网里的 ONVIF 摄像头。在页面上的
Discovery
区域,go2rtc 会自动扫描并列出支持 ONVIF 的设备,你只需要点击摄像头名字,它就会自动帮你生成配置并添加。我之前那台只记得 IP 不记得 RTSP 路径的摄像头,就是靠这个自动发现功能找回来的,省了翻手册的功夫。
不过需要提醒一句:自动发现依赖网络环境,如果你的摄像头 VLAN 隔离了,或者 go2rtc 容器用了 bridge 网络连不到摄像头网段,就发现不了。这时候还是老老实实手写地址,或者把容器网络改成 host 模式再试。
4.3 ffmpeg 前缀:兼容老旧摄像头和 H.265 转 H.264
不是所有摄像头都能被 go2rtc 直接拉流。某些老设备对 RTSP 的实现不太标准,go2rtc 内置的 RTSP 客户端连不上;还有一些摄像头只输出 H.265 编码,而浏览器不支持时就会出现黑屏。解决这个问题,go2rtc 提供了
ffmpeg:
前缀,启用后会自动调用内置的 FFmpeg 来做拉流和转码。
streams:
old_camera_h265:
- ffmpeg:rtsp://admin:123456@192.168.1.68:554/stream1
加上
ffmpeg:
前缀之后,go2rtc 会把 FFmpeg 当成一个“万能拉流器”,兼容性会好很多。如果你的浏览器播放 H.265 卡顿或者黑屏,也可以在 ffmpeg 参数里强制转成 H.264。go2rtc 支持通过环境变量或者配置给 ffmpeg 传附加参数,比如:
ffmpeg:
bin: ffmpeg
parameters:
- -c:v
- libx264
- -preset
- veryfast
- -c:a
- aac
这段配置的意思是:所有走 FFmpeg 的流转码成 H.264 + AAC。代价是 CPU 占用会上去,但换来的兼容性提升非常明显,老浏览器、低性能终端基本都能看。
5. 多协议播放与对外共享
5.1 Web 播放器:WebRTC 低延迟、HLS 兼容性最好、MJPEG 兜底
go2rtc 的 Web 界面里,每添加一条流,它都会自动生成对应的播放地址。对着不同场景,选择也不同。
| 协议 | 延迟 | 兼容性 | 适用场景 |
|---|---|---|---|
| WebRTC | 极低,300ms 左右 | 需要浏览器支持,内网最佳 | 自用实时监控 |
| HLS | 2-5 秒 | 所有浏览器、VLC 都能播 | 跨网络分享、嵌入网页 |
| MJPEG | 较高且体积大 | 几乎所有老旧设备都支持 | 特殊环境兜底 |
我自用的时候优先 WebRTC,因为内网延迟极低,画面几乎是实时的。看门铃按铃、看宠物动态,这种对实时性要求高的场景,WebRTC 体验最好。如果要把流分享给不在同一局域网的人看,HLS 是最省心的,直接发一个
.m3u8
地址,对方用浏览器打开就能看,没有插件依赖。
实际用法上,打开
http://IP:1984
后选择一条流,Web 界面右下角会给出不同协议的地址。比如 HLS 地址通常是:
http://IP:1984/api/stream/living_room.m3u8
RTSP 地址如果你开了
rtsp.listen
,则是:
rtsp://IP:8554/living_room
这个“一次接入,四处可用”的感觉,正是它作为流媒体网关的核心价值。
5.2 把视频流接到 Home Assistant 和 Frigate
很多玩 go2rtc 的人,最终目标都是把它接到 Home Assistant 或者 Frigate 里做统一监控和 AI 识别。这一步其实相当顺滑。
在 Home Assistant 里,如果要用 generic camera 或 stream 组件,视频源地址直接填 go2rtc 的 RTSP 或 HLS 地址即可。比如在 configuration.yaml 里:
camera:
- platform: generic
name: Living Room
stream_source: rtsp://127.0.0.1:8554/living_room
如果你用的是 Frigate,Frigate 官方很推荐 go2rtc 作为统一流媒体入口。你可以在 Frigate 的
config.yml
里把摄像头源指向 go2rtc:
go2rtc:
streams:
living_room: rtsp://127.0.0.1:8554/living_room
cameras:
living_room:
ffmpeg:
inputs:
- path: rtsp://127.0.0.1:8554/living_room
roles:
- detect
- record
这样做的最大好处是,Frigate 不再需要直接面对各种不同品牌的摄像头协议,而是统一从 go2rtc 拿流,同时 go2rtc 还能给 Web 界面、Home Assistant 提供实时预览,一套配置多处复用,省心太多。
5.3 外网访问时必须做的安全措施
go2rtc 的 Web 界面本身是不带登录认证的,一旦把 1984 端口直接暴露到公网,等于把家里的实时监控画面免费送给所有人。我强烈不建议这么做。如果确实需要外网访问,比较稳妥的做法是套一层反向代理并加鉴权。
Nginx 的反向代理配置可以参考:
server {
listen 443 ssl;
server_name your.domain.com;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
proxy_pass http://127.0.0.1:1984;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
.htpasswd
文件可以用
openssl passwd -apr1
生成。需要提醒的是,WebRTC 的 UDP 端口经过反向代理转发时会比较麻烦,如果你外网主要用 HLS,那这套 Nginx 方案完全够用;如果你外网也想用 WebRTC 低延迟,那就要把对应的 UDP 端口也一并考虑进去,这属于更进阶的网络配置了。
6. 常见问题排查和避坑记录
6.1 Docker 容器层面
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 容器一直重启 | go2rtc.yaml 格式错误 |
docker logs go2rtc --tail 50
查看报错
|
| 浏览器打不开 1984 | 端口没映射或者被防火墙拦了 |
检查
docker ps
确认映射,放行宿主机 1984 端口
|
| 改了配置重启后没变化 | 挂载目录不对 |
确认容器内
/config
对应宿主机哪个目录
|
| 服务器重启后容器没了 |
缺
--restart
参数
|
重新创建容器并加上
unless-stopped
|
我在刚开始用 Docker 的时候,最常犯的错就是把配置文件的挂载路径写错,导致改了宿主机文件但容器里读的还是旧配置。后来我统一用
/opt/go2rtc
作为项目根目录,
config
子目录挂载,再没出过这种问题。
6.2 go2rtc 连接摄像头失败
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 画面黑屏 | H.265 编码浏览器不支持 |
用
ffmpeg:
前缀转码成 H.264
|
| 连接超时 | RTSP 地址里的密码含特殊字符 | 对特殊字符做 URL 编码 |
| 画面卡顿 | 无线网络质量差或者码流过高 | 换成有线连接,或者使用摄像头的子码流 |
| 只有画面没有声音 | 摄像头的音频编码格式兼容性差 | 尝试用 FFmpeg 转成 AAC |
| 无法自动发现摄像头 | 容器网络隔离了摄像头网段 | 改用 host 网络模式,或手动填写 ONVIF 地址 |
这里特别想分享一个小经验:很多摄像头默认的主码流是 4K 甚至更高,在局域网预览时看起来流畅,但一旦走 WebRTC 或者 HLS 播放到外网,带宽不够就会出现持续卡顿。go2rtc 本身不做录像,只是实时转发,这时最有效的解法是接入摄像头的子码流,比如海康的
/Streaming/Channels/102
就是子码流,分辨率低不少,用于预览足够,带宽压力也会小很多。
6.3 资源占用与控制
go2rtc 本身作为 Go 程序,内存占用很低,通常几十 MB 就够。但如果你给很多路流都加了
ffmpeg:
转码,CPU 占用会跟着涨,因为 FFmpeg 转码非常吃计算资源。如果你在群晖这类设备上部署,建议给容器加上资源限制,并在 go2rtc 配置里合理选择是否转码。H.265 转 H.264 只在你确实需要浏览器播放时再做,不需要强行全局转码。
日志方面,go2rtc 默认会写不少访问日志,跑久了也会占磁盘空间。可以在配置里把日志级别调成
warn
,减少磁盘写入:
log:
level: warn
最后再分享一个小技巧
部署 go2rtc 这件事,其实逻辑上并不复杂:Docker 负责跑起来,go2rtc 负责把各路摄像头协议理顺,Web 界面负责可视化,Home Assistant 和 Frigate 负责后续的自动化与检测。我个人的建议是,刚开始不用急着上 compose,先
docker run
一条命令跑起来,在 Web 界面里把摄像头添加好,确认能预览、能播放、能转码,再逐步迁移到 compose 固定下来。等你真正把配置稳定住,你会发现统一的流媒体入口带来的便利远超预期,家里再多几个摄像头,也只是在 yaml 里加几行的事情。
更多推荐

所有评论(0)