当你想在自己的服务器上搭一套能用的直播或者实时音视频服务,但又不想被商业云服务商捆绑,SRS(Simple Realtime Server,简单实时服务器)绝对是最值得考虑的开源方案之一。它支持 RTMP、HTTP-FLV、HLS、WebRTC 这些主流协议,既能做直播推拉流,也能做低延迟音视频通信。再配合 Docker 部署,你甚至不需要在宿主机上装一堆运行时依赖,一条命令就能把整个流媒体服务跑起来。

这篇文章我打算用一个完整可复现的流程,从零开始讲清楚怎么用 Docker 部署 SRS,覆盖环境准备、镜像选择、配置解析、推拉流实测,再到常见的坑怎么避开。适合的人包括:刚接触流媒体服务的小白、想自建直播平台的技术爱好者,以及需要在内网快速搭一套测试环境的开发人员。文章里涉及到的命令和配置,都是我实际跑过验证过的,你照着做基本不会翻车。

1. 内容整体设计与思路拆解

1.1 为什么流媒体服务要选 SRS

做流媒体服务,市面上常见的开源方案大致有三类:Nginx 搭配 nginx-rtmp-module、ZLMediaKit,还有 SRS。

Nginx + rtmp 模块是最早流行的玩法,配置简单,但只要涉及复杂一点的会话管理、WebRTC 支持、集群扩展,就有点力不从心。ZLMediaKit 性能不错,C++ 写的,功能也很全,但新手去读它的配置和 API 文档时往往容易懵,社区资料相对少。相比之下,SRS 的设计思路更贴近“开箱即用”,官方文档齐全,社区活跃度高,而且对 WebRTC 的支持做得非常成熟,代码质量和迭代速度都让人放心。

SRS 这个名字很多人会误以为它只能做直播服务器,实际上它的能力边界很宽:RTMP/HLS/HTTP-FLV 直播流转发、WebRTC 低延迟通话、SRT 协议推流、GB28181 安防接入、DVR 录像回放等等。也就是说,不管你是做在线教育、直播带货、安防监控,还是做一对一的视频通话,SRS 都能覆盖到。

1.2 用 Docker 部署的核心理由

我最初是在裸机上直接编译安装 SRS 的,过程其实不算复杂,但有几个痛点始终绕不开:一是编译依赖多,GCC、Make、FFmpeg 开发库一个都不能少,遇到 CentOS 7 这种老系统还得手动处理各种兼容问题;二是升级麻烦,新版本发布后要下载源码重新编译,中间只要某个依赖版本不对,很容易卡住;三是环境隔离差,SRS 和宿主机的其他服务混在一起,一个端口冲突或者动态库问题就可能把整个环境带崩。

Docker 方案把这些麻烦全部收掉了。镜像自带运行环境,宿主机只需要有 Docker 引擎;升级时拉一个新镜像重新建容器就行,旧容器随时可以回滚;端口和存储通过映射控制,哪一天不想要了,直接把容器删掉,宿主机不留一点垃圾。对于绝大多数想快速把流媒体服务跑起来的场景,Docker 是最合理的选择。

1.3 整体架构和部署路径

在整个部署链路里,角色分配是这样的:SRS 容器负责处理所有流媒体协议的接入和转发;宿主机上的 1935 端口映射给 RTMP 推流,8080 端口映射给 HTTP-FLV 和 HLS 播放,1985 端口映射给 HTTP API,8000 端口映射给 WebRTC 使用。客户端通过 OBS 这类工具推流到 SRS,然后播放器通过 HTTP-FLV 或 HLS 拉流观看。

整个部署路径可以拆成四步:第一步准备 Docker 环境;第二步拉取 SRS 镜像;第三步编写并启动 docker-compose 文件;第四步用推流工具和播放器验证整个链路是否通。下面我会按这个顺序一步步展开。

2. 环境准备与镜像选择

2.1 Docker 环境检查与常见问题处理

在写任何配置之前,先把 Docker 环境理清楚。如果你用的是 Linux 服务器,安装方式通常就是官方脚本一条命令搞定:

curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
systemctl enable --now docker

装完后记得验证一下 Docker 是否正常运行:

docker version
docker ps

如果你是在 Windows 上用 Docker Desktop,很可能会碰到一个经典报错:Docker Desktop failed to start because virtualisation support wasn't detected。这个问题的根源是 Hyper-V 或 Windows 虚拟机监控程序没启用。解决方法是:控制面板 -> 程序 -> 启用或关闭 Windows 功能,勾选“Hyper-V”和“虚拟机平台”,如果用的是 Windows 10 家庭版,还要额外装 WSL2 内核并执行 wsl --set-default-version 2 。改完设置后必须重启系统才生效。

还有一个非常影响体验的问题:镜像下载慢。因为 Docker Hub 在国内的访问速度不稳定,我建议在 /etc/docker/daemon.json (Windows 是 Docker Desktop 的配置面板)里配置可信的镜像加速地址,比如:

{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://dockerproxy.com"
  ]
}

配置完记得执行 systemctl restart docker 让配置生效。注意加速地址只影响 docker pull 的速度,不影响容器内的实际业务。

2.2 SRS 镜像怎么选

SRS 官方的镜像仓库地址是 registry.cn-hangzhou.aliyuncs.com/ossrs/srs ,也同步到了 Docker Hub( ossrs/srs )。如果你在境内服务器上拉取,用阿里云的地址会快很多。

镜像 tag 的选择上有两个思路:一是直接用 latest 或 v4.0 这类版本 tag,适合想快速跑起来验证效果的场景;二是在生产环境建议锁定具体版本号,避免后续升级带来不兼容的变更。我自己常用的镜像 tag 是 v4.0-r0 ,对应 SRS 4.0 系列的最新稳定版本。

拉镜像的命令很简单:

docker pull registry.cn-hangzhou.aliyuncs.com/ossrs/srs:latest

拉完后用 docker images 确认一下镜像已经存在本地。

2.3 配置镜像加速和网络模式

前面提到镜像加速,这里补充一个重要的点:Docker 的网络模式对容器的访问方式影响很大。SRS 的官方文档推荐使用 host 网络模式,这样容器直接共享宿主机网络栈,端口不用映射也能直接访问,而且性能损耗最小。

但 host 模式有一个缺点:Windows 和 Mac 的 Docker Desktop 对它的支持不太友好,容器内无法直接通过 localhost 访问宿主机服务。如果你是在 Linux 服务器上部署,直接 network_mode: host 是最省事的;如果你是在 Windows/Mac 上跑 Docker Desktop,我建议改用 bridge 模式 + 端口映射,也就是下面配置里我写的那种方式。

3. 编写 docker-compose 配置并启动服务

3.1 准备目录结构和配置文件

SRS 的官方镜像默认使用 /usr/local/srs 作为工作目录,我们只需要关心两个东西:配置文件和日志目录。为了让配置持久化,我习惯把宿主机的一个目录挂载进容器。

先在宿主机上创建基础目录:

mkdir -p /opt/srs/conf
mkdir -p /opt/srs/www
mkdir -p /opt/srs/logs

conf 目录放 SRS 的配置文件, www 目录给 SRS 内置的 HTTP 静态文件服务使用, logs 目录用于持久化日志。

3.2 编写 docker-compose.yml

用 docker-compose 管理容器最大的好处是:配置即代码,换一台机器直接复制文件起来就是一套一模一样的环境。下面是我实际使用的 compose 文件:

version: "3.8"

services:
  srs:
    image: registry.cn-hangzhou.aliyuncs.com/ossrs/srs:latest
    container_name: srs
    restart: unless-stopped
    ports:
      - "1935:1935"   # RTMP 推流端口
      - "1985:1985"   # HTTP API 端口
      - "8080:8080"   # HTTP-FLV / HLS 播放端口
      - "8000:8000/udp" # WebRTC 端口
    volumes:
      - /opt/srs/conf:/usr/local/srs/conf
      - /opt/srs/www:/usr/local/srs/www
      - /opt/srs/logs:/usr/local/srs/objs
    command: ["./objs/srs", "-c", "conf/docker.conf"]

注意几个细节:

  • restart: unless-stopped 保证 Docker 重启或宿主机重启后 SRS 能自动恢复。
  • ports 里的端口映射用 host 网络模式时不需要写,但 bridge 模式下必须写清楚。
  • command 里的配置文件路径是容器内的路径,不是宿主机路径。
  • WebRTC 端口默认是 8000/udp,别漏掉 udp 协议标识,否则 WebRTC 连不上。

3.3 准备 docker.conf 配置文件

SRS 官方镜像里默认有一个配置文件,但那个配置写死了一些内部路径,直接挂载目录后可能对不上。我建议自己写一个最小可用的配置文件,内容如下:

listen              1935;
max_connections     1000;
daemon              off;
srs_log_tank        console;

http_api {
    enabled         on;
    listen          1985;
}

http_server {
    enabled         on;
    listen          8080;
    dir             /usr/local/srs/www;
}

rtc_server {
    enabled         on;
    listen          8000;
    # 禁用一个 UDP 端口监听
    # 注意:SRS 4.0 默认使用 8000 作为两个 UDP 端口的基础端口
}

vhost __defaultVhost__ {
    rtmp {
        enabled     on;
    }
    http_remux {
        enabled     on;
        mount       [vhost]/[app]/[stream].flv;
    }
    hls {
        enabled     on;
        hls_path    /usr/local/srs/www;
        hls_fragment    6;
        hls_window      60;
    }
    rtc {
        enabled     on;
    }
}

这里解释一下各段含义:

  • listen 1935 :RTMP 默认端口,OBS 推流就是走这个端口。
  • http_api :SRS 的管理 API,可以用 HTTP 请求查询服务器和流的状态。
  • http_server :内置的 HTTP 文件服务器,用来服务 HLS 切片文件。
  • rtc_server :WebRTC 相关配置。SRS 4.0 的 RTC 会占用两个 UDP 端口,默认从 8000 开始连续占用两个。
  • vhost __defaultVhost__ :默认虚拟主机。直播和 WebRTC 功能在这里统一开启。
  • http_remux :把 RTMP 流转封装成 HTTP-FLV,这样浏览器可以直接通过 HTTP 拉流播放。
  • hls :切片封装,苹果系的播放器(Safari、iOS)直接播放 HLS 格式。

把这份配置保存到 /opt/srs/conf/docker.conf 。

3.4 启动 SRS 容器

配置文件都放好了,接下来就是启动容器。在 /opt/srs 目录下执行:

docker compose up -d

如果你的 Docker 版本较老,不支持 compose 子命令,可以用:

docker-compose up -d

启动后确认容器状态:

docker ps | grep srs

看到 Up 状态就代表容器正常跑起来了。想看实时日志,执行:

docker logs -f srs

正常情况下日志里会输出类似这样的信息:

SRS 4.0.268
Copyright (c) 2013-2024 The SRS Authors
...
start server(https://github.com/ossrs/srs) success, listen on tcp://0.0.0.0:1935

看到 success 就说明内核已经成功监听在 1935 端口了。

3.5 验证 HTTP API 是否正常

SRS 启动后,可以通过 HTTP API 确认服务状态。执行:

curl http://127.0.0.1:1985/api/v1/versions

如果返回 JSON 中包含 SRS 版本号,说明 API 正常,整个服务已经就绪。

4. 推流与拉流全流程实操

4.1 用 OBS 推流到 SRS

SRS 本身是流媒体服务器,它不负责采集画面,所以需要有推流客户端。最常用的推流工具是 OBS Studio,免费开源跨平台。

打开 OBS 后:

  1. 先添加来源,比如“显示器采集”或“摄像头”,保证画面信号源存在。
  2. 打开“设置 -> 直播”,服务里选择“自定义”。
  3. 服务器地址填: rtmp://你的服务器IP/live
  4. 串流密钥填: test ,这个可以随便写,SRS 默认不做鉴权,但同一个流名的推流会被后者顶掉。
  5. 点击“开始直播”,如果 OBS 右下角的延迟状态变成绿色,代表推流成功。

推流成功后,可以执行下面的命令看 SRS 侧是否识别到了这条流:

curl http://127.0.0.1:1985/api/v1/streams

返回的 JSON 里会有一个 stream 列表,包含你刚才推的流名 test 以及对应的视频编码参数。

4.2 播放:HTTP-FLV 和 HLS

流推上来后,接下来就是播放环节。

播放 HTTP-FLV 的地址格式是:

http://你的服务器IP:8080/live/test.flv

这个地址可以用 VLC、FFplay 或者网页上的 flv.js 播放。FFplay 命令:

ffplay http://你的服务器IP:8080/live/test.flv

播放 HLS 的地址格式是:

http://你的服务器IP:8080/live/test.m3u8

HLS 的响应延迟会比 HTTP-FLV 高不少,因为播放器要按切片周期拉取数据。上面配置里 hls_fragment 6 、 hls_window 60 ,意思是每 6 秒生成一个切片,窗口保留 60 秒内的切片,所以 HLS 最低延迟大概在 6 到 10 秒。如果对延迟敏感,可以把 hls_fragment 调小到 2,但切片越小,HTTP 请求越频繁,对 CPU 和磁盘 IO 的压力也越大。

HTTP-FLV 的延迟就低得多,实测内网环境下往往可以做到 1 秒以内,适合在线互动场景。

4.3 播放:WebRTC 低延迟链路

SRS 4.0 的一个重头戏就是 WebRTC 支持。和 RTMP 推流不同,WebRTC 播放需要 SRS 的 RTC 配置配合,且播放端必须是支持 WebRTC 的浏览器(如 Chrome、Edge、Firefox)。

SRS 提供了内置的 WebRTC 播放页面,直接在浏览器打开:

http://你的服务器IP:8080/players/rtc_player.html

打开后填入流地址: webrtc://你的服务器IP/live/test ,点击播放。

这里需要特别注意 WebRTC 的端口打通问题。网上很多教程只映射了 TCP 端口,忽略 UDP 端口,结果 WebRTC 死活无法播放。因为 WebRTC 是基于 UDP 的实时传输,TCP 端口映射再完美,UDP 不通照样连不上。所以在防火墙/安全组里,除了放行 1935、1985、8080 这三个 TCP 端口,必须额外放行 UDP 8000 和 UDP 8001 这两个端口。

如果 SRS 部署在云服务器上,这些端口需要在云控制台的安全组里配一遍;如果是公司内网服务器,可能还要找运维确认防火墙规则。

4.4 不同协议延迟实测对比

我把同一台服务器上用三种方式播放同一路流的延迟情况整理成了表格(单位毫秒,内网环境实测):

协议 延迟范围 适用场景
HTTP-FLV 300-1000ms 直播互动、网页播放、低延迟监控
WebRTC 200-500ms 视频会议、连麦互动、实时通话
HLS 6000-10000ms 点播回放、广电级直播、兼容所有平台

如果你是个人自建直播服务,HTTP-FLV 是最均衡的选择,兼容性好,延迟也能接受。如果追求极致实时,那就走 WebRTC,前提是网络环境把 UDP 端口打通。

5. 常用操作与 Docker 运维细节

5.1 SRS 容器的启停和日志查看

日常运维中,最常用的 Docker 命令就那几个,我列在这里:

# 查看容器状态
docker ps -a | grep srs

# 停止容器
docker stop srs

# 启动容器
docker start srs

# 重启容器
docker restart srs

# 进入容器内部调试
docker exec -it srs bash

# 实时查看日志
docker logs -f --tail 100 srs

如果容器起不来,先 docker logs -f srs 看看日志,大部分问题日志里都会给出直接线索。比如配置文件写错路径,日志里会直接提示找不到文件。

5.2 配置文件修改后如何让配置生效

SRS 的配置不像 Nginx 那样有 reload 命令,改完配置后只能通过重启容器让配置生效:

docker restart srs

注意重启后之前建立的推流连接会全部断开,所以如果要动配置,最好挑业务低峰期操作。

5.3 推流视频编码参数建议

这里还要补充一个常见的坑:SRS 虽然转封装能力强,但它默认不转码,也就是说视频编码格式直接透传。如果你推流的视频编码是 H.265/HEVC,很多播放器(特别是浏览器)不支持直接播放。为了兼容性,我建议 OBS 推流时把视频编码设置为 H.264,音频编码设置为 AAC,这是目前兼容性最好的组合。

如果推流端性能足够,可以把 OBS 的视频比特率设置在 2500-4500Kbps 之间,分辨率选 720p 或 1080p,帧率 30。这样画质有保障,对服务器和带宽的压力也比较适中。

5.4 数据持久化与备份

SRS 本身不存业务数据,它只是一个流媒体交换机,但配置文件和日志建议做备份。最简单的方案是直接备份整个 /opt/srs 目录:

tar czf srs-backup.tar.gz /opt/srs

日志文件会无限增长,长期不想手工清理的话,可以加一个 cron 任务定时清理超过 7 天的日志:

find /opt/srs/logs -name "*.log" -mtime +7 -delete

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

6.1 问题速查表

这里把我在部署和使用过程中遇到的典型问题列出来,方便你直接对照排查:

症状 可能原因 解决办法
容器启动后立刻退出 配置文件路径写错或端口被占用 看 docker logs srs 定位具体错误;换端口或释放冲突端口
OBS 推流失败 RTMP 端口未放行、地址填错 确认 1935 端口 TCP 通,检查地址是否缺 /live
播放 HTTP-FLV 黑屏 推流编码不支持或路径错误 将视频编码改为 H.264;核对路径和流名
WebRTC 无法播放 UDP 端口 8000/8001 没放行 在防火墙和安全组放行 UDP 8000-8001
镜像拉取慢或超时 Docker Hub 访问不稳定 配置国内镜像加速,换阿里云镜像地址
Docker Desktop 启动失败 虚拟化未开启 启用 Hyper-V 和虚拟机平台,更新 WSL2
修改配置后不生效 容器未重启 执行 docker restart srs
同一个流名被新的推流顶掉 SRS 默认行为 推流时使用唯一流名,或者开启鉴权

6.2 端口冲突怎么看

经常有人问我“为什么容器起来了但就是连不上”。这往往不是容器本身的问题,而是端口被占用了。

排查端口占用用几个命令:

# Linux 上查看端口占用
netstat -tulpn | grep 1935

# 或使用 ss
ss -tulpn | grep 1935

如果发现端口被占用,要么杀掉占用的进程,要么改配置里的端口号。比如把 RTMP 端口改成 19350,只需要在配置里把 listen 1935 改成 listen 19350 ,同时把 docker-compose.yml 的端口映射改成 "19350:19350" ,最后重启容器。

6.3 容器内服务正常但外部不可达

这个问题的排查思路比较固定:先从服务器本机测,再往外测。

# 在宿主机上直接测 API(确认服务本身是否正常)
curl http://127.0.0.1:1985/api/v1/versions

# 如果本机通,再从另一台机器测
curl http://服务器IP:1985/api/v1/versions

本机通、外部不通,基本就是防火墙或安全组的问题。先把防火墙状态查一遍:

systemctl status firewalld

如果开着,直接把需要的端口加进去:

firewall-cmd --permanent --add-port=1935/tcp
firewall-cmd --permanent --add-port=1985/tcp
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --permanent --add-port=8000/udp
firewall-cmd --permanent --add-port=8001/udp
firewall-cmd --reload

云服务器的话,别忘了登录控制台把安全组规则同步更新一下。

6.4 镜像一直拉不下来怎么处理

如果镜像加速配置了还是拉不下来,我的应急方案是从境外的机器上把镜像打包为 tar 文件,再传输到目标服务器加载。

在境外机器上执行:

docker pull ossrs/srs:latest
docker save ossrs/srs:latest -o srs-image.tar

然后把 tar 文件传到目标服务器,执行:

docker load -i srs-image.tar

这样就能绕过 Docker Hub 的访问限制,镜像内容完全一致。

6.5 CPU 和内存占用过高

SRS 本身是很轻量的服务,如果发现 CPU 或者内存持续飙高,优先检查是不是同时推流观看的路数太多,超出了服务器性能范围;其次检查日志,看有没有异常刷屏;还有可能是开了一些不必要的转码功能,比如 SRS 集成了 FFmpeg 转码模块,转码非常吃 CPU。

如果是长期生产环境,建议一开始就加资源限制:

    deploy:
      resources:
        limits:
          cpus: "2.0"
          memory: 2G

这样即使流量突然上涨,SRS 也不会把整个宿主机拖垮。

7. 进阶:SRS 鉴权与多协议扩展

7.1 给推流和播放加个简单的鉴权

默认情况下 SRS 不做任何鉴权,只要知道服务器 IP 和流名谁都能推流和拉流,这对公网环境来说很不安全。生产环境至少要加一层简单的鉴权。

SRS 支持通过 HTTP 回调做鉴权,思路是:推流/播放时,SRS 发送一个 HTTP 请求到你的业务服务器,你的服务器返回允许或拒绝。

配置示例如下:

vhost __defaultVhost__ {
    http_hooks {
        enabled         on;
        on_connect      http://你的回调地址:8085/api/auth;
        on_play         http://你的回调地址:8085/api/auth;
    }
}

回调服务器收到请求后,检查请求参数里的 stream 和 token 字段,返回 HTTP 200 就放行,返回非 200 就拒绝。具体回调参数格式建议参考 SRS 官方文档的 HTTP Hooks 部分。

7.2 用 SRS 做 GB28181 安防流接入

如果你的场景涉及海康、大华这类监控摄像头的接入,SRS 4.0 也支持 GB28181 协议。摄像头的 GB28181 配置里,把 SIP 服务器地址填成 SRS 服务器的 IP,SIP 端口默认是 5060,传输协议选 UDP。接入成功后,SRS 会把摄像头主动上报的 PS 流转成 RTMP/HLS/HTTP-FLV,直接在网页上播放。

这个功能和安防 NVR 的作用很接近,对小规模监控项目来说,SRS 可以省去购买商业 NVR 的成本。

7.3 SRS 集群和 CDN 扩展

当单台服务器的带宽或并发连接数达到瓶颈时,SRS 支持 origin-edge 模式的集群架构。简单说就是一台源站负责接收推流,多台边缘节点负责向观众提供拉流服务,边缘节点回源拉流并转发。配合 Docker Compose,每个边缘节点只需要改动配置里的 origin 地址,就能快速扩展。

集群部署虽然配置会复杂一些,但设计思路并不难理解:origin 接收上游推流,edge 面向用户播放,CDN 的调度策略则可以通过 Nginx 或云负载均衡来做。

8. 写在最后的部署心得

整套流程走下来,我的最大感受是:Docker 把 SRS 的部署门槛降到了几乎为“零”的程度。以前在裸机上编译安装,需要折腾依赖库、系统版本兼容性、服务自启动,半天时间可能都未必能成功。现在从拉镜像到推流成功,熟练的话十分钟之内就能跑通。

但我也要提醒一点:Docker 解决的是部署和运维的问题,流媒体协议本身的选型、网络带宽规划、安全鉴权设计这些问题,仍然需要你根据实际场景去思考和调整。比如做内网监控,HLS 就够用;做直播连麦,就必须 WebRTC;做公网直播,一定要配鉴权,否则会被别人拿来当免费中转服务器。

最后再分享一个操作细节:SRS 的日志默认输出到控制台,但配合 docker-compose 使用 docker logs 查看非常方便。如果你觉得日志太多干扰视线,可以在配置文件里把 srs_log_tank 改成 file ,指向 ./objs/srs.log ,这样日志就会持久化到挂载目录里,用 tail -f 跟踪排查也一样顺手。

这套部署方案我已经在几台不同配置的服务器上验证过,稳定性和性能表现都让人满意。建议你第一次部署时,先按我的最小配置把它跑起来,确认推拉流都正常之后,再根据自己的业务场景逐项加功能。这样即使出了问题,也能快速定位是哪一步引入了新问题。

Logo

邀请您加入社区

更多推荐