ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Docker部署go2rtc:从RTSP到WebRTC的摄像头流媒体网关

Docker部署go2rtc:从RTSP到WebRTC的摄像头流媒体网关 1. 项目初衷与核心思路1.1 go2rtc 到底是干什么的如果你接触过摄像头接入多半经历过这种破事家里的老摄像头只支持 RTSP 协议想在网页上看一眼画面却发现浏览器原生根本不支持 RTSP想接进 Home Assistant插件告诉你要先转成 HLS想在手机 App 上低延迟预览又被告知需要 WebRTC。go2rtc 就是解决这类“协议乱炖”问题的。它是一个用 Go 写成的轻量流媒体服务器核心能力是把不同来源的流RTSP、RTMP、HLS、MJPEG、文件等拉进来再以多种协议输出出去。你给它一个 RTSP 摄像头地址它能自动给你生成 WebRTC、HLS、RTMP、MJPEG 等多种输出流。底层的 WebRTC 能力基于 Pion 实现所以浏览器端不需要任何插件打开网页就能低延迟看画面。这个项目最初是给 Home Assistant 玩家做摄像头低延迟预览用的后来因为简洁好用逐渐被更多人拿来当独立的流媒体网关。它还会自动发现局域网内支持 ONVIF 的摄像头省去手动逐个填写地址的功夫。1.2 为什么非要套一层 Docker有人会问go2rtc 本身就是一个单个可执行文件直接下载二进制放服务器上跑不就行了确实可以但用 Docker 部署有几个实实在在的好处尤其适合家庭或小型工作室的场景。第一是隔离干净。go2rtc 依赖 Go 运行时环境以及可能存在的 FFmpeg 转码功能。用容器把所有依赖打包好不污染宿主机卸载时一条命令就能清理干净。第二是升级方便。官方镜像更新频繁docker compose 里改一下 tag 再 up -d几秒钟完成升级。第三是配置统一。把 go2rtc.yaml 和 docker-compose.yml 放在同一个目录里整个服务可以随项目目录迁移换机器时拷贝过去就能跑。我自己的体会是容器化最大的价值是“心智负担低”。你不用记得这个服务的可执行文件放在哪个目录、环境变量怎么配、日志在哪儿看一切都被 Docker 的约定固化下来了。2. 环境准备与基础概念2.1 装好 Docker 基础环境开始部署之前先把 Docker 环境准备好。如果你是在 Linux 服务器上操作以 Debian/Ubuntu 为例安装命令一般是sudo apt update sudo apt install docker.io docker-compose-v2 sudo systemctl enable --now docker如果是 Windows 或 macOS直接安装 Docker Desktop注意在设置里开启 WSL2 / Hyper-V 虚拟化支持。如果安装完提示 virtualization support not detected基本就是 BIOS 里的虚拟化没打开进 BIOS 开启 Intel VT-x 或 AMD-V 即可。这里我建议直接把 Docker Compose 一起装上因为后面我们会用 docker compose 来编排服务。别用旧版的 docker-compose带横杠了v2 版本的 compose 插件功能更全语法也更标准。装完验证一下docker version docker compose version能正常打印出版本信息说明环境没问题。2.2 镜像选型与版本策略go2rtc 官方维护的容器镜像在 GitHub Container Registry拉取地址是ghcr.io/alexxit/go2rtc:latest如果你在国内服务器上拉取 GitHub 的镜像比较慢可以配置 Docker 的 registry-mirrors 使用国内加速源或者在 Docker Hub 上找第三方转存的镜像。不过我更推荐直接用 ghcr.io 官方源毕竟第三方镜像的更新时效性和安全性都没法完全保证。版本策略上家庭自用场景我通常直接拉 latest。这个项目发版很活跃latest 基本等于最新的稳定版。如果你对稳定性要求高可以指定具体版本号比如 ghcr.io/alexxit/go2rtc:v1.9.8升级时手动改版本号。我个人习惯在 compose 文件里写成 latest 或大版本 tag方便自动拿到新功能。有一个小坑值得提一下不同版本的 go2rtc 配置文件字段有过调整。如果你是老版本升级上来建议升级后先看一眼 go2rtc 的 docs确认配置项没有被废弃避免启动时报错。3. 实操部署docker compose 搭建 go2rtc 服务3.1 端口和目录规划go2rtc 主要监听三个端口1984/TCPWeb 管理界面和 API浏览器访问 http://IP:1984 就能看到所有流的状态和画面。8554/TCP内置的 RTSP 服务端口用于对外提供 RTSP 输出流。8555/TCPUDPWebRTC 的媒体端口浏览器和服务器之间通过它传输音视频数据。如果你还需要把流推给其他 RTMP 服务或者接收 RTMP 输入可以额外映射 1935 端口。不过默认场景下这三个端口就够了。目录结构我习惯这样规划/home/ubuntu/go2rtc/ ├── docker-compose.yml └── config/ └── go2rtc.yaml把配置文件放在宿主机上容器内挂载到 /config 目录。这样备份配置、修改配置都非常直观不用进容器操作。3.2 编写 docker-compose.yml直接上完整配置services: go2rtc: image: ghcr.io/alexxit/go2rtc:latest container_name: go2rtc restart: unless-stopped network_mode: bridge ports: - 1984:1984/tcp - 8554:8554/tcp - 8555:8555/tcp - 8555:8555/udp volumes: - ./config:/config command: - -c - /config/go2rtc.yaml environment: - TZAsia/Shanghai几个关键点我逐一说明。restart: unless-stopped保证服务器重启后服务自动拉起摄像头流掉线后也会自动重连。network_mode: bridge是默认模式配合显式的端口映射来暴露服务。.config目录挂载到/config然后在 command 里用-c参数指定配置文件路径这是最稳妥的方式——go2rtc 在某些环境下默认配置文件查找路径很玄学直接在启动参数里指定就完全不会有找不到配置的问题。TZAsia/Shanghai设置时区主要影响日志时间戳和后续可能的定时功能。看日志时如果发现时间对不上大概率就是忘了设置时区。3.3 启动、验证与开机自启配置写好后启动服务cd /home/ubuntu/go2rtc docker compose up -d第一次启动会拉取镜像耐心等一会儿。启动完成后看容器状态docker compose ps docker logs go2rtc正常情况下日志末尾会出现类似这样的内容INFO go2rtc: starting config/config/go2rtc.yaml INFO api: listen0.0.0.0:1984 INFO rtsp: listen0.0.0.0:8554 INFO webrtc: listen0.0.0.0:8555此时浏览器访问http://服务器IP:1984应该能看到 go2rtc 的管理界面。界面上会显示当前的流列表、摄像头在线状态以及各种协议的播放地址。这一步能正常打开说明容器跑通了。开机自启不用额外配置因为restart: unless-stopped已经覆盖了这个场景。你只需要确保 Docker 服务本身是开机自启的也就是前面提到的systemctl enable docker。4. 摄像头接入配置从 RTSP 到多协议输出4.1 RTSP 摄像头源配置go2rtc 的摄像头源配置写在 go2rtc.yaml 里。最基本的配置是定义一个流名然后指向摄像头的 RTSP 地址streams: cam_backyard: rtsp://admin:password192.168.1.50:554/Streaming/Channels/101这里有几个容易踩坑的地方。第一不同品牌的摄像头 RTSP 地址路径完全不同。海康威视一般是/Streaming/Channels/101大华是/cam/realmonitor?channel1subtype0TP-Link 又是一种。建议先用 VLC 或 ffprobe 在电脑上测试一下确认地址能出画面再写到配置里否则就是来回试错。第二用户名密码中如果包含特殊字符比如、:、#必须做 URL 编码。比如密码是admin:123RTSP 地址里的密码部分要写成admin%3A123否则地址解析会出错表现为一直连接不上或者反复提示认证失败。配置多个摄像头时逐个添加即可streams: cam_backyard: rtsp://admin:password192.168.1.50:554/Streaming/Channels/101 cam_front: rtsp://admin:password192.168.1.51:554/cam/realmonitor?channel1subtype0配置修改后不需要重启容器go2rtc 会自动热加载配置文件。这一点非常方便我经常改一行配置然后刷新页面就能看到效果。4.2 多协议输出链路摄像头源配置好之后go2rtc 会自动生成多种协议的播放地址。在 Web 管理界面的流详情里你可以看到该流对应的 WebRTC、HLS、RTSP、MJPEG 等地址。以名为cam_backyard的流为例输出地址分别是这样WebRTChttp://服务器IP:1984/api/webrtc?srccam_backyardHLShttp://服务器IP:1984/api/hls/cam_backyard.m3u8MJPEGhttp://服务器IP:1984/api/mjpeg?srccam_backyardRTSPrtsp://服务器IP:8554/cam_backyardRTMPrtmp://服务器IP:1935/cam_backyard这套多协议输出是整个方案的核心价值。摄像头本身只支持 RTSP但经过 go2rtc 中转后iOS 端可以走 HLS浏览器可以走 WebRTC 低延迟预览NVR 录制可以走 RTSP 或 RTMP老旧系统可以走 MJPEG。一个流源头多种消费场景完全不用为每种场景单独搭一套转码服务。实际测试下来WebRTC 模式在局域网内端到端延迟一般能控制在 100 到 300 毫秒以内这是看云台控制或实时门铃的理想效果。HLS 延迟一般在 2 到 5 秒适合手机端的稳定预览。4.3 特殊源FFmpeg 拉流、本地文件和音频流go2rtc 不只是支持 RTSP 摄像头还能接入一些特殊来源。遇到某些格式刁钻的摄像头比如私有协议或者编码格式是 MJPEG over RTSPgo2rtc 原生解析可能不干净。这时可以用 FFmpeg 方式拉流只要在源前面加ffmpeg:前缀streams: cam_weird: ffmpeg:rtsp://admin:password192.168.1.60:554/stream1#videocopy#audiocopy#videocopy#audiocopy的含义是视频和音频都不要重新编码只做封装转换CPU 开销非常小。只有当源格式和目标格式确实不兼容时才去掉 copy 参数交给 FFmpeg 转码那会比较吃 CPU。本地视频文件也可以作为输入源适合做测试streams: test_loop: file:///media/test.mp4甚至麦克风、音频流也可以通过 go2rtc 转发。总之只要能拿到流go2rtc 都能帮你转发成需要的输出协议。5. 常见问题与排查实录5.1 端口被占用导致服务启动失败新部署时最常遇到的是端口冲突。如果你服务器上已经有其他服务占用了 1984 或 8554go2rtc 会启动失败日志里会明确提示address already in use。排查方法很简单sudo lsof -i :1984 sudo netstat -tlnp | grep 8554找到占用端口的进程后要么停掉旧服务要么修改 go2rtc 的监听端口。改端口时要注意go2rtc.yaml 里可以这样覆盖默认端口api: listen: :1985 rtsp: listen: :8555 webrtc: listen: :8556改完之后docker-compose.yml 里的端口映射也要同步修改。5.2 摄像头认证失败或拉流超时这一类问题在日志里的表现是unauthorized或connection timeout。我的排查顺序是这样的先用 VLC 或者命令行工具在宿主机上直接测试源地址。注意是从宿主机测试不是从容器内测试这样可以快速定位是摄像头拒绝认证还是容器网络访问不到摄像头。ffprobe -rtsp_transport tcp -i rtsp://admin:password192.168.1.50:554/Streaming/Channels/101如果 ffprobe 能出流信息说明地址没问题问题出在容器到摄像头的网络上。最常见的原因是 Docker 容器默认用的 bridge 网络如果摄像头限制来源 IP或者摄像头在一个单独的 VLAN 里容器就可能访问不到。解决方式是把容器网络改成 host 模式或者把摄像头网段接入到 Docker 网络中。如果 ffprobe 直接提示认证失败那就是用户名密码或路径的问题。密码里带特殊字符的话优先检查 URL 编码是否做了。5.3 WebRTC 画面黑屏、一直转圈这是 Docker 部署 go2rtc 最经典的坑。现象是 Web 管理界面能看到流点击播放后黑屏或一直转圈控制台报 ICE 连接失败。原因在于 WebRTC 的候选地址机制。go2rtc 在容器内运行时默认会向浏览器报告容器内部 IP 作为媒体传输候选地址但浏览器访问不了容器的内网 IP连接自然建立不起来。解决方法是显式配置 WebRTC 候选地址指向宿主机局域网 IP 或公网 IPwebrtc: listen: :8555 candidates: - 192.168.1.10:8555这里的 192.168.1.10 是你的宿主机局域网 IP。如果服务器有公网 IP且端口已映射到公网也可以写公网 IP。配置完成后重启服务再测试 WebRTC 播放就能秒开。这个坑我踩过一次之后深刻理解了 WebRTC 的 NAT 穿透逻辑。docker compose 的端口映射对普通 TCP 服务没问题但 WebRTC 需要的是“媒体地址要能被对端直接访问”所以必须手动手写候选地址。5.4 CPU 和内存占用突然飙高go2rtc 本身非常轻量纯转发模式下 CPU 占用几乎可以忽略。如果你发现 CPU 占用异常大概率是某个流在转码。转码的原因通常是源编码格式和目标协议不匹配比如篮球场摄像头输出的是 H.265但某些浏览器不支持 H.265 解码go2rtc 就会自动转成 H.264。我的建议是尽量让摄像头输出 H.264。如果摄像头只支持 H.265再考虑在 go2rtc 里开启转码。转码时可以设置合理的分辨率和码率streams: cam_265: ffmpeg:rtsp://admin:password192.168.1.70:554/stream1#videoh264#width1280#height720#bitrate2500内存方面如果同时预览的路数很多go2rtc 缓存区会占用一定内存。一般家庭十几个摄像头1G 内存绰绰有余。下面表格汇总这几个常见问题现象常见原因排查方向启动失败报 address in use端口被占用lsof / netstat 查端口拉流失败 unauthorized用户名密码或地址编码错误用 ffprobe 单独测试源地址拉流超时 timeout容器无法访问摄像头网段检查 docker 网络必要时改 host 模式WebRTC 黑屏转圈缺少有效的 ICE 候选地址配置 webrtc.candidates 指向宿主机 IPCPU 飙高发生不必要转码检查源编码格式优先 H.264 copy6. 进阶扩展与个人心得6.1 接入 Home Assistant 的快捷方式如果你在用 Home Assistantgo2rtc 接入其实是零成本的因为 Home Assistant 的 Stream 组件本身就推荐搭配 go2rtc 使用。你可以在 Home Assistant 的 configuration.yaml 里配置stream: source: rtsp://192.168.1.10:8554/cam_backyard这样 HA 所有依赖 stream 组件的功能比如手机 App 推送、录音、自动化触发都会通过 go2rtc 来取流延迟和稳定性比直接连摄像头 RTSP 地址好得多。6.2 配合 Frigate 做 NVRgo2rtc 和 Frigate 的关系更紧密。新版本 Frigate 内嵌了 go2rtc作为摄像头接入和预览的前置层。如果你已经有独立的 go2rtc 实例可以直接让 Frigate 连你的 go2rtc避免重复拉流go2rtc: host: 192.168.1.10 port: 1984这种架构的好处是Frigate 做 AI 检测和录制go2rtc 负责低延迟预览各司其职还能省掉摄像头侧的多路并发压力。6.3 我自己用的这套方案的体会我在家里部署这套 go2rtc 已经跑了两年多期间经历过一次 Docker 版本大升级也换过两三次摄像头总体体验非常稳定。最初我直接用 docker run 跑后来改成 docker compose 管理再后来把配置拆出来挂载到宿主机整个管理变得越来越顺手。有一点感触比较深这套方案最值钱的地方不在多协议转换本身而在于它把摄像头接入的“最后一公里”统一了。以前每接一个新摄像头都要重新折腾一遍协议对接现在只需要把 RTSP 地址加进 yaml然后所有下游应用都自动能用了。这种“一次接入处处可用”的体验是 go2rtc 最吸引我的地方。如果你刚开始搭摄像头流媒体平台或者正在被哈苏、WebRTC、HLS 各种协议兼容问题搞到头大建议直接照着上面的配置试一遍。从 docker compose 启动到第一个摄像头出画面整个过程半小时就能搞定剩下的就是根据自己的场景慢慢调优参数了。
返回列表