Docker部署SRS:从零搭建直播与WebRTC低延迟流媒体服务器
搞直播、做实时音视频的人,应该都有过被流媒体服务器折腾的经历。编码、推流、转协议、切片、分发,链路又长又碎,任何一个环节出问题,画面就是怼在那里不动。SRS 是我这几年在真实项目里用得最多的开源实时流媒体服务器,协议覆盖全、性能也够硬。而把它跟 Docker 搭配起来之后,部署门槛被压得非常低,不用再花大半天去编译依赖、配环境,一条 docker run 就能把服务拉起来。
这篇文章基于我自己在多个环境里实际部署 SRS 的记录整理而成,覆盖从基础容器启动、推拉流验证,到 WebRTC 低延迟配置、HLS 录制、鉴权防盗链,再到最常见的故障排查。无论你是刚接触流媒体的新手,还是已经踩过几个坑、想把本地流媒体服务迁到容器环境的老手,都可以把这篇当成一份能直接照抄的部署手册。
1. 为什么选择 Docker 部署 SRS:方案选型与核心思路
1.1 SRS 能做什么:从直播到连麦的场景盘点
先说清楚 SRS 的定位。SRS 全称 Simple Realtime Server,是一个基于 C++ 开发的实时流媒体服务器,支持 RTMP、HTTP-FLV、HLS、WebRTC、SRT、GB28181 等多种协议。很多人第一次接触它是因为要做直播,但实际上它的能力远比“拉一个 RTMP 流再转出去”要广。
我实际用下来,SRS 能覆盖的场景至少包括:
- 常规直播 :主播端用 OBS 等软件推 RTMP 或 SRT 流,观众端通过 HTTP-FLV、HLS 或播放器直接观看。
- 低延迟互动 :基于 WebRTC 的推拉流,延迟可以压到 1 秒以内,适合视频连麦、在线课堂、远程协助。
- 录像与回放 :开启 HLS 切片后,直播结束自动生成 m3u8,自然而然支持点播回放。
- 协议转换 :RTMP 进来,FLV、HLS、WebRTC 分发出去,不用在客户端折腾不同协议。
- 安防与物联网 :通过 GB28181 接入摄像头,把监控流转换为标准流媒体输出。
所以,SRS 并不只是“直播服务器”,更准确的说法是一套统一的实时音视频接入与分发底座。团队里没有专门做流媒体后端的同学,也可以靠它快速搭出一套能撑住实际流量的服务。
1.2 Docker 部署与裸机部署的对比
在决定用 Docker 之前,我也在裸机上编译部署过 SRS。当时的流程是:装依赖、拉源码、编译、改配置、注册成 systemd 服务。整体不算复杂,但踩坑率一点都不低。编译时工具链版本不匹配、openssl 加密库缺头文件、glibc 版本不对,这些问题每一个都能卡掉半天。
Docker 方案最大的价值在于,把“运行环境”和“业务程序”一起打包。SRS 官方提供的镜像本身就带好了编译好的二进制和默认配置,启动之后就是一个可用的流媒体服务,不污染宿主机的环境。后期升级版本也很简单,换 tag 重启容器就行。
用 Docker 部署,本质上是用“不可变基础设施”的思路来管理流媒体服务。容器是临时且可替换的,配置通过挂载目录或环境变量注入,日志输出到标准输出由 Docker 统一收集。当你需要同时维护推流、转码、录制等不同组件时,容器编排的优势更加明显。
我整理的对比表格如下:
| 部署方式 | 上手成本 | 环境隔离 | 升级回滚 | 适合场景 |
|---|---|---|---|---|
| 源码编译 | 高 | 无 | 麻烦 | 需要深度定制内核或模块 |
| 二进制包 | 中 | 弱 | 一般 | 快速验证、单机使用 |
| Docker 容器 | 低 | 强 | 方便 | 开发测试、多组件协同、生产隔离 |
依赖多、版本杂、想快速迭代的项目,我建议优先容器化。SRS 官方镜像质量不错,基础镜像小、启动快,社区活跃度高,踩坑时还能在 issue 里找到不少现成方案。
2. Docker 部署 SRS 的前置准备与环境配置
2.1 宿主机环境要求与 Docker 安装
先检查一下宿主机。SRS 本身占用资源不高,单路直播流从几百 Kbps 到几 Mbps 不等,CPU 和内存压力都不大,普通 2C4G 的云主机完全足够跑大多数场景。如果还要开启转码(依赖 FFmpeg),或者接入多路 GB28181 摄像头,建议把机器规格提到 4C8G。
Docker 的安装这里不展开讲太多,只说几个要点:
- Linux 系统建议直接用官方脚本安装,安装完成后把当前用户加入 docker 组,避免每条命令都加 sudo。
- macOS 和 Windows 分别用 Docker Desktop,注意 Windows 上要开启 WSL2 后端。
sudo apt-get update
sudo apt-get install -y ca-certificates curl
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
注意:改完用户组之后需要重新登录终端,docker 组权限才会生效。这一步很多人忽略,导致后续命令一直报 permission denied。
安装完成后执行 docker version 确认客户端和服务端都正常,再继续往下走。
2.2 端口规划:一次搞懂 1935、8080、1985、8000
SRS 默认监听几个关键端口,每个端口对应不同的协议和用途。弄清楚它们,后面不管是配防火墙还是改 docker run 映射,都会非常清楚。
- 1935 :RTMP/TCP 端口,接收 OBS 等推流工具的上行推流,也支持播放器直接拉 RTMP。
- 1985 :HTTP API 端口,SRS 的管理接口、WebRTC 信令服务、WHIP/WHEP 都走这里。
- 8080 :HTTP 服务端口,对外提供 HTTP-FLV、HLS 切片文件,以及简单的 demo 页面。
- 8000 :UDP 端口,WebRTC 的媒体数据传输入口,跑 WebRTC 时必须映射。
有些人只映射 1935 和 8080,推流和 HTTP-FLV 能通,但 WebRTC 拉流必然失败。原因就是 8000 这个 UDP 端口没有暴露,数据包根本进不来。建议从规划阶段就把四个端口全部放开,省得后面反复改。
2.3 镜像选择:官方仓库与版本说明
SRS 官方镜像仓库地址是 registry.cn-hangzhou.aliyuncs.com/ossrs/srs,同时在 Docker Hub 也有 ossrs/srs 镜像。国内服务器建议直接用阿里云仓库,拉取速度快很多。版本标签上,SRS 4 和 SRS 5 是主流,SRS 5 在 WebRTC 和 HTTP API 上改动较大,新项目直接选 5。
docker pull registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5
如果只想体验最新特性,也可以拉 tag 为 latest 的镜像,但生产环境请固定大版本,避免镜像更新造成行为变化。
另外,SRS 镜像默认包含一个示例配置,功能足够日常测试。要深度定制时,再通过挂载配置文件覆盖默认配置,这个我在第 4 部分会详细讲。
3. 亲手跑通 SRS:快速部署与推拉流全流程
3.1 使用 docker run 启动 SRS 容器
基础启动命令很简单,把四个关键端口一次性映射出来:
docker run -d --name srs \
-p 1935:1935 \
-p 1985:1985 \
-p 8080:8080 \
-p 8000:8000/udp \
registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5
启动之后,用 docker ps 看容器状态,再确认一下日志里有没有异常:
docker ps
docker logs srs
正常情况下,日志会打印 SRS 启动成功以及监听端口的信息。如果日志里出现地址被占用,多半是本机已经有一个进程占了 1935 或 8080,需要先停掉冲突进程,或者把宿主机侧的映射端口换掉,比如把 8080 换成 18080。
3.2 验证容器状态与 HTTP 服务
容器起来之后,先用最简单的 HTTP 请求验证服务是否正常:
curl http://localhost:8080/
SRS 默认在 8080 端口上提供了一个静态文件服务,如果返回了页面内容说明 http_server 正常。再访问一下 API 接口:
curl http://localhost:1985/api/v1/versions
这条命令会返回 SRS 的版本信息,包括版本号、构建时间等。能拿到 JSON 返回,说明 HTTP API 端口也通了。
提示:这一步最好在本机执行。如果在其他机器上测试,注意防火墙和安全组必须放行对应 TCP 和 UDP 端口。
3.3 用 OBS 推流验证直播链路
服务端起来了,接下来要验证真实的推拉流链路。我习惯用 OBS 做推流测试,步骤简单、能看到编码参数:
- 打开 OBS,进入“设置 -> 直播”。
- 服务选择“自定义”,服务器地址填 rtmp://服务器IP:1935/live,串流密钥填 livestream。
- 点击“开始直播”,观察 OBS 的状态面板,确认上传带宽已经在跑。
推流地址实际上由 app 名和 stream 名组成。/live 是 app 名,livestream 是 stream 名。后面的播放地址、回调地址都会用到这两个名字。
如果 OBS 提示连接失败,先在本机用 telnet 测一下 1935 端口:
telnet 服务器IP 1935
连不上就检查 Docker 端口映射、云安全组、系统防火墙三层,一层层排除。实际项目中,因为云厂商安全组没放行而导致的连不上,占了相当高的比例。
3.4 用 FFplay 与浏览器拉流验证
推流端确认没问题,接下来验证拉流。SRS 默认配置下,同一路流可以同时用多种协议拉取:
HTTP-FLV: http://服务器IP:8080/live/livestream.flv
HLS: http://服务器IP:8080/live/livestream.m3u8
RTMP: rtmp://服务器IP:1935/live/livestream
用 ffplay 测试 HTTP-FLV 最直观:
ffplay http://服务器IP:8080/live/livestream.flv
如果本机没装 ffplay,也可以用 VLC 打开网络串流,或者直接在浏览器里访问 SRS 自带的播放器页面:
http://服务器IP:8080/players/srs_player.html
在播放器页面的地址栏输入 http://服务器IP:8080/live/livestream.flv,点播放。浏览器如果能正常出画面,说明从推流到分发的整条链路已经通了。我第一次完整跑通这套流程的时候,脑子里只有一个想法:原来流媒体平台搭起来可以这么轻。
4. 进阶配置:HLS、WebRTC 与鉴权防盗链
4.1 配置 HLS 录制与点播台账
SRS 默认配置里 HLS 是关闭的,需要自己写配置并挂载进容器。我建议先在工作目录创建一个自定义配置文件 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;
}
vhost __defaultVhost__ {
hls {
enabled on;
hls_fragment 2;
hls_window 30;
}
http_remux {
enabled on;
mount [vhost]/[app]/[stream].flv;
}
}
hls_fragment 表示每个切片文件的时长,单位秒;hls_window 表示保持的切片总时长,单位秒。直播录像会根据这两个参数自动滚动生成切片,切片目录默认在容器内的 /usr/local/srs/objs/nginx/html 下。要保留录像,把该目录挂载到宿主机:
docker run -d --name srs \
-p 1935:1935 \
-p 1985:1985 \
-p 8080:8080 \
-p 8000:8000/udp \
-v $PWD/srs.conf:/usr/local/srs/conf/srs.conf \
-v $PWD/objs:/usr/local/srs/objs \
registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5
这样直播过程中产生的 m3u8 和 ts 文件会直接落在宿主机 $PWD/objs/nginx/html 目录,方便后续二次开发或对接回放系统。
注意:修改了宿主机上的 srs.conf 之后,需要重启容器才能生效:docker restart srs。
我这里把挂载点单独拿出来说一下。$PWD/objs 这个目录会给你带来一个额外好处:容器删了、换了镜像,历史录像文件还在宿主机上,完全不会丢。对于做在线教育、电商直播回放这类业务,录像持久化是刚需,别把数据放在容器里层。
4.2 开启 WebRTC 低延迟直播
WebRTC 是 SRS 5 里最值得玩的部分,延迟能做到 1 秒以内。要在 SRS 里启用它,先要理解 WebRTC 的两个阶段:信令走 HTTP(1985 端口),媒体数据走 UDP(8000 端口)。所以网络环境里,TCP 1985 和 UDP 8000 都必须对客户端可达。
在 srs.conf 的 vhost 中加入 rtc 配置:
vhost __defaultVhost__ {
rtc {
enabled on;
rtc_port 8000;
}
}
保存后重启容器。然后在播放器页面里把地址换成 webrtc://服务器IP/live/livestream,或者使用官方提供的播放器,就可以用更低延迟的方式观看。
WebRTC 的推流也有标准协议,SRS 5 支持 WHIP。在播放器页面选择推流,服务地址填 http://服务器IP:1985/rtc/v1/whip/?app=live&stream=livestream,就可以用浏览器直接推流。因为浏览器推流省去了编码器,对主播端的硬件要求也低一些。
这里提醒一句:WebRTC 在 NAT 后面或者复杂网络环境下,需要配置 ICE candidate 为公网 IP。SRS 官方提供了 CANDIDATE 环境变量,容器启动时通过 -e CANDIDATE=服务器公网IP 注入即可。
docker run -d --name srs \
-p 1935:1935 \
-p 1985:1985 \
-p 8080:8080 \
-p 8000:8000/udp \
-e CANDIDATE=你的公网IP \
-v $PWD/srs.conf:/usr/local/srs/conf/srs.conf \
registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5
没有正确配置这一项,客户端能看到信令握手,但媒体数据传不过来,表现为拉流超时。这是 WebRTC 部署里最典型的坑,没有之一。
4.3 用 docker compose 固化部署配置
docker run 命令适合快速验证,但生产环境里我建议把部署配置写成 docker-compose.yml,方便版本管理。
version: "3.8"
services:
srs:
image: registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5
container_name: srs
restart: unless-stopped
ports:
- "1935:1935"
- "1985:1985"
- "8080:8080"
- "8000:8000/udp"
environment:
- CANDIDATE=你的公网IP
volumes:
- ./srs.conf:/usr/local/srs/conf/srs.conf
- ./objs:/usr/local/srs/objs
然后启动:
docker compose up -d
restart: unless-stopped 非常有用,宿主机重启后容器会自动拉起,流媒体服务不用人工干预。修改配置后执行 docker compose restart 即可完成轮换。
Docker Compose 对多组件项目尤其合适。比如你后面要接入 FFmpeg 转码、加一个日志采集器,直接在同一个 compose 文件里扩展服务即可,一整套编排可以整体启动和销毁。相比一长串 docker run 参数,可读性和可维护性都要好得多。
4.4 HTTP 回调鉴权与 Referer 防盗链
流媒体服务如果不加任何防护,只要知道推流地址谁都能推流,这在公网环境很容易被滥用。SRS 提供了 http_hooks 功能,可以在推流、拉流、结束等事件发生时回调外部接口,由业务后端决定是否放行。
配置写法如下:
vhost __defaultVhost__ {
http_hooks {
enabled on;
on_publish http://你的业务后端/api/srs/on_publish;
on_play http://你的业务后端/api/srs/on_play;
on_unpublish http://你的业务后端/api/srs/on_unpublish;
}
}
业务后端收到回调后,检查回调参数里的 app、stream 和 token 字段,验证通过返回 HTTP 200,拒绝则返回非 200。比如常见的做法是让主播在推流串流密钥里带上签名,服务端按同样规则计算一遍签名,不一致就拒绝。这样即使推流地址泄露,别人也无法冒充推流。
对于拉流场景,SRS 还支持简单的 Referer 防盗链。在 vhost 里配置:
vhost __defaultVhost__ {
refer {
enabled on;
all on;
refer_play github.com ossrs.net;
refer_publish github.com ossrs.net;
}
}
这个配置限制了只有来源页面是 github.com 或 ossrs.net 的放行,其他来源一律拒绝。不过 Referer 可以被浏览器插件或者脚本伪造,只适合做基础防护,不能当作唯一安全手段。真正要保护好视频资源,还是得靠播放器端接入自己的鉴权协议,或者用更严格的 CDN 签名。
5. 常见问题与排查技巧实录
5.1 镜像拉取慢或超时
这是 Docker 部署时出现频率最高的问题。官方镜像在国外,国内网络下载经常只有几十 KB/s,甚至直接超时。解决办法主要有两个。
一是换用阿里云仓库地址,把 registry.cn-hangzhou.aliyuncs.com/ossrs/srs 作为镜像地址。二是配置 Docker daemon 的 registry-mirrors,写入国内镜像加速器。很多人只用 Docker Hub 官方源,镜像下载慢到怀疑人生,换成可用的加速地址之后速度立竿见影。
如果换了镜像加速还是慢,我一般会检查一下是不是公司网络做了出口限制。实在不行,就在一台网络状况好的机器上先 docker pull,再通过 docker save 导出镜像包,上传到目标服务器后用 docker load 导入。这个思路在离线环境部署时也通用。
5.2 容器启动失败:端口占用与配置文件错误
容器启动失败,第一步先看日志:
docker logs srs
日志里出现 bind 相关字样,基本就是宿主机端口被占用。用下面的命令找出占用进程:
sudo lsof -i :1935
然后停掉对应进程,或者修改 docker run 的映射端口,比如把宿主机侧的 8080 映射成 18080。
如果日志里提示 config parse failed,说明 srs.conf 格式有问题。SRS 配置对缩进并不严格敏感,但对字段名和嵌套结构敏感。检查 vhost 嵌套是否正确、括号有没有闭合、单词是否拼错。SRS 的配置解析错误提示其实比较友好,会直接告诉你哪一行出了问题,按提示逐行修即可。
另外一个容易忽略的情况是:挂载的宿主机配置文件没有权限读。检查一下 srs.conf 的文件权限,确保 Docker 进程能正常读取,不然容器会启动后立刻退出。
5.3 拉流地址打不开:协议与端口对应关系
拉流失败,要先确认你用的是什么协议,对应端口是不是通的。RTMP 走 TCP 1935,HTTP-FLV 与 HLS 走 TCP 8080,WebRTC 媒体走 UDP 8000,信令走 TCP 1985。不同协议就是不同端口,漏掉任何一个都会导致对应协议无法使用。
在上面的端口基础上,再检查防火墙和安全组。很多云服务器的默认安全组只放行了 80 和 22,需要在安全组规则里显式加添 1935、1985、8080、8000/UDP。
我遇到过不少次“Docker 端口没映射”“安全组没放行”“防火墙没开”三种问题同时叠加的情况。排查顺序建议是:先 docker ps 确认端口映射,再 curl 本机端口确认容器内部正常,最后用外部机器访问测试。一层层往上,准确率最高。
5.4 延迟高、花屏、音画不同步排查
延迟高的原因大多是播放协议选择不当。RTMP 和 HTTP-FLV 的延迟一般在 2 到 5 秒,HLS 因为切片生成机制,延迟通常在 5 到 15 秒。如果用了 HLS 还要求秒开,那不是在挑服务器的毛病,而是方案选错了。要低延迟,直接选 WebRTC,延迟能控制在 1 秒左右。
花屏和音画不同步的问题,大概率出在推流端的编码参数上。OBS 建议匹配通用参数:视频编码 x264,码率 2500 到 6000 Kbps,关键帧间隔设为 2 秒,音频用 AAC,采样率 44100。如果关键帧间隔设置不匹配,客户端在追帧时会出现花屏;音视频编码器的启动延迟差异则会导致开头几十毫秒不同步。
另外,公网拉流如果出现频繁卡顿,先看服务器带宽是不是被打满。SRS 本身不转码,流量几乎是按路数翻倍复制,一路 3 Mbps 的流,10 个人看就是 30 Mbps 出口带宽。云服务器的带宽通常按固定套餐购买,这里非常容易成为瓶颈。实际项目里,直接把流推到 CDN 的分发节点,再由 CDN 对外分发给观众,是更稳妥的架构。
5.5 查看日志与容器内调试
SRS 容器化之后,日志默认打到标准输出,用 docker logs 可以随时查看。但在排查流媒体问题时,我经常需要进入容器内部确认更多细节:
docker exec -it srs bash
进入容器后,可以检查内置的 HTTP API,比如查看当前连接的流:
curl http://localhost:1985/api/v1/streams/
这个接口会返回当前活跃的流列表,包括推流地址、客户端数量等。当发现推流地址正确但拉不到流时,先看这个接口里有没有对应流记录。有记录,说明服务端已经接收到了流,问题出在分发环节;没记录,多半是推流环节就有问题。
SRS 的日志等级可以通过配置调整,比如在 srs.conf 里加一行:
srs_log_level trace;
trace 级别会打印非常详细的 WebRTC 信令和媒体协商信息,排查 WebRTC 连不上时非常有用。排查完记得改回 warn,避免日志量过大。
结尾
这套 Docker 部署 SRS 的流程,我在本地开发机、云服务器上都跑过,可以说稳定性相当不错。个人建议在生产使用之前,务必把 CANDIDATE 公网地址、HLS 存储路径、HTTP 回调鉴权这三件事提前规划好,不然上线后再补会明显增加工作量。
最后再分享一个小技巧:把 SRS 的 HTTP API 接到自己的监控告警系统里,定期拉取 /api/v1/streams/ 的数据,当活跃流数量异常下降或端口探活失败时及时告警。流媒体服务本身不难,难的是在没人盯着的时候它也要一直稳着。希望这篇文章能帮你少走一些弯路,早点把实时音视频平台跑起来。
更多推荐

所有评论(0)