如果你手里同时有七八台不同品牌的摄像头,一台海康、一台大华、一台小米,甚至还有两台杂牌 IPC,那你大概率经历过这种崩溃:每台摄像头都有自己的专属 App,界面割裂不说,协议还五花八门,有的支持 RTSP,有的只给 RTMP,有的必须用厂商自己的 SDK 才能拉到流。想把它们统一到一个页面里低延迟看,Google 搜一圈出来的方案要么配置复杂,要么动不动就转码吃满 CPU。我最后稳定用下来的组合就两个关键词:Docker 加 go2rtc。这是一个用 Go 写的轻量级流媒体网关,本质上解决的就是“多协议接入 + 统一输出”的问题。

go2rtc 这个名字拆开看很好理解:go 是它的开发语言,rtc 指向实时通信。它能把 RTSP、RTMP、HLS、MJPEG、ONVIF 这些来自不同摄像头的协议源全部收进来,然后再以 WebRTC、HLS、MJPEG 等方式输出。最吸引我的是 WebRTC 输出——浏览器不需要装插件,打开网页就能看监控,首帧延迟通常在几百毫秒内,比以前用 HLS 看监控动辄两三秒的延迟舒服太多了。配合 Docker 部署,不管是 x86 的小主机、群晖 NAS,还是 Arm 架构的软路由,都能很轻松地把这套平台搭起来。

这篇文章我会从部署思路、环境准备、实际配置、问题排查到安全加固完整走一遍,全程按我自己实操的方式来讲。想省事的话,直接照着第二章到第四章的配置一把梭就能跑起来;想弄明白背后原理的,第一章和第四章的协议说明应该能帮你少走不少弯路。

1. go2rtc 是什么?为什么我在众多方案里最终选了它

1.1 先看看摄像头协议有多碎

很多人觉得视频监控不就是一路 RTSP 的事情吗?买回来的摄像头接上网线,然后在软件里填一个 rtsp://ip:554/... 的地址就完事了。但真当你手里有多个品牌设备的时候会发现,事情远没有这么简单。

RTSP 确实是监控行业事实标准,可各家在标准之上玩出了自己的花样。海康的默认主码流地址是 /Streaming/Channels/101 ,大华走的是 /cam/realmonitor?channel=1&subtype=0 ,某些杂牌摄像头又把 ONVIF 和 RTSP 的路径改得面目全非。更别提还有一批互联网摄像头,官方 App 走的是私有云协议,你连 RTSP 地址都拿不到,只能通过卖家提供的额外固件才能解锁本地拉流。

除了 RTSP 之外,你还会遇到 RTMP、HLS、MJPEG 这些协议。RTMP 早年是直播推流的好手,不少老设备只开放这个;HLS 是苹果系生态常见的切片协议,延迟普遍两三秒以上;MJPEG 则是把视频当成一帧一帧的 JPEG 图片连续输出,兼容性极强但带宽效率很低。这些协议之间的转换,就是流媒体网关存在的意义。

1.2 技术选型:go2rtc 对比 FFmpeg 和 Mediamtx

我在正式确定 go2rtc 之前,其实把常见的几套方案都试过一遍。最传统的做法是直接拉 FFmpeg 进程做转码推流,比如用 ffmpeg -i rtsp://... -c:v copy -f flv rtmp://... ,但这条路的问题在于进程管理全靠自己写脚本,多一路摄像头就要多维护一个进程,崩了没人帮你拉起来,流复用的逻辑也完全没有。

Mediamtx 也是我很看好的一个项目,它本身是优秀的 RTSP/RTMP/WebRTC 媒体服务器,适合把已有的 RTSP 源重新广播到多路。但它在协议输入的“桥接”层面没有 go2rtc 彻底,尤其是对 ONVIF 自动发现、多源回退这类家庭监控场景的支持,go2rtc 明显更对味。而且 go2rtc 自带的 Web UI 非常轻量,打开浏览器就能看到所有流的状态,这对日常维护来说太重要了。

go2rtc 的核心优势有这么几点。第一,单二进制文件,内存占用通常在几十 MB 级别,放到群晖或软路由上毫无压力。第二,默认不转码,只做流协议和封装层面的转换,CPU 占用很低,只有当你明确配置了 FFmpeg 输出时才会拉起转码进程。第三,Go 语言天然适合高并发连接,同一路流有多个人在网页上看,它对摄像头侧只维持一路拉流连接,然后分发到多个观看端,大大降低了摄像头的压力。第四,就是它和 Home Assistant、Frigate 两大智能家居项目深度绑定,社区插件和配置案例非常丰富。

1.3 整体架构与流转发逻辑

go2rtc 内部以“流 ID”为核心来管理一切。你给它配置一个 camera1 ,它内部就建立一个同名流对象;这个流后面可以挂多个“源”,比如同时挂主码流和子码流两个 RTSP 地址,也可以挂一个 RTMP 地址作为备用。当浏览器或者第三方请求 camera1 这条流时,go2rtc 会选择一个可用的源开始拉流,然后在内存里做很轻量的解析与缓冲,再按照观看者的协议要求封装输出。

数据链路可以理解成这样一个过程:摄像头通过 RTSP 把 RTP 包发送过来,go2rtc 收到后按需解析出视频帧,接着把这些帧交给一个“输出分发器”。分发器会维护当前这条流的所有消费者,比如网页端用 WebRTC 来看的就是一组,VLC 用 RTSP 来看的是另一组,走 HLS 切片的又是一组。因为不转码,所以各组消费者拿到的都是原始编码数据,只是封装方式不同。这也是 go2rtc 在同等硬件条件下,能比那些暴力转码方案支撑更多路数的根本原因。

WebRTC 之所以延迟低,是因为它在浏览器和 go2rtc 之间走的是 UDP 通道,使用 SRTP 加密传输,不需要像 HLS 那样先切片、再下载、再播放,省掉了缓冲队列。理解这一层,后面配置 WebRTC 时你就会知道,UDP 端口能不能通、候选地址能不能让浏览器找到,才是整个链条里最关键的环节。

2. 部署环境准备:先把 Docker 和网络这关过了

2.1 Linux 服务器 / NAS 上的 Docker 环境

go2rtc 支持直接下载二进制运行,但用 Docker 部署的最大优势是环境隔离和省心。我自己常用的一台设备是跑 Ubuntu 的小主机,安装 Docker Engine 的方式很简单,先更新系统索引,然后安装依赖包,再添加 Docker 官方软件源并执行安装。如果你完全不想折腾,也可以直接用发行版自带的管理命令安装,比如 Ubuntu 上用 sudo apt install docker.io ,虽然版本可能旧一点,但跑 go2rtc 这种更新频率不高的服务完全够用。

安装完记得验证一下:执行 docker version ,只要 Client 和 Server 两段都有版本信息,就说明 Docker 守护进程正常。这里最容易被坑的是 Linux 权限问题,直接执行 docker ps 提示权限不足的话,把当前用户加入 docker 用户组,然后重新登录一次即可。

群晖用户就更简单了,DSM 自带的 Container Manager(也就是以前的 Docker 套件)直接可以在图形界面里拉镜像、建容器,唯一要注意的是文件挂载路径要选在存储空间上,别挂到临时目录,否则重启后配置可能丢失。

2.2 Docker Desktop 在 Windows / macOS 上的坑

Windows 用户如果打算本机跑,通常绕不开 Docker Desktop。Docker Desktop 在 Windows 上依赖 WSL2 后端,安装流程本身不难,但我遇到过不少朋友卡在一个报错上:启动时提示 virtualization support not detected ,Docker Desktop 直接 failed to start。这通常意味着 BIOS 里的 CPU 虚拟化没打开,或者 Windows 功能里的“虚拟机平台”没有启用。

解决路径是:重启进入 BIOS,找到 Intel VT-x 或 AMD-V 相关选项并开启;然后在 Windows“启用或关闭 Windows 功能”里勾选“虚拟机平台”和“适用于 Linux 的 Windows 子系统”,重启后再打开 Docker Desktop。如果是公司电脑,这一步可能需要管理员权限。

还有一点要提醒,Docker Desktop 在 Windows 和 macOS 上对 host 网络模式的支持并不完善,这在后面选网络模式时会直接影响 go2rtc 的 WebRTC 播放。最简单的做法是直接用端口映射,把容器的 1984、8554、8555 几个端口分别映射出来。防火墙记得放行 UDP 8555,这一步很多人漏掉,导致网页里画面一直转圈。

2.3 端口规划与网络模式选型

go2rtc 默认会用到几个端口:1984 是 Web 管理界面和 API 端口,8554 是它对外提供的 RTSP 服务端口,8555 是 WebRTC 的 UDP/TCP 监听端口。如果只在内网用,这些端口全部保持默认即可;如果后续要远程访问,再考虑通过反向代理把 1984 暴露出去。

网络模式的选择,Linux 环境我强烈建议直接用 host 模式。host 模式让容器直接共享宿主机网络栈,不存在端口映射和 NAT 转换,UDP 端口天然就是通的,配置 WebRTC 时会少很多麻烦。代价是端口直接暴露在宿主机上,如果你宿主机本来就跑着别的服务,要注意 1984 是否冲突。

Windows 和 macOS 的 Docker Desktop 对 host 模式支持不友好,所以老老实实用 bridge 加端口映射就好。但这种情况必须手动配置 WebRTC 的 candidates,把宿主机的局域网 IP 填进去,否则浏览器的 WebRTC 会话无法建立。这个配置我在第四章会专门展开讲。

3. 用 Docker 实际部署 go2rtc,完整过程记录

3.1 最简命令:docker run 一行拉起服务

go2rtc 官方镜像名称是 alexxit/go2rtc ,在 Docker Hub 和 GitHub Container Registry 都有发布。第一次上手,最快的方式是直接执行这段命令:

mkdir -p /opt/go2rtc && cd /opt/go2rtc
docker run -d --name go2rtc \
  --restart unless-stopped \
  --network host \
  -v /opt/go2rtc:/config \
  alexxit/go2rtc

解释一下每个参数的作用: -d 表示后台运行, --restart unless-stopped 让容器在宿主机重启后自动拉起,同时只有手动 stop 时才不会自动恢复。 --network host 让容器直接用宿主机网络,省去端口映射。 -v /opt/go2rtc:/config 则是把宿主机的配置目录挂载到容器里的 /config ,go2rtc 会自动在这个目录下读取 go2rtc.yaml 配置文件。

如果暂时没有配置文件,容器启动后 go2rtc 也会使用默认配置运行。这时候访问 http://宿主机IP:1984 ,应该能看到一个简陋但可用的 Web 界面,页面上会显示一条名为 Go2RTC 的默认测试流,可以用来验证 WebRTC 是否打通。

3.2 使用 docker-compose 管理,配置更清晰

命令行虽然简单,但配置项一多就容易乱,而且每次都要重新敲一遍。我实际使用中更推荐用 docker-compose 把整个部署声明成一个文件,后续不管在哪台机器上恢复部署,只要复制文件再跑一条命令就行。下面是我常用的 compose 文件:

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

注意我把配置文件以只读方式挂载进去, ro 表示容器内无法改写配置,这样能避免误操作把配置写坏。第二个挂载目录 ./media 是留给录像输出的,go2rtc 的 FFmpeg 输出会把文件写到这个目录。

如果是在 Windows 上跑,把 network_mode: host 这一行去掉,在 ports 段里加端口映射:

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

然后 docker compose up -d 启动。从启动到服务可用大概只要几秒钟,这是 go2rtc 非常舒服的地方,启动速度和轻量性都不是虚拟机能比的。

3.3 验证服务是否真的起来了

部署完之后不要急着一股脑去填摄像头地址,先做三个基本检查。第一,执行 docker ps ,确认 go2rtc 容器状态是 Up,如果看到 Exited,用 docker logs go2rtc 看启动日志,最常见的问题是端口被占用导致监听失败。第二,在宿主机执行 curl http://127.0.0.1:1984/api/exit ,正常会返回一个 ok ,说明 API 服务正常。第三,用浏览器访问 http://宿主机IP:1984 ,能看到默认页面和测试流。

这里有个小细节:在 bridge 网络模式下,浏览器访问的地址和容器内部监听的地址不是一回事。你镜像里容器监听 1984,外部用 http://宿主机IP:1984 访问,这没问题;但如果你在容器内执行 curl 去访问宿主机 IP 反而可能不通。所以验证时尽量在宿主机或者局域网另一台电脑的浏览器上操作,更贴近真实使用场景。

4. 接入各类摄像头与 WebRTC 关键配置

4.1 配置文件总览:先认识 go2rtc.yaml

go2rtc 的配置采用 YAML 格式,入口文件就是挂载目录下的 go2rtc.yaml 。整体结构并不复杂,核心段有 log 、 api 、 rtsp 、 webrtc 、 streams 。 log 控制日志等级, api 和 rtsp 控制两个服务端口, webrtc 是浏览器播放的关键配置, streams 则是真正定义摄像头来源的地方。

一段最小可用但完整的配置长这样:

log:
  level: info

api:
  listen: ":1984"

rtsp:
  listen: ":8554"

webrtc:
  listen: ":8555"
  candidates:
    - 192.168.1.100:8555
    - stun:8555

streams:
  camera1:
    - rtsp://admin:password@192.168.1.64:554/Streaming/Channels/101

把 192.168.1.100 换成你宿主机实际的局域网 IP,把摄像头地址改成你自己的,保存后执行 docker restart go2rtc ,配置就会生效。如果你用的是 compose,也可以直接 docker compose restart go2rtc 。

4.2 各品牌摄像头 RTSP 地址的写法

不同品牌摄像头的 RTSP 地址格式差异很大,我把常见的几种列在下面。海康威视的默认地址是 rtsp://用户名:密码@IP:554/Streaming/Channels/101 ,其中 101 表示通道 1 主码流,102 是通道 1 子码流,201、202 则是通道 2 的主子码流,依次类推。大华是 rtsp://用户名:密码@IP:554/cam/realmonitor?channel=1&subtype=0 , subtype=0 是主码流, subtype=1 是子码流。

TP-LINK 和大多数 ONVIF 兼容设备通常可以用 rtsp://用户名:密码@IP:554/onvif1 或者干脆用 /stream1 、 /ch0 这样的路径。这里我不建议死记硬背,最稳的方法是把摄像头在网页管理后台里打开“媒体设置”页面,上面通常会写设备本身的 RTSP 播放地址,或者用官方 App 里的“本地 RTSP 信息”功能查看。拿不到确切路径的话,就用 ONVIF 自动发现来兜底。

还有一点很容易踩坑:如果密码里有 @ 、 : 、 / 这类特殊字符,直接填进 URL 会导致解析错误。处理方法是对这些字符做 URL 编码, @ 要写成 %40 , : 写成 %3A , / 写成 %2F 。比如密码是 abc@123 ,URL 里要写成 abc%40123 。

4.3 ONVIF 自动发现:杂牌摄像头也不怕

如果摄像头支持 ONVIF 协议,go2rtc 可以用一种更省心的方式接入:只给 IP 和账号密码,让它自动探测设备支持哪些流地址。做法是在 streams 里写一个带 onvif:// 前缀的地址:

streams:
  garden:
    - onvif://admin:password@192.168.1.65

go2rtc 会去设备的 ONVIF 服务里查询媒体配置文件,拿到 RTSP 地址后自动拉流。这种方式的好处是,即使你不知道这个型号确切的 RTSP 路径,只要设备开了 ONVIF,基本都能认出来。我实测下来,很多杂牌摄像头在 ONVIF 模式下还能拿到多档码流,可以直接选择低清晰度做多路预览。

有一点需要留意,开启 ONVIF 接入时,摄像头的 ONVIF 账号和 RTSP 账号可能是同一个,也可能一个是主账号一个是子账号。如果提示鉴权失败,去摄像头后台检查一下 ONVIF 用户的设置,确认它有所需的“媒体查看”权限。另外,ONVIF 自动发现的延迟比直接写 RTSP 地址略高一点,追求极致拉起速度的话,还是建议用明确路径。

4.4 WebRTC candidates:为什么网页一直黑屏

很多人部署完后,RTSP 源在 VLC 里播放正常,但 go2rtc 的网页播放就是黑屏转圈。这个问题九成出在 WebRTC candidates 配置上。

要理解 WebRTC 的连接过程,可以把它想象成打电话:浏览器要先知道“对方号码”才能拨号。这里的“号码”就是 ICE 候选地址,也就是 go2rtc 进程实际可达的 IP 和端口。在 Linux host 网络模式下,go2rtc 能自动探测到正确的网卡 IP,所以很多时候不写 candidates 也能工作。但在 bridge 模式或 Docker Desktop 环境下,容器内部看到的 IP 和浏览器能访问的宿主机 IP 不是同一个,浏览器拨号自然就拨不通了。

解决办法是显式声明 candidates。对于内网场景,最简单的是写宿主机局域网 IP 加 WebRTC 端口:

webrtc:
  listen: ":8555"
  candidates:
    - 192.168.1.100:8555
    - stun:8555

stun:8555 表示让 go2rtc 自己向 STUN 服务探测公网映射地址,在内网环境一般都够用。如果你要做公网远程访问,那还需要把路由器的端口映射打开,并在 candidates 里加入公网 IP 和对应的端口。在公网和局域网并存的情况下,candidates 可以同时写多个,浏览器会按顺序尝试,优先走通的那条路径。

5. 浏览器实时播放、录制与第三方扩展

5.1 打开 Web UI,多摄像头同屏管理

go2rtc 的 Web UI 虽然不算华丽,但清晰度和实用性都很好。浏览器访问 http://宿主机IP:1984 后,页面上会列出配置好的所有流名称,点击任意一条,它会调用 WebRTC 播放。如果摄像头支持多码流,你配置了 camera1 和 camera1_sub 两条流,UI 里就会分别显示,点哪个看哪个。

多路同屏在 UI 里没有直接的一键九宫格功能,但我通常的做法是开多个浏览器标签页,分别播放不同的流,再配合操作系统的分屏功能。如果你需要更正式的多路监控墙,可以后面把它接入 Home Assistant 的 dashboard,用 HA 的 picture-entity 卡片把多路流拼接在一起,效果比 go2rtc 原生 UI 好不少。

Web UI 上还有一个容易被忽略的功能,就是每条流旁边会显示状态信息,比如当前源的协议、分辨率、码率。排查问题时,这里比日志直观得多。流如果处于断线状态,UI 上会明确标红,这就节省了大量猜测时间。

5.2 配置录像输出:把流落盘到本地

看监控只是一半需求,很多时候还得能回放。go2rtc 本身不做录像存储,但它可以把流直接丢给 FFmpeg 输出到文件。前提是容器里装了 ffmpeg。官方镜像默认就集成了 FFmpeg,所以不需要额外处理。

在 streams 里给某条流加一个 FFmpeg 输出,写法是在流定义后面追加一个以 #ffmpeg: 开头的输出地址:

streams:
  camera1:
    - rtsp://admin:password@192.168.1.64:554/Streaming/Channels/101
    - "#ffmpeg:media/camera1.mp4"

注意这里的输出路径是相对容器内工作目录的,挂载 ./media:/media 之后,实际文件会写到宿主机的 ./media/media/camera1.mp4 ,有点绕。我更推荐直接写绝对路径:

    - "#ffmpeg:/media/camera1.mp4"

go2rtc 在处理 FFmpeg 输出时会自动复用已经拉到的流,不额外占用摄像头的连接数。但如果你持续写入无限制的文件,磁盘会被写满。对轻度家用,我会用外部 crontab 定期清空或移动录像文件;对认真做安防的朋友,更建议把录像交给 Frigate 或者专用 NVR 系统,go2rtc 专心负责“桥接”这一件事。

5.3 HLS / MJPEG 输出:给不支持 WebRTC 的场合留后路

虽然 WebRTC 延迟低,但并不是所有客户端都支持。比如某些旧款手机浏览器、或者你要把视频流嵌到第三方网页里,WebRTC 就未必能顺畅工作。go2rtc 直接暴露了多种输出 API,方便在不同场景下取流。

最常用的几个接口是:

  • HLS: http://宿主机IP:1984/api/hls/camera1
  • MJPEG: http://宿主机IP:1984/api/stream/mjpeg/camera1
  • 原生 RTSP: rtsp://宿主机IP:8554/camera1

HLS 接口给那些低端播放器用,延迟一般几秒,但胜在几乎什么浏览器都能播。MJPEG 接口非常适合做门禁预览图、缩略图,或者嵌入到 Home Assistant 的图片卡片里,轻量无压力。RTSP 输出则可以把 go2rtc 当成一个轻量级 RTSP 服务器,让 VLC、Onvif 客户端直接拉它。

我在实际项目里的习惯是,默认用 WebRTC 看实时画面,同时把子码流通过 MJPEG 暴露给 HA 做自动化触发条件,主码流保留在 go2rtc 内部只对 Frigate 提供检测流。这样每一路流都被物尽其用,摄像头也不至于被多个系统重复拉流拉垮。

5.4 与 Frigate / Home Assistant 联动

如果你已经在用 Frigate 做 AI 检测,go2rtc 可以说是它的最佳拍档。Frigate 自带的 go2rtc 集成可以直接复用 go2rtc 的流,这样摄像头只需要被连接一次,go2rtc 负责把视频分发给 Frigate 的检测进程和浏览器回放端。我自己在 Frigate 配置里做得很简单,把检测源指向 go2rtc 的 RTSP 输出地址:

cameras:
  front:
    ffmpeg:
      inputs:
        - path: rtsp://192.168.1.100:8554/camera1
          roles:
            - detect
            - rtmp

Home Assistant 那边,如果是用官方集成,直接把 stream_source 指向 go2rtc 的 RTSP 输出即可,也可以用 generic camera 平台:

camera:
  - platform: generic
    name: Garden
    stream_source: rtsp://192.168.1.100:8554/garden

这一步做下来,等于把 go2rtc 变成了整个智能家居视频生态的中枢。后续无论加多少个摄像头、多少套系统,接入层都只需要面对 go2rtc 一个入口,维护成本直线下降。

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

6.1 高频问题速查表

我整理了一份在实际使用中反复遇到的问题清单,按频率从高到低排,基本覆盖了大多数人部署 go2rtc 时踩过的坑。

现象 大概率原因 处理办法
网页播放一直转圈 WebRTC 的 candidates 没配对,UDP 端口不通 在 webrtc 配置里显式写宿主机局域网 IP,检查防火墙是否放行 UDP 8555
摄像头显示已连接但无画面 RTSP 地址路径不对,或子码流不支持 H.265 用 VLC 验证原始 RTSP,确认流是否可用,必要时换主码流尝试
画面卡顿严重 无线网络带宽不足,或摄像头本身码率设置过高 改用子码流播放,或者把摄像头码率上限调低
拉流鉴权失败 密码包含特殊字符未转义 将 @ 、 : 、 / 等字符改为 URL 编码
Docker Desktop 启动失败,报 virtualization support not detected BIOS 虚拟化未开启,或 Windows 虚拟机平台未启用 进入 BIOS 开启 VT-x/AMD-V,勾选“虚拟机平台”和 WSL2 功能
摄像头掉线后不自动恢复 RTSP 连接被设备主动断开,go2rtc 自动重连间隔长 提升日志级别观察重连状态,必要时给摄像头设置固定 IP 和静置时间

表格之外的隐藏规律:大多数连接问题都可以用同一种排查思路解决——先绕开 go2rtc 验证原始流,再由内向外逐层排查。不要一上来就怀疑 go2rtc,很多时候是摄像头侧的网络和鉴权问题。

6.2 排查思路:用日志和工具定位问题

我的排查顺序一般是这样的:先在宿主机上用 VLC 或者 ffprobe 直接去拉摄像头的原始 RTSP 地址,比如执行:

ffprobe -rtsp_transport tcp -v error -show_entries format=duration \
  -i "rtsp://admin:password@192.168.1.64:554/Streaming/Channels/101"

如果这个命令能正常输出时长,说明原始流没有问题,问题出在 go2rtc 的协议转换或 WebRTC 通道。如果这一步就报错,那先解决摄像头侧的问题:账号是否有效、路径是否正确、摄像头是不是被别处占用导致连接数满了。

确认原始流正常后,再看 go2rtc 的日志。在配置里把 log.level 调成 debug ,然后 docker logs -f go2rtc ,就能看到它尝试连接摄像头、解析 SDP、转发数据包的详细过程。有个很典型的日志:连接建立后不断打印 EOF 或 timeout ,说明数据传输中段,基本是网络不稳定或者摄像头主动踢了连接。

最后才是 WebRTC 层的问题排查。这时候我会直接用浏览器开发者工具,打开 Network 面板过滤 WebRTC 相关的连接事件,看看 ICE candidate 是否配对成功。如果能看到 go2rtc 上报的候选地址和浏览器本地地址,说明 candidates 配置生效;如果候选地址都是 0.0.0.0 或者空缺,回到配置里补地址再重启。

6.3 安全加固:别把摄像头直接暴露到公网

go2rtc 默认把 Web UI 和 RTSP 端口都监听在 0.0.0.0 上,这在内网没问题,但如果你有远程访问需求,直接把这几个端口映射到公网是非常危险的做法。1984 端口上没有任何认证机制,一旦暴露,任何知道地址的人都能看到你的摄像头画面,甚至能拿到流地址。

我推荐的方案是:1984 和 8554 只监听内网,远程访问统一走反向代理。用 Caddy 或者 Nginx 把外部 HTTPS 流量代理到内网的 1984 端口,并在反向代理层加上 Basic Auth 认证。下面是一个用 Caddy 的极简配置示例:

stream.example.com {
    basic_auth {
        admin $2a$14$xxxxxxxxxxxxxxxxxxxx
    }
    reverse_proxy 192.168.1.100:1984
}

这样浏览器通过 https://stream.example.com 访问时,先经过一层密码验证,再进入 go2rtc 的 Web UI。实际上 go2rtc 项目也在往这个方向努力,但依赖它自带认证还不如自己加反代来得稳妥。

摄像头侧的账号管理同样重要。不要用默认的 admin 密码,最好给每台摄像头单独建一个仅用于拉流的最低权限账号。在条件允许的情况下,把摄像头和日常上网设备放到不同的 VLAN 里,只开放必要的 RTSP/ONVIF 端口给 go2rtc 所在主机,这样就算某台摄像头固件有漏洞,攻击面也被控制在小范围内。

6.4 长期运行的一点维护经验

go2rtc 本身非常稳定,但只要跑监控,总归会碰到设备掉线、网络波动、磁盘写满这类和它无关的问题。我的经验是,定期做一次简单巡检比出问题再补救要省心得多。巡检内容就三件事:看 docker ps 确认容器存活,看 docker logs --since 24h 里有没有大量连接报错,再用 df -h 确认录像目录没有被写满。

录像文件写满导致磁盘满,是我见过最多的长期运行事故。如果录像需求固定,建议给媒体目录设置配额,或者启用 crontab 定期清理超过 N 天的文件。另外,摄像头掉线后 go2rtc 默认会自动重连,但如果你的摄像头 DHCP 租约到期换了 IP,重连也会失效。所以我一直建议摄像头全部设置固定 IP,哪怕内网用的是 DHCP 预留也行,否则流地址变了,系统还傻傻地连老地址。

还有一个小技巧是给 go2rtc 加健康检查。在一个轻量监控方案里,可以通过脚本每五分钟请求一次 http://127.0.0.1:1984/api/exit ,连续失败就触发告警,或者在 Docker compose 里直接配置 healthcheck 段让 Docker 判断容器健康状态。别小看这一步,它能让“摄像头看不了”这种事情从半夜被电话叫醒,变成第二天早上看到一条通知。

跑得久了你会发现,go2rtc 最大的价值不光是省心,而是它把视频流的接入和管理这件事做得极度简洁,简单到你可以把精力放在真正想做的事情上。就我个人实际使用而言,部署这套平台之后,我再也没为“这台摄像头用什么方式接、那条流该怎么推”这个问题操过心,剩下的时间和精力,都花在了自自动化告警和智能家居联动这种更有意思的事情上。

Logo

邀请您加入社区

更多推荐