想自己搭一个实时音视频流媒体服务,又不想被编译源码、装依赖这些事劝退?用Docker部署SRS是我这些年用下来最省心的一条路。SRS是一个开源的流媒体服务器,全称是Simple Realtime Server,专注于解决直播、RTC、监控等各种实时音视频场景,支持RTMP、HLS、WebRTC、SRT、HTTP-FLV、GB28181这些主流协议,部署起来一条命令就能拉起整套服务。这篇东西我会从选型思路、Docker环境准备、实际部署、推流拉流实操,到最后的排坑心得全部摊开讲,你有基础也好、完全新手也好,照着做基本都能跑起来。

我见过太多人卡在第一步:跑SRS直接去源码编译,结果依赖装到一半崩溃,或者编译完发现版本和文档不一致。其实Docker镜像里早就把这些乱七八糟的依赖处理好了,你要做的只是把端口和配置挂出来,让它替你跑底层那些事。下面我把踩过的坑和真正好用的姿势挨个说清楚。

1. 先搞懂SRS是什么,再决定要不要用Docker

1.1 SRS到底解决了什么问题

市面上能干的流媒体服务器不少,但SRS的定位很明确: 开箱即用、协议覆盖广、性能不错 。它是用C++写的高性能实时服务器,最擅长的场景包括:

  • 直播推流:主播端RTMP推上来,观众端能通过RTMP、HTTP-FLV、HLS多协议观看。
  • WebRTC通话/会议:不需要额外部署MCU或SFU的时候,SRS 5.0及以上本身就支持WebRTC的推拉流。
  • 摄像头/监控接入:通过RTSP拉流,或者GB28181接入,再转成前端能播的格式。
  • 低延迟直播:SRT协议在高丢包网络下表现稳定,适合弱网传输。

如果你只是想Nginx加个RTMP模块随便玩玩,SRS的定位其实是高出一截的——它把HLS切片、HTTP-FLV流、WebRTC信令、集群转发这些能力都集成好了,不用你再去东拼西凑。

1.2 为什么推荐Docker而不是裸机编译

先说裸机方案的痛点。SRS官方提供源码,也提供release包,但裸机部署很容易遇到几个问题:

  • 编译依赖繁琐:需要C++编译器、OpenSSL、FFmpeg依赖库、python工具链等,缺一个就报错。
  • 升级麻烦:每次升级要重新编译,或者替换二进制文件,还可能要迁移配置和数据。
  • 环境隔离差:同一台服务器上如果还跑着Nginx、MySQL、Redis,依赖版本冲突是常有的事。

Docker方案的好处在这些地方体现得特别明显:

  • 秒级启动: docker compose up -d 直接拉起,不需要手动装依赖。
  • 版本可切换:想用SRS 5还是SRS 6,换个镜像tag就行。
  • 不影响主机环境:SRS跑在容器里,所有依赖都封装在镜像中,删除容器不会残留垃圾。
  • 回滚方便:升级后出问题,直接切回上一个镜像就能还原。

有人担心Docker性能损耗,这其实是误解。流媒体服务器主要瓶颈在网络和CPU的编码/转发,Docker本身只是进程级隔离,网络走的是内核NAT或host网络模式,正常配置下性能损耗几乎可以忽略。个人项目、中小团队场景完全没问题,我在生产环境也这么跑过。

2. 环境准备:Docker安装与镜像加速的坑

2.1 Docker和Compose的安装姿势

不管你是Ubuntu、CentOS还是Windows,第一步先把Docker装好。Linux环境下最推荐用官方脚本安装,省事且版本较新:

curl -fsSL https://get.docker.com | bash -s docker

装完顺手把当前用户加入docker组,免得每条命令都要sudo:

sudo usermod -aG docker $USER
newgrp docker

Windows用户建议直接装Docker Desktop,勾选WSL2后端,体验比较完整。不过Windows下跑SRS做生产级服务会涉及端口、防火墙和文件挂载权限问题,个人测试可以,长时间跑还是建议用Linux服务器。

验证是否安装成功:

docker --version
docker compose version

这里有一个经验:老教程里会说“安装docker-compose”,那是独立的Python工具,需要另装。现在的Docker Desktop和新版Docker Engine都集成了 docker compose 插件,命令是 docker compose 而不是 docker-compose 。你如果照着旧教程遇到 docker-compose: command not found ,多半就是版本或安装方式不对。

2.2 镜像加速配置,解决拉取慢

国内拉取Docker官方镜像慢是常态,尤其是比较大的镜像。SRS镜像虽然不大,但如果你还要拉FFmpeg、Ubuntu底包、Nginx等,就要提前配置镜像加速。

配置方法很简单,修改Docker配置 /etc/docker/daemon.json :

{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://docker.1ms.run"
  ]
}

然后重启Docker服务:

sudo systemctl daemon-reload
sudo systemctl restart docker

关于加速器,我更推荐用国内云厂商的容器镜像服务,注册后会给一个专属加速地址,速度和稳定性比公共加速器好得多。你在阿里云或腾讯云控制台搜“容器镜像服务”,找到“镜像加速器”,复制那个地址填进去就行。有些公共加速器过一阵就失效了,填进去白折腾,云厂商的能用很久。

注意:镜像加速只对 docker pull 生效,不影响容器内业务流量。改完daemon.json记得重启Docker,否则不生效。

3. 实战:Docker Compose部署SRS

3.1 目录结构与docker-compose.yml

我建议直接用一个独立目录管理SRS,方便以后升级和迁移:

mkdir -p /opt/srs/conf
cd /opt/srs

然后创建 docker-compose.yml ,内容如下:

services:
  srs:
    image: ossrs/srs:6
    container_name: srs
    restart: unless-stopped
    ports:
      - "1935:1935"       # RTMP/RTSP推拉流
      - "1985:1985"       # HTTP API
      - "8080:8080"       # HTTP Server (HLS/HTTP-FLV/WebRTC)
      - "8000:8000/udp"   # WebRTC UDP媒体端口
      - "8001:8001/udp"   # WebRTC UDP媒体端口
    volumes:
      - ./srs.conf:/usr/local/srs/conf/srs.conf
      - ./objs:/usr/local/srs/objs
    environment:
      - TZ=Asia/Shanghai

这里几个关键点解释一下:

  • image选择 :我用的 ossrs/srs:6 ,对应SRS 6.x,WebRTC和SRT支持比5.0更完善。如果你要稳定保守, ossrs/srs:5 也可以,区别在于RTC相关的配置项有所变化。
  • 端口映射 :1935是RTMP入口,外网推流都走这里;8080是HTTP服务,HLS切片和HTTP-FLV都在这个端口输出;1985是HTTP API,用于管理、统计、鉴权回调;8000/8001是WebRTC的UDP媒体传输端口,很多新手漏配这两个,结果WebRTC死活拉不了流。
  • 数据卷挂载 :把 ./srs.conf 挂进去方便自行修改配置; objs 目录是SRS运行产生的日志和HLS临时切片,挂载到宿主机方便排查问题。
  • restart策略 : unless-stopped 表示容器因异常退出会自动重启,但手动stop后不会硬拉起来,比较符合运维直觉。

3.2 配置文件srs.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             ./objs/nginx/html;
}

vhost __defaultVhost__ {
    hls {
        enabled         on;
        hls_fragment    2;
        hls_window      6;
    }
    http_remux {
        enabled         on;
    }
    rtc {
        enabled         on;
    }
}

说明几个容易迷惑的配置项:

  • daemon off :容器里必须用 off ,因为前台运行才能被Docker的日志和进程管理捕获。
  • srs_log_tank console :日志输出到标准输出,这样我们直接用 docker logs 就能看到。
  • hls_fragment 2 :切片长度设成2秒,延迟更低。默认是5秒,追求低延迟时可调小,但会增加服务器切片次数和海量小文件,生产环境要根据观看规模权衡。
  • http_remux :HTTP-FLV拉流靠这个模块,不开启的话 xxx.flv 地址无法访问。
  • rtc enabled on :开启WebRTC支持。注意SRS 6的配置已经和5.x有差异,这个写法是6.x的格式。

写完配置后,启动服务:

docker compose up -d

看下容器状态和日志:

docker ps
docker logs -f srs

日志中出现类似“SRS is running”的字样,说明启动正常。这时候可以访问 http://你的IP:8080/ ,能看到SRS的默认目录页面;访问 http://你的IP:1985/api/v1/versions ,能返回JSON版本信息,说明HTTP API也通了。

3.3 自定义配置后怎么生效

改 srs.conf 之后不用重新创建容器,只需要:

docker compose restart srs

这个操作的逻辑是:配置通过volume挂载进容器,重启容器后SRS重新加载,所以改动就能生效。如果改坏了起不来,用 docker logs srs 看报错,通常能定位到是配置语法还是端口冲突。

4. 推流拉流实战:把视频送进去再取出来

4.1 推流:FFmpeg循环推一个文件

SRS部署起来只是把路修好了,真正要看到画面,还得有“车”开上去。最常用的推流工具就是FFmpeg。本地没有视频文件的话,可以下一段MP4,然后执行:

ffmpeg -re -stream_loop -1 -i /data/test.mp4 -c copy -f flv rtmp://127.0.0.1:1935/live/stream

命令拆开看:

  • -re :按原视频帧率读取,避免以最快速度推完,这是推流的关键参数。不加这个,FFmpeg会拼了命地读文件,几秒钟就把整个视频推完。
  • -stream_loop -1 :无限循环播放这个文件,直播流就不会中断。
  • -c copy :直接复制编码流,不重新编码,CPU占用极低。前提是视频编码是H.264、音频是AAC,这是浏览器和播放器最通用的组合。如果视频是H.265或其他编码,前端播放会黑屏,得用 -c:v libx264 转码。
  • -f flv :指定输出封装格式为FLV,RTMP协议只支持FLV封装。

推流几分钟后,可以在SRS日志里看到连接建立和断开的记录。如果不想敲命令,也可以用OBS Studio推流,服务器地址填 rtmp://你的IP:1935/live ,串流密钥填 stream ,效果是一样的。

4.2 拉流测试:RTMP、HTTP-FLV、HLS

验证流有没有推上去,最简单的方法是拿播放器拉流。我常用的几种方式:

  • RTMP地址: rtmp://ip:1935/live/stream ,用VLC或者ffplay可以直接播。
  • HTTP-FLV地址: http://ip:8080/live/stream.flv ,浏览器里也可以用VLC插件或flv.js播放,移动端兼容性也不错。
  • HLS地址: http://ip:8080/live/stream.m3u8 ,这个最通用,iOS的Safari、网页 <video> 标签都能直接放。

用ffplay测试最省事:

ffplay rtmp://127.0.0.1:1935/live/stream
ffplay http://127.0.0.1:8080/live/stream.flv
ffplay http://127.0.0.1:8080/live/stream.m3u8

三个地址都能出画面,说明RTMP模块、HTTP-FLV模块、HLS模块都正常。我从实践经验说,HTTP-FLV是现在Web端最稳妥的协议,延迟在可接受范围,实现成本低;HLS适合点播和对延迟不敏感的场景;WebRTC延迟最低,但部署复杂度也最高,下一节单独说。

4.3 摄像头RTSP流接入:从“找流地址”到真正用起来

很多人部署SRS不是为了自己推流,而是想把家里的摄像头、公司监控或者网上找来的公开直播源接入自己的平台。这类需求本质上都涉及一个动作: 拉取RTSP/RTMP源,再转成前端能播的格式 。

摄像头通常暴露RTSP地址,格式类似 rtsp://用户名:密码@IP:554/stream1 。把摄像头流接入SRS,用FFmpeg转推:

ffmpeg -rtsp_transport tcp -stimeout 5000000 -i "rtsp://admin:password@192.168.1.100:554/stream1" -c copy -f flv rtmp://127.0.0.1:1935/live/camera1

这个命令比前面的文件推流多了几个关键参数:

  • -rtsp_transport tcp :强制走TCP拉RTSP流。默认可能是UDP,监控网络丢包严重时画面会花屏、卡顿,TCP模式稳定很多。代价是稍微增加带宽占用,但对局域网场景完全不是问题。
  • -stimeout 5000000 :设置网络超时,单位是微秒,也就是5秒。摄像头流断线或者网络抖动时,FFmpeg进程能在5秒后主动退出,配合守护进程脚本就能实现自动重连。不加这个参数,FFmpeg可能一直卡在阻塞状态,怎么等都等不到它退出。

摄像头源断线重连是监控场景最大的坑,我建议用一个循环脚本来跑转推命令:

#!/bin/bash
while true; do
  ffmpeg -rtsp_transport tcp -stimeout 5000000 -i "rtsp://admin:password@192.168.1.100:554/stream1" -c copy -f flv rtmp://127.0.0.1:1935/live/camera1
  echo "FFmpeg exited, restarting in 3s..."
  sleep 3
done

把脚本挂到systemd服务或者用supervisor管理,基本能做到断线自动恢复。很多朋友拿着一堆“直播源地址”想接进自己的播放器,思路也是类似的:先用FFmpeg把这些RTMP/HTTP-FLV源拉到本地SRS,再统一输出成HLS或WebRTC给前端,中间还能做转码、录制、截图,这就是一套最原始的“流媒体中台”了。

4.4 WebRTC拉流:低延迟但注意这些细节

SRS 6对WebRTC的支持已经很成熟,地址格式是:

webrtc://ip:8080/live/stream

但这里有一个大坑: WebRTC在非localhost环境下强制要求HTTPS ,否则浏览器直接拒绝访问摄像头和播放流。如果你只是在本机测试,用 webrtc://localhost:8080/live/stream 可以通;但如果要在局域网或公网给其他设备播放,必须有HTTPS证书。

最简单的做法是用Caddy或者Nginx做反向代理,把 https://你的域名:443 转发到SRS的8080端口,并在代理层处理好WebRTC需要的UDP端口转发。SRS官方文档有Nginx反代WebRTC的完整配置,这里我建议新手先用HTTP-FLV把业务跑起来,等有时间再折腾WebRTC,因为WebRTC涉及证书、UDP端口、ICE候选等多个环节,任何一个没配好都白屏,排查起来比较费时间。

SRS的WebRTC底层其实帮你处理了TURN/STUN的大部分逻辑,但UDP端口不映射到宿主机、防火墙不开UDP,媒体数据就传不过去。所以再次提醒: 配置里8000/8001的UDP映射不能少 。

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

5.1 镜像拉取慢或超时

这几乎是新手必踩的坑。处理方法就是前面说的配置 registry-mirrors 。如果配置了加速器还是慢,可以考虑直接拉阿里云等云平台上的镜像副本,或者干脆用代理环境把镜像导出再导入到目标服务器。另外建议查看当前镜像信息:

docker inspect ossrs/srs:6 --format '{{.RepoDigests}}'

确认镜像完整度,有时候半途中断的pull会留下残缺层,重新 docker pull 一次即可。

5.2 推流报错或连接被拒绝

FFmpeg推流提示 Connection refused ,优先排查三件事:

  • 容器是不是真的起来了: docker ps 看有没有退出。
  • 1935端口有没有映射: ss -lntp | grep 1935 。
  • 防火墙有没有放行TCP 1935。

如果是腾讯云、阿里云这类服务器,还要去控制台安全组里放行端口,这是最容易忽略的,很多人在服务器本地测试没问题,外部一访问就失败,锅就在安全组。另外SRS默认最大连接数是1000,如果连接数打满了,会拒绝新连接,适当调大 max_connections 。

5.3 画面卡顿、延迟高

HLS切片默认可能是5秒甚至更长,总延迟自然高。想降低延迟,把配置里的 hls_fragment 调到2,再打开HTTP-FLV通道。播放器选择也很重要,VLC播HTTP-FLV延迟不高,但网页里播放要注意用flv.js的 live 模式,不要去走进度条。

如果推流端CPU拉满,多半是ffmpeg在转码而不是copy,检查是不是解码格式问题导致 -c copy 失效。用 ffprobe 看下源文件编码,如果是H.265但没有H.265解码能力的播放器,前端会黑屏,这种场景就必须转码。

5.4 WebRTC能推不能拉,或者拉流黑屏

这个问题我在5.0时代被折磨过很久。排查顺序:

  • 确认浏览器是通过HTTPS访问的页面(localhost除外)。
  • 确认容器映射了UDP 8000/8001,并且服务器防火墙同时放行了UDP端口。
  • 确认SRS版本和配置项匹配。WebRTC相关配置在5.x和6.x之间有过调整,照着旧教程配新版本容易踩坑。
  • 看SRS日志里有没有报 ICE 、 DTLS 错误,这些通常指向UDP端口不通。

如果以上都检查完还不行,用官方自带的WebRTC测试页面 http://ip:8080/players/rtc_player.html 测试。这个页面能直接播放rtc流,还能给出详细的错误提示,比你自己写的播放器更容易定位问题。我自己排查的时候,经常先用这个页面确认SRS本身没问题,再去改前端。

5.5 容器日志太多、磁盘被撑满

SRS开启HLS后会产生大量切片文件,默认配置下临时文件都在 objs 目录。解决办法是定期清理,或者把HLS切片放到内存盘/tmpfs,再或者调大 hls_window 让旧切片尽快被删除。挂载的 ./objs 目录在宿主机上长期运行,建议写个cron定时清理:

find /opt/srs/objs/nginx/html -name "*.ts" -mmin +10 -delete

还有 docker logs 本身也会持续增长,SRS在调试模式下日志量很大,容器跑久了 /var/lib/docker/containers 会占不少空间。建议在 daemon.json 里加上日志轮转:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "20m",
    "max-file": "5"
  }
}

改完重启Docker,新容器的日志才会被限制大小。

6. 部署之外的几点扩展思路

SRS容器跑起来只是第一步,真正要投入使用时,有几个方向值得继续深入:

  • 鉴权与安全 :默认配置下,SRS的HTTP API没有任何鉴权,任何能访问1985端口的人都能查到你的服务器信息甚至调接口。如果服务暴露在公网,建议用Nginx反代加一层Token校验,或者配置SRS的 http_api 的鉴权回调,回源服务器验证推拉流地址的合法性。
  • 录制与回放 :SRS支持DVR录制,推上来的流可以直接落盘成FLV或MP4文件。结合HLS切片,可以很容易做点播回放。
  • 集群扩展 :一台SRS扛不住高并发时,用SRS的Origin/Edge集群架构,Edge节点做分流和缓冲,Origin节点处理源流和转码,在Docker里可以通过多个Compose服务编排起来。
  • 监控指标 :SRS的HTTP API能输出 /api/v1/streams 列表和 /api/v1/clients 在线状态,写个脚本定时抓取,推给Prometheus或者钉钉告警,就能实现简单的流健康监控。

我在实际使用中最大的体会是,Docker化的SRS把部署的复杂度降到了一个很低的水位,让人能把精力放在真正重要的事情上——比如流怎么组织、延迟怎么优化、播放端体验怎么提升。如果你只是自己折腾,照着这篇文章跑到WebRTC能拉流就已经很完整了;如果你是想拿它支撑业务,建议把官方文档的“配置”和“API”章节通读一遍,尤其是 vhost 、 token 和 http_hooks 这几块,那才是SRS真正值钱的地方。

Logo

邀请您加入社区

更多推荐