我刚用 Docker 把 SRS 流媒体服务器从头到尾部署了一遍,整个流程比想象中顺畅太多。今天把完整过程写出来,包括我踩过的坑、调过的参数、验证过的推拉流路径,一次性讲清楚。不管你是想自建直播服务、做视频监控平台、还是搞 WebRTC 低延迟通话,这篇文章都能帮你少走弯路。
SRS 全称是 Simple Realtime Server,目前已经是 4.0 版本,一个非常成熟的开源实时音视频服务器。它原生支持 RTMP、HTTP-FLV、HLS、WebRTC、SRT、GB28181 等一堆协议,意味着你可以用它接收 OBS 的 RTMP 推流,也可以让浏览器通过 WebRTC 直接连上来低延迟观看,甚至对接海康、大华摄像头做 GB28181 国标接入,能力覆盖得非常广。
用 Docker 部署 SRS 最大的好处,就是不用自己折腾编译环境、依赖库和系统服务配置。SRS 源码编译并不算轻松,依赖关系多,参数调起来也麻烦,而官方 Docker 镜像把这些脏活累活都处理好了。你只需要把镜像拉下来,把配置文件和端口对好,一条命令就能启动一个功能完整的流媒体服务,这对快速验证场景和生产环境落地都很友好。
1. 部署前必须搞清楚的事
动手之前,我建议你先想明白自己到底要用 SRS 做什么,这直接决定你选哪个镜像版本、开哪些端口、用哪种配置模板。
1.1 SRS 能解决什么问题
SRS 本质上是一个媒体分发中枢。你可以把摄像头、电脑屏幕、手机画面推到 SRS 上,SRS 再把这些流转换协议、分发到不同的终端。它解决的几个核心痛点,我用自己的话总结一下:
第一,协议转换。推流端通常用 RTMP,因为 RTMP 在复杂网络下更稳定,但浏览器原生不支持 RTMP。SRS 收到 RTMP 流后,可以转成 HTTP-FLV 或 HLS 给浏览器播放,这就打通了采集端和播放端之间的协议壁垒。第二,低延迟分发。如果做直播连麦、远程操控这种场景,延迟必须控制在几百毫秒以内,SRS 的 WebRTC 能力就是干这个的,配合 WHIP/WHEP 协议可以轻松实现浏览器直接推拉流。第三,多协议覆盖。一套服务同时支持 HLS 切片用于 Apple 生态播放器,支持 SRT 协议用于弱网环境下的稳定传输,支持 GB28181 用于安防摄像头接入,相当于一台设备顶多台专用服务器。
1.2 Docker 部署相对于源码编译的优势
我之前在 CentOS 上源码编译过 SRS,印象太深刻了。依赖下载慢、编译时间动辄半小时起步、不同系统之间的兼容性问题折磨死人。后来切到 Docker 部署,最直观的感受就是:版本切换变得非常简单,今天用 4.0.2 验证功能,明天换成 5.0 版本做测试,改个镜像标签就行,宿主机上一点残留都不会有。
另外 Docker 对系统环境是隔离的。SRS 运行时依赖特定的 glibc、openssl 库版本,如果用源码编译,这些依赖可能和系统上的其他应用产生冲突。容器化之后,所有的依赖都封装在镜像里,和宿主机环境解耦,安全性也更高,不会因为 SRS 的某个配置失误直接破坏宿主机的网络栈。
1.3 确定你的使用场景和性能预期
SRS 的性能和你的硬件配置、网络带宽强相关。单核 CPU、1GB 内存的小鸡鸡跑一个转发 RTMP 到 HLS 的小型直播场景,几十路并发没问题。但如果要做 WebRTC 大规模会议,就需要多核 CPU 和充足的内存,因为 WebRTC 的编码交换非常吃 CPU 资源。
我这次部署的目标场景是:OBS 推 RTMP 流,经过 SRS 转成 HTTP-FLV 和 HLS,用于网页和手机端播放,同时验证 WebRTC 低延迟播放路径。所以我选的是 SRS 4.0 稳定版镜像,端口规划上预留了 1935(RTMP)、8080(HTTP API 和 HTTP-FLV)、1985(HTTP API)、8000(WebRTC over UDP)。如果你还要做 GB28181,得额外开放 9000 端口给 SIP 信令用。
注意:Docker 端口映射有一个容易忽略的坑,WebRTC 是 UDP 协议,必须在 docker run 或者 docker-compose 里同时映射 UDP 端口,只映射 TCP 端口的话,WebRTC 推拉流会失败。
2. 环境准备与镜像拉取
这次部署我用的是一台 2 核 4G 的云服务器,操作系统是 Ubuntu 22.04,Docker 版本是 24.0.5。下面我把环境准备的关键步骤拆开讲,每个步骤都说清楚为什么这么做。
2.1 安装 Docker 环境
如果你服务器上还没有 Docker,先把基础环境装好。Ubuntu 系统推荐用官方脚本安装,又快又省事。curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun,这个命令会自动配置好软件源和 Docker 服务。如果是 CentOS 或者 Windows 系统,直接去 Docker 官网下载对应安装包即可,Windows 上记得装 WSL2 后端。
装完之后先验证一下:sudo docker info能看到 System Info 和 Server Version 等信息就说明 Docker 正常工作了。我建议顺手把当前用户加入 docker 用户组,这样后面执行 docker 命令就不用每次都加 sudo。sudo usermod -aG docker $USER,这条命令之后需要重新登录终端才会生效。
2.2 解决 Docker 镜像拉取慢的问题
国内拉取 Docker Hub 镜像经常遇到超时和极慢的情况,这也是部署 SRS 最常见的卡点之一。SRS 官方镜像比较大,不配镜像加速器的话,拉取过程可能持续几十分钟甚至直接失败。
我习惯在/etc/docker/daemon.json里配置镜像加速地址。文件内容大概长这样:
{ "registry-mirrors": [ "https://docker.m.daocloud.io", "https://dockerproxy.com", "https://docker.mirrors.ustc.edu.cn" ] }配置完成之后重启 Docker 服务:sudo systemctl restart docker。这里提醒一句,不同的加速地址稳定性不一样,如果某个加速源拉取速度不理想,换一个再试。实测下来,拉取 SRS 镜像加上它的基础镜像文件,总共大概几百兆,加速正常的话五分钟以内能完成。
2.3 拉取 SRS 官方镜像
基础环境就绪后,开始拉 SRS 镜像。我用的是带完整功能的 ossrs/srs:4 标签,这个镜像内置了 FFmpeg 和 SRS 主程序,对于验证业务完全够用。
docker pull ossrs/srs:4如果希望用最新开发版或者准备跑 SRS 5.0 的 WebRTC 增强功能,可以拉取ossrs/srs:5。不过我建议生产环境优先用 4.x 稳定版本,5.0 虽然是当前主推的版本,API 改动更多,社区资料相对少一些。我这次就是为了完全求稳,选择了 4.0。
拉取完成后可以用docker images查看镜像,看到 ossrs/srs 出现就说明成功了。
3. 容器化部署 SRS 的完整实操
环境准备好了,接下来就是最关键的部署环节。我按两种方式讲:先讲直接用 docker run 快速启动验证,再讲用 docker-compose 做正式部署。两条路都走一遍,你根据自己的习惯选。
3.1 快速启动:一条命令跑起来
如果你只是想在本地快速验证 SRS 能不能用,直接执行这条命令:
docker run --rm -d \ -p 1935:1935 \ -p 1985:1985 \ -p 8080:8080 \ -p 8000:8000/udp \ -p 8000:8000/tcp \ ossrs/srs:4启动之后,检查一下容器状态:docker ps看到 srs 容器状态为 Up 就说明 SRS 已经运行了。然后打开浏览器访问http://你的服务器IP:8080,如果能看到 SRS 的欢迎页和控制台界面,就说明 Web 服务已经正常启动。
这一条命令背后做了几件事:映射 RTMP 端口 1935,让推流端能连上来;映射 1985 给 HTTP API 使用;映射 8080 提供 HTTP-FLV 播放和网页控制台;映射 8000 的 TCP/UDP 给 WebRTC 传输数据。理解每个端口的用途很重要,后面排查问题的时候你就知道该查哪个口了。
3.2 正式部署:docker-compose 方案
用 docker run 直跑适合临时测试,但正式的部署我强烈推荐用 docker-compose。好处有两个:一是配置可维护,环境变量、端口映射、数据卷都在一个文件里,团队协作和二次部署都方便;二是可以统一管理重启策略和网络模式。
我的 docker-compose.yml 内容如下:
version: "3.8" services: srs: image: ossrs/srs:4 container_name: srs-server restart: always ports: - "1935:1935" - "1985:1985" - "8080:8080" - "8000:8000/tcp" - "8000:8000/udp" volumes: - ./srs.conf:/usr/local/srs/conf/srs.conf - ./logs:/usr/local/srs/objs environment: - TZ=Asia/Shanghai这个配置有几个细节值得展开说:
restart: always解决了服务崩溃或服务器重启后的自愈问题。流媒体服务通常要求 7x24 小时在线,有这一行至少不用担心宕机了没人管。volumes 挂载把宿主机上的 srs.conf 配置文件和容器内的配置关联起来,这样我改完配置只需要docker restart srs-server就行,不用重新打镜像。日志目录也挂出来,排查问题的时候直接从宿主机查看,不用进容器。
启动命令就是标准的 compose 流程:
docker compose up -d3.3 自定义配置文件:把控制权拿回来
默认配置其实已经能让 SRS 跑起来,但要做真实业务,最好还是自己写配置文件。默认配置走的是 docker 镜像里的 srs.conf,没有针对具体场景优化。
我使用的配置文件核心段落如下:
listen 1935; max_connections 1000; daemon off; srs_log_tank console; http_api { enabled on; listen 1985; } http_server { enabled on; listen 8080; dir ./objs/nginx/html; } rtc_server { enabled on; listen 8000; # 生产环境请改为实际公网 IP candidate $CANDIDATE; } vhost __defaultVhost__ { tcp_nodelay on; min_latency on; play { gop_cache off; queue_length 10; } publish { mr on; mr_latency 350; } hls { enabled on; hls_path ./objs/nginx/html; hls_fragment 2; hls_window 6; } http_remux { enabled on; mount [vhost]/[app]/[stream].flv; } rtc { enabled on; rtmp_to_rtc on; rtc_to_rtmp on; } }我解释一下几个关键配置项的用途:
daemon off这个必须保持开启状态,Docker 容器需要前台进程存活,如果配置成 daemon on,容器会启动后马上退出。我一开始就踩过这个坑,容器起来之后几秒钟就死了,检查日志才发现是 daemon 配置的问题。srs_log_tank console同理,让 SRS 日志输出到标准输出,这样docker logs srs-server才能看到日志。http_remux开启后,SRS 就能把 RTMP 流转成 HTTP-FLV 流,播放器可以通过http://IP:8080/live/livestream.flv这样的地址直接播放。hls配置我设成了 2 秒一个切片,6 秒窗口,这是延迟和流畅性都比较均衡的组合。rtc 配置块里开启了 rtmp_to_rtc 和 rtc_to_rtmp,支持 RTMP 推流转 WebRTC 播放,以及 WebRTC 推流转 RTMP 播放,双向打通。
这里有一个容易踩坑的地方:rtc_server 里的 candidate 参数。WebRTC 建立连接时要进行 NAT 穿透,需要知道服务器的公网地址。如果 candidate 配错了,客户端能连接服务器,但媒体数据传不回来,表现为一直黑屏无法出流。我一开始没配这个参数,局域网内测试一切正常,换到公网服务器就不行了,排查很久才找到是这个参数的问题。生产部署时,我建议把它改成你的服务器公网 IP,或者用环境变量注入的方式动态配置。
3.4 配置文件的生效与验证
配置文件写好之后,修改 docker-compose.yml 挂载的配置文件路径,然后重启:
docker compose down docker compose up -d查看启动日志:
docker logs -f srs-server看到日志里出现SRS is running或者类似的关键字,就说明服务已经正常启动。接下来推荐用 SRS 自带的 API 做一个快速验证,请求http://IP:1985/api/v1/versions,如果能返回 JSON 数据,说明 HTTP API 正常。再请求http://IP:1985/api/v1/summaries能看到当前的连接数、带宽等运行时状态,也可以顺便确认流媒体引擎检测正常。
4. 推流与拉流全链路实测
服务端配置好了,必须实际推拉流来验证整条链路。我用 OBS 和 FFmpeg 各推了一路流,分别用 HTTP-FLV、HLS 和 WebRTC 播放,结果都正常出流。下面是具体的操作过程。
4.1 使用 OBS 推送 RTMP 流
OBS 的配置很简单。打开 OBS,进入「设置」→「直播」,服务选「自定义」,服务器地址填rtmp://你的服务器IP/live,推流码填livestream,然后点击开始推流。
这里的解析一下推流 URL 的结构:/live是应用名,Stream 名称livestream是流名。SRS 默认的 vhost 是__defaultVhost__,所有没有匹配到特定 vhost 的流都会走这个默认配置。推流成功后,播放地址对应的就是:
- HTTP-FLV:
http://你的服务器IP:8080/live/livestream.flv - HLS:
http://你的服务器IP:8080/live/livestream.m3u8 - WebRTC:
webrtc://你的服务器IP/live/livestream
需要注意的是,OBS 推流走的是 RTMP 协议,端口是 1935,如果你在本地防火墙或者云安全组里只开放了 8080 而忘了 1935,OBS 会一直显示连接失败。
4.2 使用 FFmpeg 模拟推流
如果你没有 OBS,用 FFmpeg 推流也一样方便,还方便做自动化测试。我用了系统自带的测试视频源:
ffmpeg -re -f lavfi -i testsrc=size=1280x720:rate=30 -f lavfi -i sine=frequency=1000:sample_rate=44100 \ -vcodec libx264 -preset veryfast -tune zerolatency -acodec aac \ -f flv rtmp://your-server-ip/live/test这条命令用的是 FFmpeg 内置的 testsrc 视频源和 sine 音频源,不用准备实际的视频文件。推流后同样可以通过http://IP:8080/live/test.flv播放。
这里多说一句-tune zerolatency参数,它能让编码器牺牲一点压缩率来换取最低的编码延迟,对实时流非常重要。如果是普通的短视频转码,不需要加这个参数,但直播场景一定得加,不然累积延迟会越来越大。
4.3 各协议播放效果实测
我分别用三种方式验证了播放效果:
HTTP-FLV 播放,延迟最低,实测大约在 1-3 秒之间,兼容性也比较好,支持 flv.js 的浏览器都能播放。我在浏览器里用 flv.js 播放,拉流地址http://IP:8080/live/test.flv,画面清晰流畅,音画同步正常。HTTP-FLV 是目前国内直播站点最主流的低延迟播放方案,推荐优先使用。
HLS 播放,兼容性最好,iOS Safari、Android Chrome 原生支持,但延迟也比较高,在 5-10 秒之间。我用 VLC 播放了http://IP:8080/live/test.m3u8,正常出流。HLS 适合对延迟要求不高的点播回看场景,不适合实时性要求强的互动直播。
WebRTC 播放,延迟最低,实测在 500ms 以内,几乎无感知。WebRTC 播放通过webrtc://IP/live/test地址拉起,具体用 WHIP/WHEP 客户端接入。我用浏览器直接走 WHEP 会话拉流,从 OBS 推流到浏览器出画面,延迟的体感就和看本地摄像头差不多。如果做视频连麦、远程手术示教这类场景,WebRTC 是唯一的正经选择。
4.4 用 SRS 控制台观察运行状态
SRS 自带一个简单的 HTTP 控制台,地址是http://IP:8080/console/,在里面可以看到当前的推流状态、播放连接数、带宽数据。如果觉得控制台功能太简单,也可以直接调用 HTTP API,比如:
curl http://IP:1985/api/v1/streams/这个接口返回一个 JSON 数组,里面包含当前所有的推流流信息,包括流名、客户端IP、视频编码、分辨率、码率等。我自己写了个小脚本,每分钟拉一次这个接口,如果流中断了,马上通过钉钉群机器人告警,省了不少事。
5. 常见问题与排查经验
部署和测试过程中,我遇到了好几个问题,这里逐个记录,都是可以用最短时间解决的,但没经验的话可能会卡一整天。
5.1 容器启动后马上退出
这个问题的典型表现是docker ps看不到容器,或者容器状态是 Exited。先用docker logs srs-server看日志,我遇到的情况是日志里报signal: killed或者Segmentation Fault,最后定位到是配置文件的 daemon 参数问题。SRS 在 Docker 里必须以daemon off前台模式运行,默认配置里如果写的是daemon on,容器启动后 SRS 自己 fork 到后台,Docker 找不到前台进程就把容器杀了。
还有一种情况是端口被占用。如果 1935 端口已经被宿主机上的其他程序占用了,SRS 启动时绑定端口失败,也会直接退出。解决方法是换一个端口映射,比如-p 19350:1935,前提是你理解这时外部推流地址要改成rtmp://IP:19350/live/xxx。
5.2 推流成功但播放黑屏或卡顿
这类问题最常见的原因是 GOP 缓存配置。在 SRS 默认配置里,客户端的播放可能要从关键帧开始才能解码出画面,如果播放器恰好错过了关键帧,就会一直黑屏等待下一个关键帧。可以通过把 HTTP 播放器配置里的gop_cache打开来解决,但这会增加一点延迟。我自己的做法是在 vhost 里保持gop_cache off,因为我的场景对延迟更敏感。
另外,推流端和播放端的编码参数不一致也会导致花屏或卡顿。比如视频源是 H.264 High Profile,某些老客户端只支持 Baseline Profile,播放就会出问题。建议推流端统一使用 H.264 Main Profile + AAC 音频,这是兼容性最好的组合。
5.3 WebRTC 无法连接,一直显示连接中
遇到 WebRTC 连接不上,九成是 candidate 配置或者端口开放问题。先检查云服务商的安全组是否放行了 8000 端口的 UDP 和 TCP,再检查系统防火墙sudo ufw status。这两个地方都确认没问题之后,再看 SRS 日志里有没有candidate相关的报错。
还有一个隐蔽的坑:如果你服务器上有多个网卡,或者用了 NAT 网关,SRS 会自动探测本机 IP,但探测到的可能是内网 IP,这个 IP 公网访问不到。这种情况必须手动指定 candidate 为公网地址,或者使用ifconfig那个有公网 IP 的网卡来监听。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 排查命令 / 解决方案 |
|---|---|---|
| 容器启动后秒退 | daemon 未设置为 off,或端口被占用 | 检查 srs.conf 中daemon off;执行netstat -tlnp | grep 1935查端口占用 |
| 推流连接失败 | 1935 端口未在云安全组和防火墙放行 | 检查安全组/防火墙;telnet IP 1935测试连通性 |
| 播放 HTTP-FLV 黑屏 | gop_cache 配置关闭导致等待关键帧 | 播放器多次重连或开启 gop_cache;确认推送流编码参数 |
| HLS 播放延迟过高 | 切片时长设置过大 | hls_fragment 调小到 1-2 秒,hls_window 设为 3-6 秒 |
| WebRTC 一直连接中 | candidate 配置错误/端口未放行 | 检查http://IP:1985/api/v1/rtc返回;确认 8000 TCP/UDP 放行 |
| 公网访问 8080 不通 | 云安全组未放行 HTTP 端口 | 检查云控制台入方向规则,放行 8080 TCP |
5.5 性能调优与稳定性经验
如果你准备把 SRS 用于正式生产环境,这几个经验点可以参考:
关于内核参数调优。高并发场景下,可以适当调整 Linux 内核参数,比如net.core.rmem_max和net.core.wmem_max增大 Socket 缓冲区,处理大码率流时能降低丢包率。不过这些调整在容器里需要特权模式才能生效,我的做法是在宿主机上直接配置,容器启动时加--network host让 SRS 直接使用宿主机的网络栈。这个方案在性能要求高的场景下推荐使用,但需要注意端口冲突管理的复杂度会增加。
关于日志轮转。SRS 在 console 模式下日志量挺大的,长时间运行不处理会吃掉大量磁盘空间。我写了个简单的 logrotate 脚本,每天对/var/lib/docker/containers/*/*-json.log做切分和压缩,保留最近 7 天日志,这个操作帮我避免了好几次磁盘空间告警。
关于版本选择。SRS 4.0 和 5.0 我都试过,5.0 在 WebRTC 的 SFU 能力和 API 设计上有不少改进,但社区参考资料确实比 4.0 少。个人建议:如果你不是特别需要 5.0 的新特性,4.0 已经足够稳定,遇到问题也好搜资料。等你的主要功能在 4.0 上验证通了,再计划性地迁移到 5.0 也不迟。
6. 进阶玩法:SRS 与其他服务的组合
SRS 不只是单独运行一个流媒体服务,它和很多其他开源组件配合起来,可以搭建更完整的音视频平台。这里简单聊几个我验证过的组合方案。
6.1 结合服务端录制做点播回看
SRS 原生支持 DVR 录制功能,把直播流直接写成 FLV 文件存到磁盘。我的配置文件里加了一段:
vhost __defaultVhost__ { dvr { enabled on; dvr_path ./objs/nginx/html/record/[app]/[stream]/[2006-01-15]/[2006-01-15]_[15-04-05].flv; dvr_plan session; dvr_duration 30; dvr_wait_keyframe on; } }这样直播的同时就能生成回放文件,之后可以把这些文件接入到点播服务,或者定期转码成 MP4 存档。
6.2 与 FFmpeg 集群协同做转码
SRS 本身不做视频转码,但可以通过 HTTPCallback 对接 FFmpeg 集群。当 SRS 收到一个推流,回调通知转码服务,FFmpeg 拉取原始流做转码后,再推回给 SRS 分发不同的清晰度。
我在实际项目中这样实现过:原始流默认 1080P 推到 SRS,FFmpeg 收到回调后,把流拉下来转成 720P 和 480P 两路,重新推回 SRS 的同一个 vhost 下,播放端根据带宽和终端类型选择对应清晰度的播放地址。如果你对延迟要求不高,这个方案完全可以替代商业转码服务。
6.3 与监控系统集成
SRS 的 HTTP API 数据可以非常方便地接入 Prometheus 这类监控系统。我在服务器上跑了 node-exporter 加 Prometheus,通过脚本定期抓取 SRS 的/api/v1/summaries数据,把推流数、播放数、总带宽这些指标转换成 Prometheus 格式。再配合 Grafana 的仪表盘,实时看到整个平台的运行状态,比手动登录服务器查看高效太多了。
这类实践在真实运维中价值极高,所有涉及音视频线上业务的团队,我都很建议把监控体系搭起来,否则每路流的故障定位都会非常被动。
我个人在实际操作中的体会是,Docker 部署 SRS 真正的难点不在 Docker 命令,而在对流媒体协议和 SRS 配置项的理解,Docker 只是帮你省去了环境搭建的麻烦。这篇内容从镜像准备、配置文件、推流验证到问题排查都覆盖了,按着一步步操作应该很快能跑通。最后再分享一个小技巧:SRS 的docker exec -it srs-server ./objs/srs -v命令可以查看当前版本,而遇到疑难杂症时,用docker logs --tail=200 srs-server拉出最近 200 行日志,绝大多数问题都能从里面找到线索。祝你顺利搭建出自己的实时音视频平台。