家里装了四五个不同品牌的摄像头,有海康的、大华的、还有几个杂牌 PoE 相机,之前想看实时画面就得开各自的 App,想在电脑上统一预览就得更麻烦。后来我把所有摄像头都接进了 go2rtc,配合 Docker 部署,用一套配置就把 RTSP、RTMP、HTTP-FLV、HLS、WebRTC 全打通了。这篇文章把我从 0 到 1 的部署过程、配置思路和踩过的坑完整拆给你。

go2rtc 是一个用 Go 写的轻量级流媒体服务器,专注做一件事:把各种协议的视频源拉进来,再按需转成你想用的协议吐出去。它不像 FFmpeg 那样是一把功能极多的瑞士军刀,而是更像一个“流的中转站”。配合 Docker,一个容器就能同时管理十几路摄像头,浏览器直接低延迟预览,局域网内延迟能做到 0.3 秒左右,这个效果我实测下来非常稳。适合谁?如果你手里有多路不同协议的视频源,想统一接入、统一输出,还想省掉一堆复杂的 Nginx-FLV-Module 和转码脚本,这篇就是给你写的。

1. 为什么用 go2rtc,而不是直接推流?

1.1 一次性统一接入,省掉多个转流进程

我之前处理多路摄像头时,最头疼的问题就是协议不统一。海康摄像头默认给的是 RTSP 流,群里朋友推过来的直播源可能是 RTMP,还有些平台只给 HTTP-FLV 地址。想要在浏览器里看,RTSP 直接是行不通的,因为浏览器不认这个协议。于是常见做法是开几个 FFmpeg 进程,一个把 RTSP 转成 HLS、一个把 RTMP 转成 FLV,再让 Nginx 去分发。说实话,这样确实能跑通,但问题也很明显:进程多、脚本乱、端口杂、一重启你根本不知道哪个流挂了。

go2rtc 把这一层逻辑收口到了一个进程里。你只需要在配置文件里把各路源的地址写清楚,它自己会去拉流、缓存、转协议。我现在的部署方式就是公司一台 Linux 小主机上跑一个 go2rtc 容器,底下接着客厅、门口、车库三支不同品牌的摄像头,浏览器访问统一页面,手机外网通过 HLS 看。整个过程没有手动启停过任何 FFmpeg 进程,稳定性比之前脚本方案高了太多。

1.2 多种输出协议覆盖不同端

go2rtc 牛的地方在于输出端不是你指定死一种,而是同一个流名,根据你访问的方式自动切换协议。比如我有一路流叫 front_door ,浏览器里打开 Web 管理界面,它走 WebRTC 播放,延迟极低;我用 VLC 访问 rtsp://host:8554/front_door ,它就从同一个流源输出 RTSP;我想在手机 App 里临时看,直接拉 http://host:1984/api/stream.m3u8?src=front_door ,这就是 HLS。

这种“一源多出”的架构,最大好处就是不用为每个终端单独适配。摄像头端不需要知道是谁在看,go2rtc 统一从原始源拉流,说白了就是一个智能分发中心。对于家庭用户来说,你不需要懂 WebRTC 的信令细节,也不需要去配什么 HLS 切片器,配置文件里写明白源地址,剩下的交给它就行。

1.3 和 FFmpeg / ZLMediaKit 的边界

很多人一听流媒体服务器,会先想到 FFmpeg 或者 ZLMediaKit。我不否认这两个工具的能力,但说实话,在“摄像头多协议接入”这个场景上,它们都不是最顺手的选择。FFmpeg 本身是个命令行工具,你要把它变成常驻服务,还得配合 supervisor 或者 systemd 去守护进程,每个转码任务还得单独管理日志和退出码。ZLMediaKit 功能确实强,但概念也多,部署下来要理解拉流代理、录像、GB28181 这些模块,对只是想看个摄像头画面的用户来说,学习成本偏高。

go2rtc 就卡在它们中间:比 FFmpeg 更像服务,比 ZLMediaKit 更简单。它内部也能调 FFmpeg 做转码,但普通需求完全不需要触发。用一个 YAML 文件定义所有源,启动一个容器,剩下的交给它,这才是“多协议流媒体平台”该有的样子。

1.4 一个隐藏优势:Home Assistant 和 Frigate 都在用它

如果你玩智能家居,go2rtc 的名气可能会更大,因为 Home Assistant 从某个版本开始就内置了 go2rtc 集成,直接在 HA 里添加摄像头流就能用 WebRTC 播放,不需要再单独装插件。Frigate 这个 NVR 工具也把 go2rtc 作为默认推荐的流媒体后端。我之所以敢在正式环境里用它,很大程度上就是看中它在开源社区里的被集程度高、更新活跃,至少不用担心作者跑路之后没人维护。

2. Docker 部署前的规划和选型

2.1 为什么选择 Docker 而不是直接装二进制

go2rtc 本身有个很轻量的二进制,直接下载到 Linux 上也能跑。但我个人还是强烈建议用 Docker,原因有三。

第一,依赖隔离。go2rtc 有时会用到 FFmpeg,如果直接装二进制,你还要自己搞定 FFmpeg 的安装和版本兼容;用 Docker 镜像的话,镜像里已经按官方推荐把依赖备齐了。第二,管理方便。容器挂掉可以自动重启,日志统一走 docker logs 查看,想要升级版本,拉个新镜像重启容器就行,回滚也简单。第三,迁移方便。整个服务就一个 docker-compose.yml 加一个配置目录,备份、迁移到新机器,五分钟搞定。对于玩 NAS 和家庭服务器的朋友来说,Docker 几乎是标配能力。

2.2 运行环境要求与推荐

go2rtc 对硬件要求很低,纯转发模式下,Intel J4125 这种低功耗小主机跑十几路都没问题。如果是带转码的场景,比如要把 H.265 转成 H.264 给老设备看,那就需要一点 CPU 算力,建议选带核显的机器,比如 N100、i3 级别的平台,后续能上 Intel Quick Sync 硬件转码。

软件层面,我推荐直接在 Linux 服务器或者 NAS 的 Docker 环境里跑。如果你用的是 Windows 系统,Docker Desktop 也能跑,但有个坑我后面会专门说,网络模式会受限。最省心的方案,还是找一台 Linux 小主机或者群晖、威联通这类 NAS。

2.3 端口规划:别和现有服务撞车

go2rtc 默认三个关键端口需要提前规划好。我整理了一个常用端口表,部署前最好看一眼自家网络里有没有占用:

端口 协议 用途 说明
1984 TCP Web 管理界面 / API / HLS 浏览器访问和 API 调用都走这个
8554 TCP RTSP 输出端口 VLC 或其它播放器拉 RTSP 流时使用
8555 TCP/UDP WebRTC 端口 浏览器低延迟播放的核心端口,UDP 也要放行

我在第一次部署时没有规划,把 8554 和另一个服务冲突了,结果 go2rtc 启动时日志一直报端口绑定失败,排查了半天才想起来是端口占用。建议在 docker-compose 里直接映射成自定义端口,比如 18554:8554 ,这样就算冲突也能快速换掉。如果你用 host 网络模式,那端口是直接占用的,更要提前用 ss -lntup 检查一遍。

2.4 网络模式:优先 host,Docker Desktop 用户要注意

go2rtc 官方文档其实很推荐 host 网络模式,因为这样 WebRTC 的 UDP 端口不需要做繁琐的映射,性能也最好。在 Linux 环境里,这完全没问题。但如果你用的是 Docker Desktop for Windows 或者 macOS,host 模式支持得不完整,甚至某些版本根本不支持,这时候就只能走 bridge 模式加端口映射了。

bridge 模式下,除了映射 TCP 的 1984、8554,还要格外注意 WebRTC 的 UDP 8555 端口必须映射,而且如果你的 WebRTC 连接跨越不同网络,往往还需要额外暴露一段 UDP 端口范围。这个复杂度一下子就上来了。所以我个人建议,跑 go2rtc 尽量放到真正的 Linux 环境里,别在 Docker Desktop 上死磕,除非你只是本地测试。

3. docker-compose 配置详解与启动

3.1 镜像选择与目录规划

go2rtc 的官方镜像在 GitHub Container Registry 和 Docker Hub 上都有,比较常见的名字是 ghcr.io/alexxit/go2rtc 和 alexxit/go2rtc 。我习惯用 ghcr.io 仓库,更新更及时。镜像是支持多架构的,arm64 和 amd64 平台都能直接拉,树莓派上也能跑。

目录规划上,我一般会在宿主机建一个 /opt/go2rtc 目录,下面挂 config 子目录和 record 子目录。config 放配置文件,record 用来存临时录制文件。这个习惯是从之前玩其他容器服务养成的,所有配置都集中在一个地方,备份或者迁移时直接打包目录就走。

3.2 最小可用的 docker-compose.yml

直接给你一个我目前在用的最小配置,你可以复制过去改改就能用:

version: "3.8"

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

看到这里你可能发现,这个 compose 没有 ports 映射,因为用了 host 网络模式。容器内 go2rtc 的 1984、8554、8555 端口会直接绑定在宿主机上,不需要再映射一遍。如果你只能用 bridge 模式,把 network_mode 那行去掉,加上:

    ports:
      - "1984:1984"
      - "8554:8554"
      - "8555:8555"
      - "8555:8555/udp"

启动之前,记得在 config 目录里创建一个配置文件。go2rtc 支持 go2rtc.yaml 或者 go2rtc.conf ,我习惯用 YAML 格式,可读性更好。哪怕你还没配置任何流,也要确认这个文件存在,否则容器起来后会以默认空配置运行,Web 界面也能打开,只是没有视频流而已。

3.3 启动与验证:怎么确认它已经跑起来了

配置写好后,在 /opt/go2rtc 目录下执行:

docker compose up -d

查看启动状态:

docker logs go2rtc

第一次启动会拉镜像,日志里能看到版本号、监听端口和配置加载情况。启动成功后,浏览器直接访问 http://你的服务器IP:1984 ,就能打开 go2rtc 的 Web 管理界面。这个界面非常简洁,左边是流列表,右边是播放器。没有配置任何流时,界面上是空的,这很正常,接下来我们就去配置文件里添加摄像头。

我自己验证时会再用 curl 看一下 API 是否正常:

curl http://127.0.0.1:1984/api/streams

返回一个 JSON 数组,说明 API 服务正常。到这里,go2rtc 本身已经部署完毕,还剩最后一步,也是最核心的一步:把摄像头接进来。

4. 摄像头多协议接入实战

4.1 RTSP 摄像头接入:地址格式才是关键

RTSP 是目前安防摄像头最通用的协议,海康、大华、宇视这些主流品牌都支持。go2rtc 接入 RTSP 流很简单,就是在 streams 里加一行地址。但真正让新手卡壳的,是搞不清摄像头 RTSP 地址的完整格式。不同品牌地址路径不一样,而且同一个品牌主码流和子码流的路径也不同。我整理了几个常见品牌的标准地址,你在配置前先用 VLC 本地验证一下:

品牌 主码流地址示例 说明
海康威视 rtsp://user:pass@192.168.1.64:554/Streaming/Channels/101 101 是主码流,102 是子码流
大华 rtsp://user:pass@192.168.1.65:554/cam/realmonitor?channel=1&subtype=0 subtype=0 主码流,subtype=1 子码流
宇视 rtsp://user:pass@192.168.1.66:554/MediaInput/ch1/main/Streaming main 主码流,sub 子码流

在 go2rtc 的配置里,添加摄像头流是这样的:

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

写这里有个重要细节:如果密码里包含 @ 、 : 、 / 这类特殊字符,YAML 解析时会出问题。我遇到过密码里有个 @ ,结果 go2rtc 一直报认证失败,日志里看不出原因,后来才发现是 URL 解析把 @ 当成用户名和密码的分隔符了。解决办法很简单,把整个地址用双引号或单引号包起来:

  front_door:
    - "rtsp://admin:pass@word@192.168.1.64:554/Streaming/Channels/101"

4.2 接入更多类型源:RTMP、HTTP-FLV、文件等

go2rtc 不只是接 RTSP 摄像头,它支持的源协议非常多。我实际用过几个场景,给你列一下:

如果你有个 RTMP 推流源,比如来自 OBS 推流或者某些直播平台的源地址,配置方式一样:

streams:
  live_rtmp:
    - rtmp://192.168.1.100:1935/live/stream

如果你只有一个 HTTP-FLV 的地址,比如某些平台提供的 .flv 链接,go2rtc 也能直接拉:

streams:
  flv_source:
    - http://192.168.1.100:8080/live/stream.flv

甚至如果你有本地视频文件想临时测试,也可以直接指向文件路径:

streams:
  test_video:
    - /record/test.mp4

这种多协议接入能力,让我觉得 go2rtc 更像是一个“视频源适配器”。不管底层是什么协议,在上面都统一成一个命名流,访问端完全感受不到区别。

4.3 核心输出协议怎么选:WebRTC / HLS / RTSP

接入做好了,接下来就是输出。同一个流 front_door ,不同场景下我用不同方式拉。

浏览器实时预览,首选 WebRTC。在 go2rtc 的 Web 界面里,直接单击流名就会自动走 WebRTC 播放。WebRTC 延迟最低,局域网实测 0.2 到 0.5 秒,基本感觉不到延迟。这也让我可以在门口有人按门铃时,直接浏览器弹窗看到实时画面,而不是等 5 秒延迟的 HLS。

手机或者 App 里看,用 HLS 最方便。地址格式是 http://HostIP:1984/api/stream.m3u8?src=front_door 。HLS 延迟会高一些,我实测在 3 到 10 秒左右,取决于播放器缓冲设置,但兼容性极好,iOS 的 Safari 和安卓的播放器基本上通吃。

如果要在 VLC 或者支持 RTSP 的客户端里看,用 rtsp://HostIP:8554/front_door 。这个就是 go2rtc 把统一流直接转成 RTSP 输出,VLC 打开这个地址就能直接播放。

如果你需要把这个流推给其他服务,比如让 OBS 抓流或者推到另一个流媒体服务器,还可以用 RTMP 输出: rtmp://HostIP:1935/front_door ,go2rtc 默认也开了一个 RTMP 服务端口。

4.4 按需拉流 on_demand,节省带宽

默认情况下,go2rtc 配置好摄像头之后,它会一直保持拉流状态,好处是任何时候去看都是秒开,坏处是摄像头和服务器之间的带宽一直被占用。如果你家里摄像头不多,这无所谓;但如果你接了十几路,或者摄像头在户外走 4G 网络,一直拉流就不太划算。

go2rtc 提供了 on_demand 参数,可以让它“懒加载”:有客户端访问时才真正去拉摄像头的流,没有人在看时自动断开。配置方式是在对应流名下面加一个参数:

streams:
  front_door:
    - "rtsp://admin:pass@192.168.1.64:554/Streaming/Channels/101"
    on_demand: true

我一开始把所有流都设成常驻,结果发现 4G 摄像头一个月流量跑掉好几个 G,后来改成 on_demand ,流量直接降了 70% 多。代价是第一次访问会有 1 到 2 秒的等待,因为要重新建立连接。这个取舍我觉得非常值得。

5. 踩坑记录和问题排查

5.1 摄像头不出流,我建议的排查顺序

这个问题我在群里被问过最多。摄像头配置进去,Web 界面点开就是黑屏或一直加载。我自己的排查逻辑是“先源头,再中间,后输出”,按这个顺序走能省很多时间。

第一步,先确认摄像头地址在 VLC 里能打开。如果你拿 VLC 打开同一个 RTSP 地址都是黑屏或者报错,那问题根本不在 go2rtc,而是摄像头端的认证、地址路径或者网络不通。第二步,看 go2rtc 的日志。执行 docker logs go2rtc ,如果能看到 401 Unauthorized ,基本是用户名密码错了;如果是 404 Not Found 或者 No such stream ,多半是地址路径写错了;如果是 Connection refused 或者 timeout ,那就是摄像头端口不通或者防火墙挡住了。第三步,确认端口和网络。摄像头和 go2rtc 服务器是否在同一网段,摄像头是否限制了访问 IP。

我用过一个简化流程,总共就两句话:先在 VLC 测源,再在 go2rtc 日志里找线索。按这个顺序,我基本三五分钟就能定位问题,没必要一上来就怀疑 go2rtc 配置。

5.2 H.265 的视频在浏览器里放不了,怎么办?

摄像头尤其是 4K 款的,默认编码不少是 H.265/HEVC。但浏览器对 H.265 的支持一直是个老大难,Chrome、Firefox 自带的 WebRTC 播放基本不支持 H.265,只有 Edge 在某些条件下能硬解。你配置好摄像头之后,如果用 WebRTC 播放黑屏但 VLC 走 RTSP 播放正常,十有八九就是编码格式的问题。

最简单的解法,是把浏览器的播放协议改成 MP4 之类的兼容格式,或者直接用 VLC。但如果你确实希望在浏览器里流畅看 H.265 的摄像头,最好请 go2rtc 帮你把流转成 H.264。配置方法是在流前面加 ffmpeg: 前缀:

streams:
  front_door_h264:
    - "ffmpeg:rtsp://admin:pass@192.168.1.64:554/Streaming/Channels/101"

加了 ffmpeg: 前缀之后,go2rtc 会用内置的 FFmpeg 去拉流并实时转码成 H.264。代价是 CPU 占用会上升。我自己实测,一个 1080P H.265 转 H.264 的流,大约要吃 0.3 到 0.5 个核,如果是 N100 这种小主机,同时转两路就有点吃力了。如果你家里全是 4K H.265 摄像头,个人建议不要全都走实时转码,要么用支持 H.265 硬解的播放器,要么只在需要网页预览时才转码,配合 on_demand 使用。

5.3 延迟大、画面卡顿,优先检查这几个点

WebRTC 延迟还大的话,先怀疑是不是网络瓶颈,而不是 go2rtc。我遇到过几次,最后发现要么是摄像头端的上行带宽不够,要么是 wifi 信号差。

实践时我有个习惯:先看 go2rtc 的 Web 界面里的流状态。如果能显示出实时的比特率,你就能判断是不是摄像头推流码率过高。比如摄像头是 4K 主码流,码率跑到了 12 Mbps,但你的无线网卡实际传输只有 8 Mbps,那画面必然卡。解决办法也很直接:改用子码流接入预览,把码率压到 2 Mbps 左右就完全够看了。

还有一个容易被忽视的点:go2rtc 日志里如果频繁出现 dropped 或者 late 这类的字样,说明接收端处理不过来,通常是 CPU 不够或者磁盘 IO 有问题。这时候优先降低转码负担。

5.4 问题排查速查表

我把实际操作中碰到过的常见问题整理成了一个表,方便你直接对照:

现象 大概率原因 解决方案
Web 界面点流黑屏 H.265 编码浏览器不支持 用 ffmpeg: 前缀转 H.264,或用 VLC 播放 RTSP
日志报 401 摄像头账号密码错误 去摄像头后台确认密码,注意 URL 特殊字符
日志报 404 或 No such stream RTSP 地址路径错误 用 VLC 先测试,确认是主码流还是子码流路径
日志报 timeout 摄像头网络不通或防火墙拦截 检查摄像头与服务器之间的连通性
画面卡顿、延迟高 主码流码率太高或 wifi 信号差 切换子码流,降低码率,优先有线连接
容器直接退出 端口被占用或配置格式错误 查看 docker logs go2rtc ,检查端口的占用

6. 扩展玩法:从流媒体中心到自动化

6.1 接入 Home Assistant,实现智能家居联动

go2rtc 被 Home Assistant 集成之后,摄像头流在 HA 的仪表盘里直接用 WebRTC 播放,延迟低到像看本地视频。配置方式也很简单:在 HA 里添加 go2rtc 集成,填上 go2rtc 服务器的 IP 和 1984 端口,然后在设备里添加摄像头流即可。我现在的门铃摄像头就是这么接入 HA 的,门口有人按铃时,智能音箱弹窗提醒的同时,平板立刻显示实时画面,体验很顺滑。

这块功能的好处是你不会受摄像头厂家 App 的生态限制,不同品牌的摄像头可以在 HA 的同一个面板里并排显示。再配合 HA 的自动化,比如检测到人体移动时自动录制或者推流到某个房间的显示屏,玩法就非常多了。

6.2 按需录制视频片段

go2rtc 自带一个很实用的 API,可以直接按需录制当前流的视频片段:

curl -o record.mp4 "http://127.0.0.1:1984/api/record.mp4?src=front_door&duration=30"

这个命令会从当前流中录制最近 30 秒的视频保存成 MP4 文件。我一般会在某个事件触发时,用它把门口的画面录下来,方便回头看是谁来过。当然,它不像正经 NVR 那样有完整的录像计划和回放界面,如果你需要真 24 小时不间断录像,建议在 go2rtc 后面再接 Frigate 或者 Scrypted。

Frigate 是我现在很推荐的一个组合,它专门做摄像头检测和录像,go2rtc 作为前端拉流组件,把视频推给 Frigate 做识别和存储,两者配合非常默契。Frigate 对 go2rtc 的官方支持意味着很多配置项都已经帮你优化好了,基本上 Go2RTC 里能看的流,Frigate 里直接引用流名就能用,不需要二次适配。

6.3 把 go2rtc 的流变成虚拟摄像头,接入会议软件

还有一个我实际用得很多的玩法:把 go2rtc 里的视频流通过 OBS 变成虚拟摄像头,然后在腾讯会议、Zoom、钉钉这些软件里选它作为摄像头源。举个例子,我想给异地朋友直播一下家里阳台的植物,或者在公司会议里共享现场画面,我就不用再举着手机,直接在 OBS 里添加一个媒体源,填入 go2rtc 的 HLS 地址或 RTSP 地址,OBS 就会把它当时视频画面,再用 OBS 的虚拟摄像头功能输出给会议软件。

OBS 添加媒体源时,地址填 http://127.0.0.1:1984/api/stream.m3u8?src=front_door ,或者 rtsp://127.0.0.1:8554/front_door 都可以。我实测下来,HLS 地址在 OBS 里更稳,RTSP 偶尔会断流重连。

这里要注意的是,OBS 机器最好和 go2rtc 服务器在同一个局域网,延迟低而且稳定。如果要从公网拉流,你还需要在路由器上做端口转发,并且考虑带宽成本。坦白说,公网远程看流的最佳方案我觉得还是 HLS,因为兼容性和抗丢包能力都比 WebRTC 更稳,代价是延迟高一点。

7. 写在最后的一点实际体会

如果你之前没有接触过 go2rtc,我建议你第一次配置时,不要一上来就把所有摄像头全接入。先用一支摄像头、一条流,把 Web 界面预览、VLC 拉 RTSP、手机播放 HLS 这三条链路全跑通,确认整套系统正常了,再分批把其余摄像头加进去。我在正式环境推广这个方案时,都是先在测试机上跑通,再切生产,这样排障压力会小很多。

另外,go2rtc 的镜像不要一直追 latest ,虽然它更新很积极,但偶尔也会有行为变化的版本。我在生产环境里习惯指定大版本号或者固定的 tag,等测试环境验证无误后再更新。这样至少不会在一个周末的早上发现原本正常的页面突然打不开了。

最后再说一个小经验:配置修改后,不需要重启整个容器,只要在 Web 界面里点击刷新,或者调用 API 重新加载配置就行。这个细节能让你调试摄像头时少等很多次容器重启的时间。

整体来说,go2rtc 不是那种功能庞杂、越用越乱的系统,它定位非常明确,就是做一个稳定可靠的视频流分发中心。把摄像头统一接入之后,不管是自己本地看、远程看、录像、还是接智能家居,你面对的永远是一套简单清晰的流名,而不是一堆五花八门的协议地址。这套方案我用了大半年,几乎没再为摄像头流媒体操过心,偶尔需要排查问题,看日志和访问状态也都很直观。如果你也被多协议摄像头接入折磨过,可以试试这个方案。

Logo

邀请您加入社区

更多推荐