news 2026/11/5 15:21:51

自建直播服务器选型与SRS部署实战:RTMP/HLS/HTTP-FLV全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
自建直播服务器选型与SRS部署实战:RTMP/HLS/HTTP-FLV全解析

很多人第一次接触"直播服务器"这个词,第一反应是那些商业直播平台的推流地址、控制台、付费带宽。但当你只是想在公司内网做一个活动直播、给远程课程搭一个在线教室、或者把某个监控画面送给团队看时,真正的需求其实很朴素——我要一个能接收推流、转发给多个观看者的程序。自己搭直播服务器,本质上就是把这个程序跑起来,然后填对几个地址。这篇文章我打算从直播链路的基本逻辑讲起,再到选型对比、实际部署、推流拉流全流程,最后把我在真实使用中踩过的坑一并说出来。适合想自建直播服务、又不想一上来就被复杂概念劝退的朋友。

1. 直播链路的核心:推流、分发、播放到底谁在干活

1.1 一条直播流的完整旅程

很多人以为直播就是"编码器把画面发出去,播放器能收到",中间那块其实是个容易被忽略的关键环节。一条典型的直播流要经过三个角色:推流端(OBS、手机、摄像头)、流媒体服务器(我们这篇文章的主角)、播放端(VLC、浏览器、小程序)。

推流端把画面和声音压缩成流,通过RTMP协议推到服务器;服务器不是简单地把字节转手,它会做接收、校验、转封装、分发这一系列动作;播放端再从服务器按需拉取。简单理解,直播服务器像一个快递中转站:各家推流端是把包裹送进站的货车,服务器是中转场的分拣线,播放端是来取件的人。货车只有一辆没关系,分拣线可以同时供很多人取件。

这个模型能解释很多实际问题:为什么推流端只有一个,观看端却可以几百人?因为服务器在中间做了分发。为什么换了播放协议,延迟差别很大?因为中转站对包裹的处理方式不同,有的直接放行(低延迟),有的重新打包(高延迟)。理解了这个角色划分,后面所有配置都不会再觉得混乱。

1.2 协议怎么选:RTMP、HTTP-FLV、HLS、WebRTC

直播服务器就像中转站,但它和不同运输车队(协议)打交道的成本不一样。我直接用四个最常见的协议来说明差异。

  • RTMP:Adobe当年为Flash直播设计的协议,至今仍是推流端的事实标准。TCP长连接,延迟可以做到1-3秒。OBS、FFmpeg推流几乎都走它。播放端也能拉RTMP,但不是所有浏览器都支持,所以现在更常用于推流。
  • HTTP-FLV:把RTMP里的视频数据用HTTP方式传输,浏览器里通过flv.js这类播放器就能播放。延迟通常在2-5秒,比RTMP稍高一点,但在浏览器场景里非常实用。
  • HLS:苹果提出的协议,服务器把流切成一小段一小段的ts文件,播放器按顺序拉取。兼容性最强(iOS、Android、PC浏览器都行),但延迟通常有10-30秒,因为切片本身就有时间损耗。
  • WebRTC:浏览器之间点对点音视频通信的标准,用在直播分发上延迟可以低到几百毫秒。缺点是部署相对复杂,需要HTTPS环境。

我打个比方:RTMP是直达班车,适合从出发地运到中转站;HTTP-FLV是普通快递,不快但很好使;HLS是挂号信——安全稳妥,就是要多等几天;WebRTC是同城闪送,快得能感觉到实时,但价格和门槛也高。

日常使用中,推流几乎固定用RTMP,播放端则按场景选。要兼容性就HLS,要低延迟就用HTTP-FLV,追求极致低延迟且能接受配置成本就上WebRTC。大部分内网直播场景,我在播放端用HLS或HTTP-FLV就够了。

2. 自建方案选型:为什么我最终常用SRS

2.1 三条常见的路:Nginx-RTMP、MediaMTX、SRS

说到自建直播服务器,很多人查到过的方案无非三类:用Nginx加RTMP模块、用MediaMTX、用SRS。这三条路我都实际跑过,分别说一下我的感受。

  • Nginx + nginx-rtmp-module:这是老牌经典方案。Nginx本身是HTTP服务器,加个RTMP模块就能转直播。问题是官方主仓库已经把这个模块移出了维护列表,现在要用基本都得自己编译。我试过编译,依赖一堆,升级麻烦,而且它默认只处理RTMP,HLS功能要自己配,HTTP-FLV支持也比较弱。适合本来就深度使用Nginx且不介意折腾的人。
  • MediaMTX:它更偏向"接入各类摄像头RTSP流"和"协议转换"。一个二进制文件就能跑,配置文件是YAML格式,非常简洁。但它的定位是轻量网关,不是完整的直播分发系统:没有内置的Web管理面,鉴权、录制、集群等能力都不如专业直播服务器。如果只是把几路RTSP摄像头转成HLS给网页看,它很舒服;要做一场有观众、有录制、有权限控制的直播,会感觉缺了很多东西。
  • SRS(Simple Realtime Server):这是国产开源项目,从最早的Flash直播一路做到现在的WebRTC直播,专门解决"直播服务器"这一件事。它用C++写成,单进程就能完成RTMP接入、HLS切片、HTTP-FLV分发、WebRTC进出,默认配置几乎开箱即用。内置HTTP API和Web控制台,推流鉴权、录像、转码、集群这些都有,文档和社区在直播服务器里算非常活跃的。我第一次用SRS时,下载压缩包、解压、启动,三分钟就把流推起来了,这是其他方案没有给过我的体验。

方案对比如下:

方案上手难度协议支持扩展能力维护活跃度适合场景
Nginx-RTMP中高(需编译)RTMP、HLS基础较弱低已有Nginx体系
MediaMTX低RTSP、RTMP、HLS、WebRTC中等高摄像头接入、协议转换
SRS低RTMP、HLS、HTTP-FLV、WebRTC强(鉴权/录制/集群)高正式直播分发

2.2 不同场景怎么选

如果你要做的是一件"正式能对外用"的直播服务,SRS基本是首选。它把"接收推流→切片→分发到播放器"这条链路的每一环都做了,而且每一步都有日志和API可以排查。哪怕是新手,跟着默认配置用起来也不会有太多认知负担。

反过来,如果你已经有Nginx在负责网站,只是偶尔转一下流,那Nginx-RTMP也还凑合。如果你只是想把设备上的RTSP流转给网页看,MediaMTX更轻。但在这篇文章的语境下,我默认你想要的是一台能长时间运行、有人推流有人观看、出了事还能查日志的直播服务器——这个定位SRS最合适。

顺便说一句,很多人会纠结"要不要先把FFmpeg学了再搭服务器"。我的建议是没必要。FFmpeg在直播里的作用是转码和推流,但服务器本身不依赖它;你可以先用OBS推流,FFmpeg等有需求再学。

3. 三分钟跑起来:SRS的Docker与二进制部署

3.1 最省事的启动方式:Docker

如果你的机器上有Docker,SRS启动真的就是一条命令的事。我用Docker跑SRS的基本命令如下:

# 创建配置目录并持久化(可选,但建议) mkdir -p /data/srs docker run -d --name srs \ -p 1935:1935 \ -p 1985:1985 \ -p 8080:8080 \ -v /data/srs:/usr/local/srs/objs/nginx/html \ ossrs/srs:6

这里有三个端口要记住:

  • 1935:RTMP协议入口,推流和RTMP拉流都用它。
  • 1985:SRS的HTTP API端口,用来查状态、拉流信息。
  • 8080:HTTP服务端口,HLS切片、HTTP-FLV播放地址都由它对外提供。

-v参数把容器里的HTML目录(也就是HLS切片的输出目录)映射到宿主机,这样即使容器删除,录像和切片数据也还在。我习惯先建好宿主机目录再挂载,因为容器会在目录不存在时自动建目录,权限又不一定是你想要的。

如果ossrs/srs:6镜像拉取较慢,可以用Docker配置镜像加速器,或者直接用后面说的二进制方式。

3.2 不依赖Docker的二进制启动

有些服务器上没有Docker,或者你对容器转来转去的方式不放心,那就用二进制包。去SRS的GitHub Releases页面下载Linux版压缩包,然后解压、启动:

wget https://github.com/ossrs/srs/releases/download/v6.0.186/srs-6.0.186.tar.gz tar xf srs-6.0.186.tar.gz cd srs-6.0.186 ./objs/srs -c conf/srs.conf

看到日志里出现start server successfully之类的字样就说明起来了。二进制的目录结构很清晰:conf放配置、objs放可执行文件和日志。我个人的习惯是把它放到/usr/local/srs下,方便统一管理。

二进制方式的好处是依赖少、性能好、排障直观,日志就在objs/srs.log里,问题定位非常直接。

3.3 srs.conf里那几个必须看懂的关键项

SRS默认配置可以直接跑,但既然要长期使用,我还是建议把关键项过一遍。简化后的核心配置大概是这样的:

listen 1935; # RTMP入口 max_connections 1000; # 最大连接数 daemon on; # 后台运行 srs_log_tank console; # 日志输出到控制台 http_api { enabled on; listen 1985; # HTTP API端口 } http_server { enabled on; listen 8080; # HTTP服务端口(HLS、FLV、播放页) dir ./objs/nginx/html; # 静态文件与切片目录 } vhost __defaultVhost__ { hls { enabled on; # 开启HLS切片 hls_path ./objs/nginx/html; hls_fragment 10; # 每个切片时长(秒) hls_window 60; # 保留窗口时长(秒) } }

vhost的概念可以理解为一个虚拟的直播房间组。默认的__defaultVhost__会接收所有到达这个IP的RTMP流,对单机场景完全够用。hls_fragment控制切片时长,直接影响HLS延迟——后面讲延迟坑时会再提到。

对于docker映射出来的端口,因为容器内部配置用的还是这几个默认端口,所以你不需要改配置,知道它们干什么是为了排查问题。

3.4 启动后先确认三件事

服务器启动后,我建议立刻做三件事确认它真的活着。

  • 查API:访问http://你的服务器IP:1985/api/v1/summaries,如果返回一段JSON且里面有"status": "running"或类似的状态字段,说明API正常。这一步用浏览器或curl都行。
  • 看默认页:访问http://你的服务器IP:8080,能出现SRS的提示页或目录列表,说明HTTP服务正常。
  • 本地连RTMP端口:在同一台机器执行telnet 127.0.0.1 1935,能连通就说明RTMP入口在监听。

这三件事全部通过之后,再去做推流配置,否则后面排查起来会把网络问题和服务问题混在一起。我发现很多人第一次搭完去问"为什么推流失败",结果连服务都没起来,白白浪费半小时。

4. 推流和播放实战:从OBS到多终端同时观看

4.1 OBS推流:复制粘贴三个字段

服务端就绪后,推流端用OBS(Open Broadcaster Software)来做是最顺手的。打开OBS的设置,找到"直播"(或"推流"),选择自定义服务,然后填写三个信息:

  • 服务器:rtmp://你的服务器IP/live
  • 串流密钥:myroom(这个名字可以随便取,相当于房间名,播放地址里会用到)
  • 没有单独的"应用名"字段,live已经含在服务器URL里了

填好后点击开始推流。此时OBS的推流状态会从"正在连接"变成"直播中",同时日志里会出现"发送时间"和"丢帧"的数据。如果丢帧持续增加,优先检查网络带宽和服务器CPU,而不是急着重推。

值得说明的是,为什么服务器地址是rtmp://IP/live而不是rtmp://IP?因为SRS默认把VT应用配置在live这个名字下。流密钥myroom就是播放地址里的房间标识,它决定了播放端用什么URL来找这条流。同一个密钥下可以同时有多个播放器观看,服务器会自动转发。

4.2 播放端:三种方式对比实测

推流成功后,我在内网分别用三种方式实测了播放,效果如下:

  • FFplay拉RTMP(最直接):
    ffplay rtmp://你的服务器IP/live/myroom
    这是延迟最低的播放方式之一,画面基本和推流端同步,适合快速验证流是否正常。
  • VLC播放:打开VLC,选择"媒体-打开网络串流",输入rtmp://你的服务器IP/live/myroom。移动端VLC也可以,但要在网络串流里手动输地址。
  • 浏览器HLS播放:在Chrome/Safari/Edge任一浏览器地址栏输入:
    http://你的服务器IP:8080/live/myroom.m3u8
    HLS切片是SRS默认开启的,所以这个URL能直接在浏览器里以video标签播放(Safari原生支持,Chrome也需要用hls.js或者直接访问页面的话SRS有对应的示例播放器页面)。

如果SRS自带的示例播放页可用,也可以直接访问http://你的服务器IP:8080/players/srs_player.html,在里面选择协议、填写流地址,点播放就行。这在排查"到底是我的播放器问题还是流问题"时非常省事。

4.3 同一个房间,多人观看的资源账

很多人关心"一台服务器能支持多少人同时看"。这个问题其实取决于你的码率和带宽,而不是服务器软件本身。直播服务器不转码时,它做的只是把一份进来的流复制成多份出去,CPU开销很小,真正的瓶颈在网络带宽。

举个实际例子:推流端设了4Mbps码率(1080p),有20个人同时观看,那么服务器至少需要4Mbps × 20 = 80Mbps的出站带宽。如果只有100Mbps的带宽,强行支撑30人就会出现播放卡顿。

所以做直播活动前,先算清楚这笔账:

观看人数1080p(4Mbps)720p(2Mbps)480p(1Mbps)
10人40Mbps20Mbps10Mbps
50人200Mbps100Mbps50Mbps
100人400Mbps200Mbps100Mbps

如果带宽有限,可以在服务器侧用FFmpeg转出多路不同清晰度的流,或者提前让推流端压到合适的分辨率。这个账没算清,活动当天网络崩了再想补救就来不及了。

5. 真实环境里最容易踩的五个坑

5.1 坑一:端口和服务看着都正常,但别人连不上

我第一次部署完,服务端日志一切正常,本机也能播放,但局域网里的另一台电脑就是连不上。一查,问题出在防火墙。

SRS需要对外开放1935(RTMP)、1985(API)、8080(HTTP),无论你用的是云服务器还是内网机器,都要先把这三个端口放行。云服务器要去安全组里加规则;Linux本机可以用firewall-cmd或ufw放行。排查的时候,先在播放端机器上执行telnet 服务器IP 1935:

telnet 192.168.1.10 1935

如果卡住不动或者报连接失败,绝大概率是端口没放行。我建议先把三个端口一次性放行再测试:

# 以firewalld为例 firewall-cmd --permanent --add-port=1935/tcp firewall-cmd --permanent --add-port=1985/tcp firewall-cmd --permanent --add-port=8080/tcp firewall-cmd --reload

这个坑太基础了,但栽的人特别多。因为服务端日志和本机播放成功会给你一种"服务正常"的错觉,而问题根本不在服务,在网络入口。

5.2 坑二:流地址能出,播放端却黑屏转圈

有一次我在浏览器里访问HLS地址,能看到返回的.m3u8文件,但播放器一直转圈。检查了半天,发现HLS切片目录根本没有生成最新的.ts文件。

这类问题的排查路径是固定的。先用curl直接访问一下切片地址:

curl -v http://你的服务器IP:8080/live/myroom.m3u8

如果返回的是空文件或者404,那问题在服务器侧;如果切片能正常列出,再去检查播放器。

我碰到过的实际情况有两种:一种是因为服务器时间和服务启动顺序的问题导致切片没有落盘,重启SRS后恢复正常;另一种是推流端用的是可变码率(VBR),画面静止时码率过低,HLS切片迟迟不产生新的分片。把OBS里码率设定为固定码率(CBR)后问题就消失了。所以先看切片有没有产生,再谈播放器配置,别一上来就怀疑播放器。

5.3 坑三:画面模糊,我却先怀疑服务器

直播画面模糊,大多数人第一反应是"服务器是不是压缩太狠了"。这个思路完全错了。SRS默认是不转码的,它不改变画质,你的画面模糊大概率是推流端参数没设好。

OBS里影响画质的两个核心参数是分辨率和码率。同样分辨率下,码率太低就会出现马赛克、边缘发虚。我常用的参数如下:

分辨率推荐码率适用场景
1080p5000-8000 Kbps游戏直播、画面运动多
720p2500-4500 Kbps课堂、会议画面相对静止
480p1000-2000 Kbps带宽受限或观看端以手机为主

如果你是用FFmpeg推流,命令里-b:v就是码率,-preset选medium或slow能让同样码率下画质更好一点点。检查顺序应当是:先看推流端的码率是不是跑得起来,再看服务器CPU和带宽是否够用,最后才轮到服务器配置。

5.4 坑四:延迟大得没法用,到底怎么调

第一次用HLS播放时,我对着画面愣了几秒才反应过来流是延迟的,而且比我想象中严重得多。这是因为HLS切片的机制:服务器把流切成一段段几秒长的文件,播放器至少要等下完一个切片才能开始播。默认切片10秒,再加上缓冲,延迟十几秒到半分钟都是正常的。

如果你对延迟有要求,办法有两条:

  • 用HTTP-FLV代替HLS:在浏览器里用flv.js配合HTTP-FLV地址(http://IP:8080/live/myroom.flv),延迟可以压到2-5秒。这是当前网页端低延迟最实用的方案。
  • 调低HLS切片时长:把srs.conf里的hls_fragment从10改成2-3,延迟会下降,但切片数量变多、播放时对服务器和客户端的压力也变大,还可能因为切片太碎导致首屏加载更卡。

RTMP播放的延迟本来就很低,如果你想做互动直播,优先考虑HTTP-FLV而不是继续折腾HLS。每次调整完延迟,记得重新推流测试,因为切片参数对已存在的流不一定立即生效。

5.5 坑五:HTTPS页面里FLV播放器一片空白

这个坑特别隐蔽。我后来做了个带HTTPS的页面,想在上面内嵌flv.js播放器,结果播放器区域一直是黑的,控制台报错信息提示"Mixed Content"。

浏览器安全策略规定:HTTPS页面里不能加载HTTP资源。如果你的播放页面是https://,而HTTP-FLV流地址是http://IP:8080/live/myroom.flv,浏览器会直接拦截。解决办法要么是把流地址也改到HTTPS(给SRS配置证书并开启HTTPS监听),要么放弃在HTTPS页面上直接嵌HTTP流,改走HLS(某些浏览器的策略对HLS相对宽容但不绝对)。

我在实际项目中最终为SRS配了HTTPS来同时支持WebRTC和HTTP-FLV播放,如果只是内网临时用,直接用HTTP页面也能绕开这个限制。这个坑的价值在于提醒你:直播服务器不只是后端程序,它和浏览器的安全策略是强耦合的,选播放方式前先确认页面协议和流地址协议一致。

6. 还没完:鉴权、录制、低延迟扩展

6.1 给直播服务器加一把锁

默认配置下,任何人只要知道你的服务器IP和端口,都可以往live应用里推流或拉流。这在公网环境下等于门户大开。最实用的做法是用SRS的回调机制:配置一个HTTP地址,SRS在收到推流请求时先回调它,返回“允许”才继续,否则拒推。

我用Node.js写过一个极简的验证服务,代码大概是:

// 伪代码示例:on_publish回调验证token const http = require('http'); http.createServer((req, res) => { const query = new URL(req.url, 'http://localhost').searchParams; const token = query.get('token'); if (token === 'myroom_token') { res.writeHead(200); res.end('0'); // 0表示允许推流 } else { res.writeHead(200); res.end('1'); // 非0表示拒绝 } }).listen(8081);

SRS的配置里加上:

vhost __defaultVhost__ { hooks { enabled on; on_publish http://127.0.0.1:8081/api/v1/hooks; } }

然后推流地址就可以是rtmp://IP/live/myroom?token=myroom_token。OBS的"串流密钥"里填上myroom?token=myroom_token即可。不光是推流,看流也可以加类似限制,SRS的鉴权体系可以做到很细。至少把on_publish加上,能挡住一大半误入的推流。

6.2 自动录制回放

直播结束想留档,SRS可以直接在服务端录制。配置起来很轻:

vhost __defaultVhost__ { dvr { enabled on; dvr_path ./objs/nginx/html/[app]/[stream].[timestamp].flv; } }

这样每一条推流都会在服务端录制成FLV文件,路径里的[timestamp]让文件名不重复。录制产生的文件可以直接放到OBS里播放,也可以让FFmpeg转成MP4。我办过几次活动直播,录完直接用这个FLV文件留档,省去了单独开录屏软件的麻烦。

注意录制文件是按流生成的,如果推流中途断过线,会生成多个文件,不要问我是怎么知道的。

6.3 对延迟敏感的WebRTC玩法

如果你要做的是远程操作画面、线上问答这类对实时性要求极高的场景,SRS也能支持WebRTC播放。原理是让SRS开启WebRTC网关,播放端通过浏览器直接建立近实时的音视频通道,延迟能压到几百毫秒。

它需要你额外配置HTTPS证书和WebRTC相关端口。流程大概是:给SRS配置证书和rtc_server端口,然后在播放端使用SRS的WebRTC播放器SDK,把流地址改为WebRTC格式。配置门槛比RTMP和HLS高不少,但带来的实时性提升也很明显。我个人的使用建议是:一般直播用HTTP-FLV足够,别一上来就上WebRTC,先满足需求再谈性能。

我实际跑过几次完整流程后最大的体会是:搭SRS本身真不是难点,真正的功夫都在那些“小事”上——端口通不通、码率配没配、浏览器安不安全策略、录制文件在哪。与其背各种参数,不如先跑通RTMP加HLS这条默认链路,再根据自己的场景慢慢加鉴权、录制和低延迟方案。最后分享一个小技巧:把服务器IP固定下来,或者在内网DNS里给它一个稳定名字,推流地址永远用名而不用IP,这样换设备、换网络时配置不用来回改。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/23 10:35:28

CUDA GPU架构与芯片型号对照表:计算能力、编译目标与选型指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/22 19:40:18

10 分钟免费激活 Windows 和 Office:MAS 激活脚本完整上手

10 分钟免费激活 Windows 和 Office:MAS 激活脚本完整上手 【免费下载链接】Microsoft-Activation-Scripts Open-source Windows and Office activator featuring HWID, Ohook, TSforge, and Online KMS activation methods, along with advanced troubleshooting. …

作者头像 李华
网站建设 2026/10/25 14:27:59

PL/SQL Developer执行.sql文件实战:从编码到事务避坑指南

在Oracle开发里,我见过太多人在“执行.sql文件”这件小事上反复折腾。要么双击打开发现根本跑不了,要么在命令行里被各种诡异报错劝退,要么同一份脚本别人跑得好好的,到你机器上就全是乱码。今天这篇就把PL/SQL Developer下执行.s…

作者头像 李华
网站建设 2026/10/26 14:46:31

AI推理时突然“想起“最初的问题,却总被系统忘记

你有没有过这样的经历:写一篇长文章写到中间,突然要回头翻看开头列的提纲,确认自己没跑题?大语言模型在做复杂推理的时候,也会做同样的事情。而这篇论文要讲的,就是当AI也需要"翻回去看看开头"时…

作者头像 李华
网站建设 2026/10/22 10:05:13

Netty HTTP 请求如何进入 MVC:从请求接收到响应写回

读 Netty 与 MVC 的集成代码时,可以先抓住三个位置:请求从哪里进入,谁来调用处理器,处理结果在哪里写回连接。 本文使用 TODAY Infrastructure 的同步 HTTP 请求作为例子。我是项目维护者,也向 Spring Framework、MyB…

作者头像 李华