Docker部署go2rtc:统一接入RTSP摄像头,实现浏览器WebRTC低延迟预览
2026/9/16 5:33:49 网站建设 项目流程

搞监控项目、做智能家居,或者单纯想在网页里看看自家摄像头的朋友,应该都体会过接入设备有多烦。手头三五个摄像头,海康的、大华的、杂牌的,RTSP 地址一家一个格式,浏览器又原生不支持 RTSP,想在网页里低延迟观看还得装插件、装客户端,体验稀碎。go2rtc 这个轻量级流媒体网关,就是专门解决这类问题的:它能把 RTSP、RTMP、HLS、MJPEG、WebRTC 这些五花八门的协议统一管理起来,尤其在浏览器低延迟预览摄像头这一块,体验比很多商业平台还顺滑。今天我用 Docker 把整套服务跑起来,从镜像加速、容器部署到多品牌摄像头接入,完整走一遍,顺便把踩过的坑都整理出来,照着抄就行。

1. 为什么需要 go2rtc:摄像头接入的协议困局

先把场景说清楚。绝大多数网络摄像头都支持 RTSP 协议,但 RTSP 是个“老古董”,它自己跑在 554 端口上,用的是 RTP/UDP 传输,浏览器不做特殊处理根本播不了。于是各家厂商就搞出了自己的客户端,或者要求装 Web 插件,海康的 web 插件、大华的 web 插件,换台电脑、换个浏览器又要重装一遍,烦得不行。再往后,HLS 和 RTMP 慢慢变成网页播放的主流,但 HLS 延迟高,RTMP 又是 Flash 时代的遗留产物,现代浏览器一样不原生支持。真正适合摄像头实时预览的,其实是 WebRTC——延迟能做到 500ms 以内,浏览器原生支持,不需要任何插件。麻烦的是,市面上几乎没有摄像头原生支持 WebRTC。

1.1 摄像头生态的碎片化现状

先看一组我日常打交道的设备。海康威视的 RTSP 地址长这样:rtsp://admin:password@192.168.1.64:554/Streaming/Channels/102,这个/102表示通道 1 的子码流,如果你想要主码流就得写/101。大华的地址格式又不一样,走的是rtsp://admin:password@192.168.1.65:554/cam/realmonitor?channel=1&subtype=1。TP-LINK 是rtsp://user:pass@ip:554/stream1。杂牌摄像头更是百花齐放,有的还要自己去 ONVIF 探测设备才知道真实地址。

海康大华这些设备,虽然也都支持 ONVIF 标准,但 ONVIF 主要管设备发现、云台控制这些“管理面”,真正的视频流还是要靠 RTSP 拉。再加上很多摄像头支持 H.265 编码,浏览器对 H.265 的 WebRTC 支持又很差,这就带来了第二个问题:就算你拿到了 RTSP 地址,也没法直接在网页里看。所以实际做项目时,通常需要一层“协议转换中间层”,把摄像头吐出来的 RTSP 流,转成浏览器能直接消费的协议,再扔给前端播放器。

1.2 go2rtc 的核心价值:一个入口、全协议转换

go2rtc 就是干这个的。它最初在 Home Assistant 社区里火起来,因为 Home Assistant 的 WebRTC 摄像头组件就想找一个能把 RTSP 转 WebRTC 的工具。后来大家发现这个工具单独拿出来也特别好用,慢慢就变成独立部署的流媒体网关。

它的核心逻辑很简单:你给它一堆视频源地址,它统一拉流、统一管理,然后对外提供多种输出协议。你可以用 WebRTC 在浏览器低延迟观看,也可以用 HLS 或者 MJPEG 给老系统、低性能设备用,还可以把它当作 RTSP 服务器,让 NVR 录像机来拉流。整个服务是 Go 写的,单二进制文件就能跑,内存占用极低,跑在树莓派、NAS、或者一台 1 核 1G 的小云主机上都毫无压力。这跟动不动就要几个 G 内存的完整流媒体服务器(比如 MistServer、ZLMediaKit)相比,轻量太多了。

1.3 适用场景和整体架构

这套方案适合谁?我自己归纳下来主要是三类:第一类是家里有摄像头、想在浏览器或手机上看实时画面的玩家;第二类是在做智能家居集成、想把摄像头统一接进 Home Assistant 或者其他平台的开发者;第三类是做小型安防项目、需要给客户提供网页端实时预览但又不想买商业平台的工程商。图像识别、巡检机器人、智能车这些项目里的摄像头画面,如果也需要通过网页低延迟查看,同样用得上。

整体架构就是一条单向链路:摄像头 → RTSP/ONVIF → go2rtc → WebRTC/HLS/MJPEG → 浏览器。go2rtc 在这条链路里相当于一个网关,不存录像、不做推流分发(虽然它也支持),核心职责是解协议、转协议。接下来就用 Docker 把这层网关搭起来。

2. Docker 环境准备与镜像加速

go2rtc 支持多种安装方式,官方甚至提供了 Windows 和 macOS 的桌面版,但我要重点讲 Docker 部署,原因有两个:一是 Docker 把运行环境隔离得干干净净,升级、回滚、迁移都方便;二是国内摄像头的网络环境比较特殊,go2rtc 有时候要跟摄像头所在网段通信,Docker 的网络模式可以灵活调整。部署前先把两个前置条件确认清楚。

2.1 前期准备:Docker 与 Compose

机器上得先有 Docker 和 Docker Compose 插件。Linux 服务器一般一条命令装 Docker,然后用docker compose version确认 Compose 可用。Windows 和 macOS 用户直接装 Docker Desktop 就行,注意开启 WSL2 或 Hyper-V 后端。有一点要提醒:如果用的是 Docker Desktop 的 Windows 环境,go2rtc 的容器网络会走 NAT,和摄像头通信时要注意网段问题,Linux 环境可以开 host 网络模式,少很多麻烦。

检查完版本之后,我习惯先建一个独立的目录,把配置文件和容器绑定的目录都放进去,这样后面备份、迁移都很清晰:

mkdir -p /opt/go2rtc cd /opt/go2rtc

这个目录在启动容器时会挂载进容器内部,config 文件、日志、临时文件都在里面,不会污染宿主机。

2.2 镜像拉取与加速配置

说句实话,go2rtc 的镜像本身很小,但国内拉 Docker Hub 镜像排队的情况大家也懂,有时一条docker pull alexxit/go2rtc能卡十分钟,进度条纹丝不动。这不是网络故障,是镜像仓库的连通性问题,解决办法是给 Docker 配置镜像加速器。

打开/etc/docker/daemon.json(Windows 下是 Docker Desktop 的设置界面),把加速地址写进去:

{ "registry-mirrors": [ "https://docker.m.daocloud.io", "https://hub-mirror.c.163.com", "https://mirror.ccs.tencentyun.com" ] }

改完重启 Docker:

sudo systemctl restart docker

加速地址的可用范围变化很快,如果发现某个地址失效,直接删掉换成新的就行。如果是在云厂商的服务器上,优先去控制台拿他们提供的专属加速地址,稳定性和速度都是最好的。

2.3 两种部署方式:docker run 与 docker compose

go2rtc 官方镜像叫alexxit/go2rtc,部署方式有两种。第一种是三行命令快速启动:

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

端口说明:1984 是 Web 管理界面和 API 端口,WebRTC 播放会用到;8554 是 go2rtc 自带的 RTSP 服务端口;8555/UDP 是 WebRTC 的媒体通道端口。容器启动后,打开http://服务器IP:1984就能看到管理界面。

第二种是用 Compose 文件,适合需要长期维护、配置较多的情况。先写一个docker-compose.yml

services: go2rtc: image: alexxit/go2rtc container_name: go2rtc restart: unless-stopped network_mode: host volumes: - /opt/go2rtc/go2rtc.yaml:/config/go2rtc.yaml

注意这里我用的network_mode: host,也就是直接把容器网络挂在宿主机上,go2rtc 监听端口和访问摄像头都像在宿主机本地操作一样。好处很明显:WebRTC 的 UDP 端口不用一个个映射,摄像头如果和宿主机在同一网段,通信毫无障碍。但 host 模式在 Docker Desktop 的 Windows/Mac 上支持不完整,所以这两个平台还是用第一种docker run-p映射端口的方式。

启动命令:

docker compose up -d

跑起来之后先看下日志,确认没有报错:

docker logs -f go2rtc

正常的话日志里会打印出监听端口和 WebRTC 初始化信息,然后浏览器访问管理界面就能看到 go2rtc 的首页。

2.4 配置文件和启动验证

go2rtc 的配置文件是 YAML 格式,默认路径在容器内的/config/go2rtc.yaml。首次启动时如果文件不存在,go2rtc 会自动创建一个带默认配置的文件出来。我习惯先手动建好,把基础的logwebrtc配置放进去:

log: level: info webrtc: listen: ":8555"

log.level默认是 info,调试的时候可以改成 debug,能打印出每个流的详细状态。webrtc.listen指定媒体端口,保持和 Docker 映射的 8555/udp 一致即可。

配置好之后,在管理页面右上角应该能看到 go2rtc 的版本号和服务状态。到这里部署环境就算搭好了,下一节开始接入摄像头。

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

go2rtc 接入视频源的核心就是配置文件的streams字段,结构很简单:key: value,key 是你给这个流起的名字,value 是视频源地址。可以写 RTSP、RTMP、HLS、HTTP-FLV、MJPEG 地址,也可以用ffmpeg:前缀让内置 FFmpeg 拉本机摄像头或其他设备。下面从协议选型开始讲,再把海康大华这类常见设备的配置挨个过一遍。

3.1 常见视频流协议及其适用场景

开始配之前,先花一分钟理清这些协议之间的关系,选错了后面会走很多弯路。

协议传输方式延迟浏览器支持适用场景
RTSPTCP/UDP + RTP200ms 级不支持原生播放摄像头/录像机首选协议
RTMPTCP1-3s不支持原生播放推流、老旧系统兼容
HLSHTTP + TS 切片5-15s原生支持(iOS/Android)移动端、大范围分发
WebRTCUDP + SRTP<500ms原生支持浏览器端低延迟实时预览
MJPEGHTTP + JPEG 帧200-500ms标签原生支持低端设备、嵌入式页面

你可能会问:为什么不直接把摄像头接到 NVR 录像机,再用 NVR 的客户端看?因为 NVR 的客户端大多要求装插件,或者只支持自家生态,无法统一接入多品牌设备。go2rtc 的意义就在于“桥接”:RTSP 进来,WebRTC 出去,浏览器零插件直接看。

3.2 海康、大华等摄像头接入配置

下面用实际的配置文件演示。假设我有两个摄像头,一台海康、一台大华,把它们接入 go2rtc:

streams: hik_front: - rtsp://admin:password@192.168.1.64:554/Streaming/Channels/101 hik_front_sub: - rtsp://admin:password@192.168.1.64:554/Streaming/Channels/102 dahua_entrance: - rtsp://admin:password@192.168.1.65:554/cam/realmonitor?channel=1&subtype=1

这里有几个经验要点。第一,海康的 URL 中/101是通道 1 主码流,/102是通道 1 子码流。主码流分辨率高、码率高,用于录像存储;子码流分辨率低、码率低,用于实时预览。我建议在 go2rtc 里尽量用子码流预览,因为 WebRTC 走 UDP,高码率在主码流上容易引起卡顿;如果你需要观看清晰画面,那就用主码流,但要保证摄像头到 go2rtc 主机的网络带宽足够。

第二,大华的 URL 里subtype=1表示子码流,subtype=0是主码流。它家早期有些固件对 URL 长度和特殊字符比较挑剔,如果发现拉流失败,优先检查?&有没有被 YAML 转义。YAML 里这么长的地址我一般直接加引号包起来,避免特殊字符解析出错。

第三,如果你手头的摄像头品牌比较偏,不确定 RTSP 地址格式,可以用 ONVIF 探测。go2rtc 的 Web 管理界面上有一个添加源的功能,输入摄像头 IP、用户名、密码,它可以直接用 ONVIF 协议发现设备并自动生成拉流地址,省去手动拼 URL 的麻烦。

配置修改完,在 Web 管理界面上刷新一下,hik_frontdahua_entrance这些流应该都能看到预览画面。go2rtc 界面自带播放器,点进任意一个流就能直接播放,同时有 WebRTC 和 HLS 两个播放选项。

3.3 浏览器低延迟预览:WebRTC 登场

如果只是能在页面上看到画面,其实传统方案也能做到,go2rtc 真正拉开差距的是 WebRTC 预览。在管理界面点击流的 WebRTC 播放,实测延迟可以做到 300ms 左右,基本是“所见即所得”,云台转动、人走过来,几乎感觉不到延迟。这对于远程看门口快递、看车间设备状态、看宠物,体验比 HLS 那种 5 秒起步的延迟强太多。

WebRTC 的原理简单说就是:浏览器和 go2rtc 之间建立一个基于 UDP 的加密媒体通道,视频帧以极低延迟实时传输。但 UDP 穿透 NAT 是个常见问题——如果你的 go2rtc 部署在带防火墙的服务器上,需要确保 UDP 端口 8555 是开放的。WebRTC 传输失败最常见的表现是:管理界面能看到流信息,但点播放一直转圈。排查思路是先到浏览器开发者工具的 Console 里看有没有 ICE 错误,如果没有明显的报错,大概率是 UDP 端口被防火墙拦截了,放行 8555/udp 就好。

3.4 扩展玩法:OBS、USB 摄像头与 Home Assistant

go2rtc 不止能接网络摄像头。如果你有一个 USB 摄像头或者树莓派的 CSI 摄像头模块,可以用内置 FFmpeg 把它拉进流媒体服务:

streams: usb_cam: - ffmpeg:/dev/video0

/dev/video0是 Linux 系统里 USB 摄像头对应的设备文件。这个特性在做智能小车、桌面监控、视频会议实验的时候特别好用,不需要单独跑一套 FFmpeg 转流程序,go2rtc 全部接管。

另一个玩法是配合 OBS。OBS 可以抓取 go2rtc 输出的 RTMP 或 WebRTC 流作为素材,比如把摄像头画面拉进 OBS 场景里做推流;反过来,OBS 虚拟摄像头的输出也可以通过 RTMP 推到 go2rtc,统一供给其他平台使用。这种“互相嵌套”的组合在直播和多平台分发场景中非常灵活。

如果玩 Home Assistant,go2rtc 更是原生集成。在 Home Assistant 的配置里把 go2rtc 地址填进去,所有接入的摄像头直接变成 HA 里的 camera 实体,再配合自动化规则,比如检测到人移动就推送 WebRTC 画面到手机端,流畅度和体验都很好。这也是我最初接触这个项目的原因。

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

Docker 部署 go2rtc 整体不复杂,但实际跑起来,总会在某个环节踩一两个坑。我把这段时间遇到过的典型问题整理成速查表,再逐个展开讲。

现象可能原因解决办法
镜像拉取慢或超时Docker Hub 连通性差配置镜像加速器,重启 Docker
管理界面打不开容器没起来,或端口冲突docker logs go2rtc看日志,改端口
WebRTC 无法打开UDP 端口未开放放行 8555/udp,或改用 host 网络
点击播放黑屏但卡住H.265 编码浏览器不支持用子码流,或配置 FFmpeg 转 H.264
音频没有声音PCM 编码浏览器不支持加装转码为 Opus 的 FFmpeg 配置
摄像头拉流闪断摄像头并发拉流受限减少预览路数,或降低码率
画面卡顿严重码率过高或网络带宽不足改用子码流,降低分辨率

4.1 搭建与访问类的典型问题

先讲镜像拉取的问题。docker pull alexxit/go2rtc卡住不动,大概率是没配置镜像加速。这不是网络故障,而是 Docker 默认访问 Docker Hub 的链路在国内不稳定。配置好daemon.json里的镜像地址后,拉取速度快很多。还有一个临时技巧:如果docker pull长时间没反应,按Ctrl+C取消,重新执行一次,有时第二次会走另一个解析结果。

容器跑起来但页面打不开,先别急着改配置,直接看日志最有效:

docker ps -a docker logs go2rtc

日志里如果显示bind: address already in use,说明 1984 端口被其他程序占了。这种情况我遇到过两次,一次是机器上有其他 web 服务占用了端口,另一次是之前误开了多个容器。解决办法是停掉旧的容器,或者把宿主机的映射端口改成别的,比如-p 1985:1984

4.2 画面、协议与兼容性问题

接入摄像头之后发现画面黑屏但播放器不报错,这是最常见的兼容性问题。90% 的情况是编码格式问题:摄像头主码流默认输出 H.265,浏览器 WebRTC 对 H.265 的支持极差,黑屏是必然的。最简单的方案是让 go2rtc 用子码流拉流——子码流一般默认是 H.264。如果你确实需要高画质,那就得让 go2rtc 内置 FFmpeg 做硬转码,把 H.265 转成 H.264:

streams: hik_front_h264: - ffmpeg:rtsp://admin:password@192.168.1.64:554/Streaming/Channels/101#video=copy#audio=copy

但转码非常吃 CPU,1 路 1080p 转码差不多要占满 1-2 个核,部署机配置不够的话,转两路就会明显卡顿。所以我的原则是:能走子码流就不转码,必须转码就上硬件的显卡加速,软件转码只是兜底方案。

还有一个容易混的问题,就是“大华摄像头一直提示下载插件”那种与浏览器相关的弹窗。直接用浏览器打开大华摄像头的管理页面,经常会被要求装插件。这是摄像头厂商自己的网页问题,不是 go2rtc 的问题。把大华摄像头接入 go2rtc 后,在浏览器里看的是 go2rtc 的页面,跟摄像头自带的 Web 页面没有任何关系,插件完全不用装。这也算 go2rtc 绕开厂商限制的一个额外好处。

4.3 录像与存储规划的实用建议

很多人部署完 go2rtc,下一步就想接到 NVR 录像。这里分享一个存储规划经验,正好对应“海康录像机设置老摄像头存储大文件大的话怎么弄”这类问题。

首先要理解录像文件“大”的本质:录像文件大小 = 码率 × 时间。码率越高,画面越清楚,文件也越膨胀。比如一台 400 万像素摄像头,主码流码率约 8Mbps,一天 24 小时录像大概是8Mbps ÷ 8 × 3600 × 24 = 86GB(换算成字节),一片 4TB 硬盘也就能存 45 天左右。如果换成子码流,码率降到 2Mbps,同样一块硬盘能存 4 个月。所以存储规划的第一原则是:录像存主码流,保证取证清晰度;预览走子码流,保证流畅不卡顿。

NVR 接入多品牌摄像头时,要手动添加设备 IP,并在摄像头端开启 RTSP/ONVIF 协议。如果摄像头和 NVR 不在一个网段,先解决网络路由问题,再在 NVR 里添加对应网段的摄像头 IP,同时留意摄像头 ONVIF 账号权限是否开放。老摄像头固件如果一直找不到流,去摄像头官网升级一下固件,或者在大华/海康的 SADP 工具里改一下 ONVIF 端口,通常能解决。

最后说一个我在实际项目中养成的习惯:部署 go2rtc 时,先在配置文件里分好“组”,把不同用途的摄像头用不同名字标记,比如front_doorwarehouseparking_lot,而不是cam1cam2。名字起得好,后面接 Home Assistant、做自动化、甚至对接 NVR 的时候,一眼就能看出哪路是哪台设备,排查问题会省很多时间。

这套 Docker + go2rtc 的方案我用了一年多,从最初只是想在家里的浏览器上看摄像头,到现在做成了一套可以交付给客户的小型安防预览系统,整体非常稳定。最后再分享一个小技巧:go2rtc 管理界面上的流列表里,每个流旁边有一个调试按钮,点进去能看到源地址连接时间、码率、丢包率这些实时数据。出现问题的时候,先看这个界面的数据,再决定是网络问题、编码问题还是设备问题,比盲目改配置高效得多。如果你也因为摄像头协议太乱、网页播放卡顿而头疼,照着这篇文章把 go2rtc 跑起来,应该能省下一大半折腾的时间。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询