ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Docker部署SRS流媒体服务器:从推流到WebRTC的完整实践

2026/9/16 1:22:32 拓冰建站 浏览量
Docker部署SRS流媒体服务器:从推流到WebRTC的完整实践 做直播服务或者实时音视频应用的开发者对 SRS 应该不陌生。这个国产开源流媒体服务器一台普通机器就能扛住不小的并发支持 RTMP、HTTP-FLV、HLS、WebRTC、SRT 这些主流协议很多在线教育、电商直播、安防监控、视频会议项目都是在它上面长出来的。不过以前要在生产环境跑起来得先编译、配依赖、调环境一套流程下来没几个小时搞不定。用 Docker 部署 SRS 之后这个门槛被拉得很低——一条命令启动服务一个配置文件描述业务想回滚版本也只是一行 docker tag 的事。这篇文章我不打算写成官方文档的复读机而是把我从零开始用 Docker 跑通 SRS 实时音视频链路的全过程拆开来讲包括环境准备、端口规划、推流配置、鉴权回调、常见坑排查。内容覆盖从“先跑起来”到“生产可用”的完整路径适合正在选型流媒体服务、打算自建直播平台或者被云厂商带宽费逼到想自建的同学参考。1. 为什么选 Docker 部署 SRS1.1 SRS 到底能解决什么问题实时音视频服务最麻烦的不是媒体协议本身而是协议太多、链路太长。客户端推流用 RTMP网页播放想用 HTTP-FLV苹果生态要 HLS低延迟通话又得走 WebRTC不同端不同协议服务端如果每种协议都自研一套工作量直接爆炸。SRS 做的事情就是把这些协议统一收编。它接收 RTMP 推流内部转封装成 FLV、HLS也能桥接 WebRTC 的低延迟传输开发者不需要关心底层错综复杂的协议转换。配合 Docker 之后整个服务变成一个黑盒镜像映射几个端口就能对外提供服务我本地 macOS 和线上 Linux 服务器跑的是同一套镜像行为完全一致这是源码编译很难做到的。1.2 和源码编译部署相比Docker 好在哪里我第一次接触 SRS 的时候官方文档推荐源码编译。在 CentOS 上要装 gcc、make、pcre-devel、openssl-devel编译一次十分钟起步中间只要某个依赖版本不对就要花半小时上网查错误。后来切到 Docker整体感受是两个词干净、可回滚。对比项Docker 部署源码编译部署环境依赖无需安装镜像内置需要 gcc、make、各种 devel 包部署耗时分钟级编译至少 30 分钟版本回滚切换镜像 tag 即可需要重新编译或备份二进制多机扩展镜像一致性强每台机器环境容易漂移资源隔离容器级隔离可限 CPU/内存进程级依赖宿主机环境我最看重的是可回滚。有一次线上需要升级 SRS 小版本源码部署的话要先备份原二进制再重新编译替换出问题很难迅速退回。Docker 部署只需要把 compose 文件里的镜像 tag 改回去再 up 一次十几秒就回到旧版本。1.3 哪些场景适合这套方案如果你属于下面几类情况Docker 部署 SRS 是性价比很高的路径中小团队自建直播服务不想被云厂商的流量费绑死在线教育、陪练、远程医疗需要低延迟音视频互动安防监控项目需要把摄像头 RTSP 流转成网页可播放的流短视频、UGC 产品要做开播、连麦、录制回放功能这套方案的优势在资源可控。云厂商的 CDN 按流量计费高峰期费用吓人自建 SRS 之后只要带宽规划合理一台 4 核 8G 的云主机就能服务几千路直播观看边际成本低很多。2. 部署前的准备工作2.1 硬件与系统要求SRS 本身对硬件要求不高纯转发场景 1 核 1G 的机器都能跑但真要考虑生产使用需要结合码率和并发量估算。一个简单的估算方法视频码率乘以同时观看人数就是服务器需要承担的下行带宽。假设直播码率是 2Mbps同时有 100 人观看下行带宽需要约 200Mbps换算成字节是 25MB/s 的持续吞吐。这种量级下CPU 主要消耗在协议转封装上WebRTC 转播会比纯 RTMP 转发多吃一些 CPU4 核起步比较稳。内存方面SRS 进程本身占用很低容器内通常不到 100MB但 HLS 切片、录制文件会写磁盘需要考虑磁盘 IO 和容量。我实践中发现720p 视频 2Mbps 码率一小时录制大约 900MB 磁盘做录像回放功能时要按这个量级规划磁盘空间。2.2 端口规划与防火墙放行SRS 不像普通 Web 服务只开一个端口它根据功能不同监听多个端口部署前必须想清楚端口映射关系。端口协议用途1935TCPRTMP 推流与播放1985TCPHTTP API用于查询流状态、触发回调8080TCPHTTP 服务用于 HTTP-FLV、HLS 播放和管理控制台8000UDPWebRTC 媒体传输8001UDPWebRTC 媒体传输多路复用这里面最容易漏的是 8000/8001 的 UDP 端口。很多同学 1935、8080 都映射了结果 WebRTC 播放一直黑屏排查半天发现是云服务器安全组没放行 UDP 端口。RTMP 和 HTTP 都走 TCP云控制台一般默认放行UDP 经常被忽略。如果你在本地虚拟机测试还要注意宿主机防火墙。CentOS 上用 firewalld 的话需要执行firewall-cmd --add-port1935/tcp --add-port8080/tcp --add-port8000/udp --add-port8001/udp --permanent并 reload否则外部设备推流拉流都会被拦。2.3 Docker 环境安装要点安装 Docker 这一步不同系统坑不一样。Linux 上比较省心用官方脚本安装后启动服务就行。Windows 和 macOS 需要安装 Docker Desktop这里面有一个高频报错经常把人卡住——Docker Desktop 启动时提示 Virtualization support not detected。这通常不是 Docker 的问题而是系统虚拟化没开。Windows 需要确认三件事BIOS 里开启 Intel VT-x 或 AMD-VWindows 功能里启用“适用于 Linux 的 Windows 子系统”和“虚拟机平台”然后执行wsl --set-default-version 2。改完这些重启 Docker Desktop 就能正常启动了。安装完成后用docker --version和docker compose version验证两个命令都有输出环境就算准备好了。3. 直接用 docker run 快速启动 SRS3.1 一条命令跑起来如果想最快看到效果直接执行下面这条命令docker run -d --name srs \ -p 1935:1935 \ -p 1985:1985 \ -p 8080:8080 \ -p 8000:8000/udp \ -p 8001:8001/udp \ registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5.0-r2这里用了阿里云镜像仓库的地址国内服务器拉取速度快避免 Docker Hub 超时。镜像 tag 选择5.0-r2是 SRS 5.0 系列比较稳定的版本能同时支持 RTMP 和 WebRTC。启动后执行docker logs -f srs看日志出现start server successfully就说明 SRS 已经起来了。这时候在浏览器访问http://服务器IP:8080/console/能看到 SRS 自带的管理控制台当前流列表、连接数、CPU 占用都有非常适合初期验证。注意这条命令用的是默认配置。默认配置下 WebRTC 的 candidate 会被设置成容器内网 IP导致局域网外的设备无法建立 WebRTC 连接。本地测试没问题如果要让外部设备也连得上需要自定义配置下一章会详细讲。3.2 验证服务是否正常服务起来之后先别急着推流用 API 接口快速验证一下curl http://服务器IP:1985/api/v1/versions正常会返回版本信息 JSON。再查一下流列表curl http://服务器IP:1985/api/v1/streams此时应该返回空数组。等推流上去之后再请求这个接口就能看到流的 meta 信息包括推流地址、视频分辨率、码率、在线观看人数。我在做监控脚本时就靠这个接口定期拉取流状态实现自动报警。3.3 默认配置有哪些限制默认配置适合体验但直接上生产肯定不行主要限制有三个。默认不开启 HTTP-FLV 转封装网页端无法通过 FLV 地址拉流。默认不开启 HLS苹果设备无法直接播放。WebRTC 的 candidate 指向容器内部 IP外部设备连不上。这三个问题的根源都是配置太简略需要自己挂载一份完整配置。下一章讲 docker compose 的时候就一并解决。4. 用 docker compose 搭建生产级 SRS4.1 编写 compose 文件我建议任何稍微正式的部署都用 docker compose原因很简单端口映射、数据卷挂载、环境变量、重启策略都写在文件里换机器部署不用回忆当初敲了什么命令。下面是我实际使用的 compose 文件version: 3.9 services: srs: image: registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5.0-r2 container_name: srs restart: always ports: - 1935:1935 - 1985:1985 - 8080:8080 - 8000:8000/udp - 8001:8001/udp environment: - CANDIDATE127.0.0.1 volumes: - ./conf/srs.conf:/usr/local/srs/conf/srs.conf - ./data:/usr/local/srs/objs/nginx/html logging: driver: json-file options: max-size: 50m max-file: 3先创建项目目录把上面的内容保存为docker-compose.yml然后根据需求编写conf/srs.conf最后执行docker compose up -d。这里有几个细节值得说明。restart: always保证机器重启后 SRS 自动拉起避免人工干预。logging配置防止容器日志无限增长撑爆磁盘。./data挂载目录是 HLS 切片和录制文件的输出位置必须放到宿主机持久化否则容器重建历史录像全丢。4.2 配置文件的重点解析SRS 的配置格式类似 nginx注释用#层级通过花括号表示。下面是一份支持 RTMP 推流、HTTP-FLV/HLS 播放、WebRTC 低延迟播放、HTTP API 查询的完整配置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; candidate ${CANDIDATE}; } vhost __defaultVhost__ { http_remux { enabled on; mount [vhost]/[app]/[stream].flv; } hls { enabled on; } }配置里的关键点listen 1935是 RTMP 入口max_connections决定最大连接数我自己线上压过 500 并发8G 内存的机器非常稳。http_api开启后1985 端口提供 API后面的鉴权回调也依赖它。http_remux是重点开启后 RTMP 流自动转成 HTTP-FLV网页播放器可以拉http://ip:8080/live/livestream.flv播放。rtc_server配了 candidateWebRTC 能否连通的关键就在这个字段。4.3 candidate 参数为什么必须设置WebRTC 不同于 RTMP 这种服务器中转模式它要协商出 P2P 或媒体服务器的传输地址。SRS 在容器里运行时默认探测到的 IP 是容器的内网地址外部浏览器拿到这个地址根本连不上。我在 compose 里通过环境变量传入宿主机的 IPenvironment: - CANDIDATE你的服务器公网IP或内网IP配置文件中写candidate ${CANDIDATE}SRS 启动时会自动读取环境变量并替换。如果只在局域网内测试填宿主机内网 IP 就行比如192.168.1.100。如果要公网访问必须填公网 IP同时确保 8000/8001 的 UDP 端口在防火墙和安全组里放行。有个调试技巧如果 WebRTC 播放失败先看一下 SRS 日志里 candidate 实际用的是什么 IP和浏览器协商的地址是否一致。大多数 WebRTC 连不上的问题都是 candidate 配置错误。5. 推流与播放实测打通第一个直播链路5.1 用 OBS 推流到 SRS服务端配好了接下来做一次完整的推流播放测试。我推荐用 OBS免费且跨平台。打开 OBS 后进入“设置 - 直播”服务选择“自定义”服务器填rtmp://服务器IP:1935/live串流密钥填livestream点“开始直播”如果服务端配置没问题几秒内 OBS 状态栏会显示“直播中”。这时候回到 SRS 管理控制台就能在流列表里看到一条live/livestream的流包括分辨率、码率、帧率信息。注意串流密钥不要包含特殊符号SRS 默认配置下密钥里带?或/会有歧义。我习惯把app固定为livestream用业务 ID比如直播间号、设备序列号这样后面做流转发和录制都好区分。5.2 用 ffmpeg 验证推流OBS 适合人工测试如果要脚本化验证推荐用 ffmpeg。把一段视频循环推到 SRSffmpeg -re -stream_loop -1 -i test.mp4 \ -c copy -f flv rtmp://服务器IP:1935/live/livestream-re表示按视频原始帧率读取模拟实时推流而不是瞬间推完。-stream_loop -1让视频无限循环。-c copy直接复制编码数据不重新编码CPU 占用极低。跑起来后再拉流验证ffplay rtmp://服务器IP:1935/live/livestream能看到画面就说明整个 RTMP 链路已经通了。5.3 各种播放协议地址对照SRS 最方便的地方是一条推流多种协议播放。推流地址是rtmp://ip:1935/live/livestream那么对应的播放地址如下协议播放地址适用场景RTMPrtmp://ip:1935/live/livestream传统播放器、低延迟要求低HTTP-FLVhttp://ip:8080/live/livestream.flv浏览器播放、PC 直播HLShttp://ip:8080/live/livestream.m3u8苹果设备、点播兼容WebRTCwebrtc://ip:8080/live/livestream低延迟互动、连麦延迟层面RTMP 和 HTTP-FLV 通常 1 到 3 秒HLS 会因为切片缓冲延迟到 5 到 10 秒WebRTC 可以做到 500 毫秒以内。做在线答题、连麦互动必须上 WebRTC纯直播观看用 HTTP-FLV 就够了没必要增加 WebRTC 的复杂度。6. 后端鉴权与 HTTP 回调把控制权握在自己手里6.1 为什么推流接口不能裸奔服务跑起来之后最紧急的事情是加鉴权。SRS 默认情况下只要知道你的 IP 和端口任何人往你的 1935 端口推流你的服务器就得转发、存储相当于被人白嫖了带宽和磁盘。更危险的是你正在直播的内容可能被别人用你的服务器转播到其他平台。有两种思路做鉴权内置 token 和 HTTP 回调校验。内置 token 配置简单但 token 拼在 URL 里容易在日志中泄露。HTTP 回调方式更灵活由你自己的后端服务决定是否允许推流和播放适合已有用户体系的业务。6.2 用 HTTP 回调实现对推流和播放的鉴权SRS 在推流开始、推流结束、播放开始、播放结束这几个节点会向配置好的回调地址发 HTTP 请求。我在 vhost 配置里加上vhost __defaultVhost__ { http_hooks { enabled on; on_publish http://宿主机IP:7000/srs/publish; on_unpublish http://宿主机IP:7000/srs/unpublish; on_play http://宿主机IP:7000/srs/play; on_stop http://宿主机IP:7000/srs/stop; } }回调 JSON 里会带上app、stream、paramparam 就是 URL 里的查询参数。比如推流地址写成rtmp://ip:1935/live/livestream?tokenabc123后端收到 on_publish 回调后解析 token 字段判断是否合法。返回0表示允许返回非 0 值 SRS 就会拒绝推流。注意一个容器网络细节SRS 容器内的 localhost 和宿主机不是同一个回调地址不能写http://localhost:7000。在 Linux 上可以用http://172.17.0.1:7000这是 Docker 默认网桥的宿主机地址。如果用的是 Docker Desktop直接写http://host.docker.internal:7000更方便。6.3 录制与 HLS 回看的配置技巧很多直播业务需要自动录制SRS 支持在推流时直接存成 FLV 文件。vhost 里加一段vhost __defaultVhost__ { dvr { enabled on; dvr_path ./data/[app]/[stream].[timestamp].flv; dvr_plan session; } }dvr_plan session表示每个推流会话存一个文件推流断开文件就封存。dvr_path支持按变量自动分目录我用[app]和[stream]区分不同直播间。录制文件默认存在容器内的工作目录但我在 compose 里挂载了./data到宿主机所以文件会直接写在宿主机上方便后续转存对象存储或做点播系统。这里要提醒一句录制文件增长很快一定要配合定时清理策略比如用 crontab 删除 7 天前的文件否则再大的磁盘也扛不住。7. 常见问题与排查技巧实录7.1 Docker 启动失败与环境问题SRS 容器起不来先看日志docker logs srs。最常见是端口被占用报错信息里会明确说 listen 端口失败。用netstat -tlnp | grep 1935查一下占用进程改掉冲突的端口映射就行。Windows 上 Docker Desktop 特别容易遇到Virtualization support not detected的报错这个我在前面说过本质是系统的硬件虚拟化或 WSL2 没开。还有一个容易被忽略的点改完 BIOS 虚拟化设置后如果 Windows 功能里的“虚拟机平台”没勾选Docker Desktop 依然起不来。7.2 WebRTC 播放黑屏或卡在连接中WebRTC 连不上是最让人头疼的因为表面现象只是黑屏日志信息还少。按这个顺序排查先确认 8000/8001 UDP 端口在防火墙和安全组放行用nc -u -z或 telnet 测试 UDP 端口连通性。然后看 SRS 日志里 candidate 的实际值docker logs srs | grep candidate。最后用浏览器控制台看 WebRTC 的 ICE candidate 信息如果显示的 IP 和服务器公网 IP 不一致说明 candidate 配置有问题。我踩过一次很隐蔽的坑云服务器有内网 IP 和公网 IP 两张网卡填公网 IP 后发现服务器自身无法通过 WebRTC 播放是因为公网 IP 的 UDP 包被安全组拦了。最后发现安全组只放行了 TCP 端口UDP 没放。这个问题排查了我一个下午。7.3 推流失败或频繁断开OBS 推流几秒后断开先看是不是 token 校验失败。如果没用 token关闭鉴权测试一次。排查网络层面尝试从服务器本机推流ffmpeg -re -i test.mp4 -c copy -f flv rtmp://localhost:1935/live/test本机能推通则说明是防火墙或云安全组的问题。还有一种情况是推流地址写错了。RTMP 推流地址的结构是rtmp://ip:port/app/streamapp和stream不能随意带路径分隔。如果配了 HTTP 回调要确认回调地址返回了0返回非 0 会被 SRS 判定为拒绝推流。7.4 延迟和画质的调优方向如果你对延迟有要求优先用 WebRTC 或 HTTP-FLV不要用 HLS。HLS 的切片时长直接决定延迟下限SRS 默认是 10 秒一个切片浏览器播放还要缓冲几个切片延迟很容易到 30 秒。可以把 hls 配置里的切片时长调小hls { enabled on; hls_fragment 2; hls_window 10; }画质方面SRS 本身不做转码画质取决于推流端的码率设置。OBS 里建议视频码率设 3000 到 6000Kbps关键帧间隔 2 秒编码器用硬件编码降低 CPU 占用。7.5 安全加固的几条建议最后说安全。自建流媒体服务暴露在公网等于给所有人开了一扇门不加防护迟早被刷流量甚至植入恶意内容。端口尽量只放行业务需要的。如果管理控制台不需要公网访问8080 端口在安全组里只对办公网 IP 开放。升级域名尽量走 HTTPS/WSSSRS 5.0 支持在配置里挂证书避免播放地址被运营商劫持。对推流接口做 token 校验对播放接口做防盗链校验这些都是上线前必须完成的动作。容器本身也要限制资源compose 里加上deploy: resources: limits: cpus: 2.0 memory: 2G防止某个直播间流量异常时把整台机器拖垮。日志大小限制我前面已经写在 logging 配置里生产环境千万别省略这个不然/var/lib/docker被日志撑爆的教训会很难忘。这套 Docker 加 SRS 的组合我在线上稳定跑了大半年最深刻的体会是流媒体服务并没有想象中那么遥不可及关键是选对工具、把基础配置吃透。如果你也准备自建实时音视频平台照着这篇文章的路径走一遍先把 RTMP 推流和 HTTP-FLV 播放跑通再一步步加 WebRTC、鉴权、录制这些高级功能整个过程会比预想中顺利很多。最后再分享一个小技巧SRS 的配置文件和 nginx 很像改配置之前一定先备份上线前用docker compose config检查一下 compose 文件的语法很多低级错误都能提前发现。