ARTICLE DETAIL

建站实战干货

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

Windows下用Nginx搭建RTMP流媒体服务完整指南

2026/9/29 3:18:29 拓冰建站 浏览量
Windows下用Nginx搭建RTMP流媒体服务完整指南 1. 为什么我最终还是选了Nginx做Windows下的RTMP服务先说说我为什么会写这个方案。之前团队里临时要搭一个内部直播演示环境视频源来自一台Windows工作站的采集卡需要把画面实时推给几个不同楼层的同事预览。当时摆在桌面上的选项其实不少SRS、Red5、Janus、Nginx-RTMP模块甚至直接用OBS自带的“服务”功能连第三方平台。我的实际诉求很简单内网私有化部署不要依赖外部平台延迟尽量低能在局域网里做到秒开级别配置和维护复杂度可控万一出事团队里其他Windows熟手也能接手排查。SRS性能很强但官方文档和生态在Windows下的体验没有Linux那么顺Red5偏Java体系内存占用和上手门槛对“只想快点把流跑起来”的场景来说有点重Janus更多面向WebRTC和RTMP推流这个需求有一点错位。最终敲定Nginx理由也很直接Nginx在Windows下的二进制分发很成熟配合Nginx-RTMP模块的动静不大配置语法和Web服务器配置同一套团队里懂Nginx的人一看就会。再加上Nginx本身就是事件驱动模型单进程在Windows下扛住几十路低码率内网拉流完全没有压力——我们这次场景是内部演示不是什么万人直播Nginx绰绰有余。需要说明的是RTMP协议本身是一套基于TCP的实时消息传输协议Adobe在Flash时代定义的标准。它把视频流拆成消息块在TCP连接上传输默认端口1935。放在今天的流媒体架构里看RTMP确实不算新但它仍然是目前推流端兼容性最好的协议之一——OBS、FFmpeg、各种硬件编码器几乎都原生支持RTMP推流。用它做内网流的“入口协议”再用Nginx做分发是目前低成本方案里的一个成熟组合。这篇文章的定位是给那些想在Windows机器上快速搭一套RTMP视频流服务的人做参考。你会在这个过程里亲手完成从下载、配置、推流、拉流到排错的完整闭环整个过程不依赖任何第三方直播平台全部在内网完成。2. 搭建前必须想清楚的三个问题在动手之前我建议你先花五分钟把下面几个问题想明白这会帮你省掉不少后面反复改配置的麻烦。2.1 你要的是“单路测试”还是“多路并发”如果只是自己验证一下推拉流链路通不通那Nginx的RTMP模块默认配置就够用如果你要同时接收多路不同的直播源比如一路来自采集卡、一路来自屏幕录制、一路来自网络拉流就必须在配置里规划好多个application块并且合理分配带宽和缓存参数。我们这次演示搭建时默认配置下同时跑两路1080p推流都正常但第三路开始出现画面卡顿。原因不复杂Windows版的Nginx是单进程模型所有worker跑在一个进程里CPU和网络中断处理都受单进程限制。所以内网低并发可以高并发场景建议直接把方案换成Linux别在Windows上硬扛。2.2 防火墙和端口策略是否已经放行这是最容易被忽略的一环。RTMP默认端口是1935如果你不做任何改动需要同时在Windows防火墙里放行TCP 1935入站规则如果后续要用HTTP-FLV或者HLS拉流还要额外放行对应HTTP端口一般是8080或80。我自己遇到过一个很邪门的问题本机拉流一切正常局域网内其他机器就是连不上排查了一整圈最后发现是Windows Defender防火墙的“公用网络”配置档里没有放行1935端口。这个细节写在这里希望能帮一部分读者少走这条路。2.3 推流端和拉流端走的到底是同一套协议还是混合协议RTMP推上来之后拉流端其实不一定非要看RTMP。常见做法是推流走RTMP然后由Nginx-RTMP模块实时转封装成HTTP-FLV或者HLS拉流端再按照自己的播放场景选择协议。如果你只是在VLC或者PotPlayer里手动打开网络串流那直接拉rtmp://ip:1935/live/stream就够了如果你要做Web页面播放那HTTP-FLV或者HLS更合适因为浏览器原生不支持RTMP。这个选择会影响你后面要不要额外开HTTP服务器、要不要配置转封装参数、要不要设置切片时长所以最好在一开始就想清楚。3. 下载、部署与最小化配置3.1 选对Nginx版本很关键Nginx在Windows下有两种常见形态一是Nginx官方发布的Windows版本它本身不带RTMP模块二是集成好第三方模块的社区构建版比如著名的nginx-rtmp-win32这类项目。这里必须强调如果你图省事直接下载了官方Nginx Windows包配置文件里写rtmp {}块是会被直接报错拒绝加载的因为官方二进制压根没有编译进RTMP模块。我当时的做法是直接用带RTMP模块的Windows构建版省去了自己用MinGW或者MSVC交叉编译模块的麻烦。Windows下自己编译Nginx-RTMP模块是真的折腾依赖顺序、编译器版本、链接库路径任何一个对不上都会在编译阶段浪费大半天。对于绝大多数“只想在内网把流跑起来”的场景直接用社区构建版是投入产出比最高的选择。下载完成后解压到一个没有空格、没有中文的路径下比如C:\nginx-rtmp这一点很关键Windows下很多后台服务和命令行工具对带空格的路径处理都容易出幺蛾子Nginx虽然不是绝对跑不起来但没必要给自己埋这个雷。解压后的目录结构大概是这样C:\nginx-rtmp ├── conf\ # 配置文件目录nginx.conf就在这里 ├── contrib\ ├── docs\ ├── logs\ # 运行日志 ├── temp\ ├── html\ # 默认Web页面 └── nginx.exe # 主程序建议先运行一下nginx.exe -V看编译参数里是否有--with-http_ssl_module和--add-module../nginx-rtmp-module之类的字样。如果都能看到说明这个包基本够用了。3.2 最小可用的nginx.conf长什么样安装完第一件事不是直接开推而是先把配置改成“最小但不缺功能”的状态。我放一份经过实测的配置做参考worker_processes 1; error_log logs/error.log info; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 8080; server_name localhost; location /stat { rtmp_stat all; rtmp_stat_stylesheet stat.xsl; } location /stat.xsl { root html; } location /live { flv_live on; chunked_transfer_encoding on; add_header Access-Control-Allow-Origin *; } } } rtmp { server { listen 1935; chunk_size 4096; application live { live on; record off; allow play all; } } }这里我解释一下每个关键配置的意图listen 8080HTTP服务端口。我特意避开了80因为Windows上80端口经常被IIS或者其他Web服务占用先跑起来比纠结端口语义重要。后面如果要用HTTP-FLV拉流访问的就是http://IP:8080/live/stream。location /live { flv_live on; }这是开启HTTP-FLV实时流分发。有了这段你的拉流端除了RTMP之外还可以用HTTP方式拉流这对网页播放器来说极其友好。rtmp { server { listen 1935; } }RTMP服务监听1935端口。application live定义了一个名为live的挂载点。推流地址就是rtmp://IP:1935/live/后面再跟流名称。chunk_size 4096RTMP块大小默认是4096一般不用动。块太小会频繁拆包增加CPU开销太大在弱网下会增加单包丢失的影响面。record off默认不录制。很多初学者不知道Nginx-RTMP模块是支持直接把直播流录成flv文件的。如果忘了关跑一段时间硬盘会被悄悄塞满别问我怎么知道的。allow play all允许所有客户端拉流。如果你所在网络环境里有不该看这个流的人这里就要改成allow play 127.0.0.1;加deny play all;来控制网段。配置文件改完在命令行里执行cd C:\nginx-rtmp nginx.exe -t看到nginx: configuration file ... test is successful再启动。平时要启动就双击nginx.exe或者在命令行执行start nginx要停止或重载配置nginx.exe -s stop # 快速停止 nginx.exe -s reload # 平滑重载配置3.3 先启动看看服务到底起来没有启动之后在浏览器打开http://127.0.0.1:8080/stat如果能看到一个XML格式的状态页或者带样式的统计页说明Nginx的HTTP服务正常。同时用netstat -ano | findstr :1935确认1935端口处于LISTENING状态。这两步都过了再进行推流测试。有朋友可能会问/stat这个页面是干什么用的它其实是Nginx-RTMP模块自带的实时状态接口可以查看当前有多少路流在推、多少客户端在拉、总带宽等。后面做压力测试或者排查“到底是谁在连着我的流”时这个页面就是最直观的仪表盘。4. 推流与拉流跑通整个链路的关键细节4.1 用OBS推流到NginxOBS是目前最主流的免费推流工具设置路径设置 → 直播 → 服务选“自定义”服务器填rtmp://127.0.0.1:1935/live串流密钥填一个自定义流名比如stream1。密钥这里其实不是真的“密钥”它只是作为流名称的一部分拼到RTMP地址里。最终OBS推流的完整地址是rtmp://127.0.0.1:1935/live/stream1。一个常见的误区是在OBS里把服务器填成rtmp://127.0.0.1:1935/live/stream1然后串流密钥又填一遍stream1结果地址变成rtmp://127.0.0.1:1935/live/stream1/stream1。虽然Nginx-RTMP模块对这种多出来的路径段处理得比较宽容但还是建议按规范来服务器和密钥各司其职避免后续排查问题时分不清实际推流地址。点击“开始直播”后如果一切正常OBS右下角的状态会变成绿色同时/stat页面里能看到一条实时流记录。如果状态红了一下又恢复大概率是网络不通或者地址拼错可以先去logs/error.log里看Nginx侧有没有connection closed之类的记录。4.2 用FFmpeg推流到Nginx如果你不想开OBS这种重量级应用或者希望推流过程可以脚本化、自动化FFmpeg是另一个更好的选择。比如把本机一个视频文件循环推流到Nginxffmpeg -re -stream_loop -1 -i C:\videos\test.mp4 -c:v libx264 -preset veryfast -tune zerolatency -c:a aac -f flv rtmp://127.0.0.1:1935/live/stream1解释一下几个参数的含义-re表示按视频原始帧率读取文件模拟实时推流-stream_loop -1表示无限循环所以这个命令跑起来之后会一直推流-tune zerolatency对低延迟场景很关键它会让x264编码器把编码缓冲降到最低代价是压缩率略微下降。如果你的直播画面是摄像头或者采集卡也可以用-f dshow -i video摄像头名替换输入源Windows下FFmpeg用dshow驱动来采集设备。如果对延迟敏感-preset veryfast -tune zerolatency这个组合基本是标配实测从摄像头采集到播放器显示端到端延迟可以控制在1到2秒以内。我在一次演示中用过这个方案拉流端看到画面和实际讲话的违和感很小观众基本无感知。4.3 拉流端怎么选播放器拉流端选择挺多的我实测过的播放器里VLC和PotPlayer对RTMP的支持最省心。直接在“打开网络串流”里输入rtmp://IP:1935/live/stream1就能播放。如果你要做Web播放可以用支持HTTP-FLV的播放器方案比如flv.js配合B站开源的mpegts.js拉流地址就是http://IP:8080/live/stream1。但要注意RTMP协议在浏览器里无法直接播放所以Web场景必须走HTTP-FLV或HLS。拉流延迟方面RTMP原生拉流的延迟通常在1-3秒之间属于“可接受范围内比较低”的水平。如果你发现延迟异常高先检查推流端是不是开了较大的缓冲再检查播放器是不是开了额外的缓存策略。VLC里可以按CtrlR也可以把网络缓存从默认的1000ms调低到300ms左右能明显改善延迟体感。4.4 同一个流多路拉Nginx扛得住吗实测下来Nginx-RTMP模块对“同一条流多个客户端同时拉”这种场景处理得很聪明。它不会让每个拉流客户端都去推流端单独取一份数据而是在内部做引用复用——推流端只推一份数据到NginxNginx向每个拉流客户端分发同一份数据的引用。换句话说拉流的人越多Nginx的带宽开销越高但推流端的上行压力几乎不增长。参考数据是内网千兆环境下一条2Mbps的推流同时分发给30个拉流客户端Nginx所在机器的CPU占用率依然很低。这背后是Nginx事件驱动架构在发挥作用单线程也能高效处理大量并发连接。5. 从“跑通”到“能用”录制、状态监控与安全性补强5.1 一键把直播流录下来如果你想把这场直播完整保存成文件用Nginx的录制功能其实是成本最低的方案不用额外起录制软件。在application块里加几行application live { live on; record all; record_path C:/nginx-rtmp/recordings; record_unique on; record_suffix _%Y-%m-%d_%H-%M-%S.flv; }record all代表所有推上来且被播放的流都录制record_unique on会在流名后面自动加时间戳防止文件互相覆盖。录制文件的格式是FLV里面是原始编码的视频流做后期剪辑之前可以用FFmpeg转封装成MP4ffmpeg -i input.flv -c copy output.mp4因为只是改封装不过编码速度非常快文件也不会二次损伤画质。不过要留意录制功能对磁盘空间有要求跑一场2Mbps码率的直播一小时大约产生900MB文件。如果是全天的活动记得给录制目录预留足够的空间。5.2 状态监控页面能做很多事前面提到/stat页面这里展开讲一下。Nginx-RTMP模块自带的统计页不仅能看“当前有没有流”还能看每路流的码率、已持续时长、连接数、读取/发送字节数。截图里能看到类似这样的XML结构rtmp server application namelive live stream namestream1 time1234 bw_in256000 bytes_in... / /live /application /server /rtmp我实际工作中还习惯用脚本定时curl这个页面把bw_in和bytes_in抓出来推到监控面板实现“直播中断自动告警”。如果你所在环境允许跑一点简单脚本用PowerShell的Invoke-RestMethod获取这个XML再解析几行代码就够了。这种“自己给自己做监播”的能力在重要直播场景中价值很大。5.3 别忘了给RTMP服务加一层访问控制默认配置下Nginx开放的RTMP服务是任何人都能推流和拉流的。这对完全内网、可信网络环境没问题但如果你所在的公司网络比较大或者你的Windows机器有公网映射就很危险——别人可以直接往你的服务器推流占满你的带宽甚至推一些不该出现的内容。建议至少做两步第一步按IP限制推流权限把allow publish设成只允许推流机的IPapplication live { live on; allow publish 192.168.1.100; # 只允许这台机器推流 deny publish all; # 其他一律拒绝 allow play all; # 拉流仍放开按需调整 }第二步如果你需要更强的安全隔离可以给Nginx配置基于RTMP的鉴权回调让Nginx在收到推流请求时向你的后端服务发一个HTTP请求由后端判断这个流名和密钥是否合法。这个方案稍微复杂不在本文展开但如果你走的是公网环境非常推荐进一步了解。另外还有一件事必须提醒不要在Windows上把Nginx以管理员权限运行成常驻服务时把error.log级别设成debug然后就不管了。Debug级别的日志会极速膨胀半天就能吃掉几个GB空间。我一般在生产配置里用error_log logs/error.log notice排查具体问题时才临时改成info。6. 实测过程中踩过的坑和排查思路6.1 Windows防火墙挡掉了所有外部拉流这个问题我在前面提了一嘴这里说详细的排查链路。当时现象是本机用rtmp://127.0.0.1:1935/live/stream1拉流正常但同一局域网内另一台机器用rtmp://192.168.1.10:1935/live/stream1拉流失败。排查步骤在推流机上netstat -ano | findstr :1935确认Nginx在监听0.0.0.0:1935而不是只有127.0.0.1。在拉流机上telnet 192.168.1.10 1935发现连接被拒绝。回到推流机用netsh advfirewall firewall show rule nameall查看防火墙规则发现没有任何针对1935端口的入站规则。执行netsh advfirewall firewall add rule nameRTMP 1935 dirin actionallow protocolTCP localport1935再拉流秒通。这个问题的根因本质上很简单Windows入站连接默认会被防火墙拦下除非显式放行。但实际踩坑时很容易一上来就去翻Nginx配置浪费不少时间。先确认端口通不通再查Nginx配置这才是正确顺序。6.2 Nginx启动失败错误日志提示“端口已被占用”这种情况在Windows上特别常见。某次我在一台已有IIS的机器上部署Nginx一直起不来错误日志写的是“bind() to 0.0.0.0:80 failed (10048: Address already in use)”。后来我把默认的listen 80改成了listen 8080问题瞬间消失。排查端口占用的命令netstat -ano | findstr :80 tasklist | findstr PID看到PID之后去任务管理器里找到对应的进程确认是不是IIS、Skype或者其他Web服务占用了80端口。如果确认是IIS可以停掉或者改端口如果想保住IIS不动就把Nginx的HTTP端口改掉。总之别和现有服务抢端口这是Windows环境下部署Nginx的第一守则。6.3 推流端正常但拉流端画面不断转圈这个现象在弱网或者跨网段拉流时很容易出现。初期我怀疑是Nginx配置问题反复调chunk_size和max_connections都没用。后来在拉流端用Wireshark抓包发现RTMP的TCP包有大量重传网络层就有问题根本轮不到Nginx背锅。遇到这类问题优先检查拉流端到Nginx之间的网络连通性和丢包率ping -n 30 192.168.1.10如果丢包超过1%先解决网络问题再调Nginx。如果网络完全正常还要检查推流端码率是不是设置得过高。比如在千兆局域网里推个10Mbps的流没问题但如果是跨Wi-Fi拉流10Mbps很容易把无线链路打垮画面自然就会卡顿。另外还有一个几乎所有人都遇到过的迷惑行为Windows的电源管理默认会在“平衡”模式下让网卡进入节能状态导致长视频流中途出现周期性卡顿。解决办法是去设备管理器里找到网卡在“电源管理”选项卡里取消勾选“允许计算机关闭此设备以节约电源”。这个坑藏得很深但影响却很实在。6.4 服务器运行一段时间后Nginx进程消失这个问题比较少见但确实存在。Windows下Nginx不是以服务方式运行的你双击启动的只是一个普通进程。如果机器重启了或者有人手动结束了进程Nginx不会自动重新拉起。如果你需要它长期在后台跑建议用sc.exe配合工具把Nginx注册成Windows服务或者用计划任务开机启动。注册成服务的操作并不复杂但要注意Nginx在Windows下对工作目录有依赖直接注册nginx.exe路径是没问题但后续日志和配置路径最好用绝对路径。我自己更喜欢用计划任务的方式开机触发一次执行C:\nginx-rtmp\nginx.exe工作目录设为C:\nginx-rtmp然后在“如果任务失败”选项卡里设置重启。这个方法轻量直观团队里其他人也容易理解。7. 进阶把现有的RTMP服务扩展成多协议分发7.1 为网页播放加上HTTP-FLV支持如果你的目标观众里有很大一部分是浏览器用户那一定要把HTTP-FLV开起来这对视频播放延迟的控制能力比HLS强。Nginx配置里的location /live { flv_live on; }就是干这个的。开启后浏览器端用mpegts.js或flv.js拉http://IP:8080/live/stream1延迟可以在1秒以内比HLS动辄5-10秒的延迟体验好太多。要注意的是HTTP-FLV本质上仍然依赖RTMP推流端不停地上传数据Nginx充当的角色是把RTMP流转封装成HTTP流也就是“零延迟转发”。所以推流端异常断开播放端会很快感知到表现为画面停止而不会像HLS那样因为切片缓冲延迟。7.2 用HLS做多码率适配和回看如果你的拉流端包含移动网络或者跨公网用户HLS其实是更稳的选择。HLS把直播流切成一个个小的TS切片文件播放器按顺序拉取即可。配置方法是在rtmp块里加application live { live on; hls on; hls_path C:/nginx-rtmp/hls; hls_fragment 2s; hls_playlist_length 10s; }hls_fragment是每个切片时长我一般设2秒hls_playlist_length是播放列表保留最近多少秒的切片。切片越短延迟越低但会产生更多的文件IO。实测在Windows NTFS文件系统上2秒切片配合普通机械硬盘跑一两路流没问题如果路数多了还是建议用SSD。使用HLS后播放地址变为http://IP:8080/hls/stream1.m3u8。VLC直接可以打开这个m3u8地址浏览器端也可以用hls.js播放。7.3 在Nginx里实现简单的防盗链如果你的流不想被外部随便拉走但又不想上重型的鉴权方案可以结合valid_referers做一道轻量校验location /live { flv_live on; valid_referers none blocked server_names *.example.local; if ($invalid_referer) { return 403; } }这种方式能挡掉一部分“随手粘贴URL”的拉流行为但防不了专业工具。真的要防还是得靠前面说的回调鉴权或者给播放地址加动态签名。对于内网演示类场景这道校验的性价比已经足够。8. 写在最后的一些实操体会这套Windows下的Nginx RTMP服务搭建方案我自己在不同机器上反复搭过很多遍。整体走下来最核心的体会是网络的故障排查顺序永远是“链路→防火墙→服务→配置”而不是反过来。大多数看似诡异的直播连接问题最后都出在防火墙上或者网卡节能上真正需要动Nginx配置的情况反而很少。第二个体会是Windows下做流媒体服务性能和稳定性虽然不如Linux但胜在团队熟悉、部署快、维护成本低。如果你只是内网几十个人用Windows完全够用如果你要公网大规模分发还是趁早换Linux加SRS或其他专用流媒体服务器更合适。最后分享一个小技巧给Nginx目录做一个干净的备份。当配置改乱、怎么都调不回来的时候直接把备份目录解压覆盖然后改回业务配置里的几个IP和路径10分钟内就能恢复服务。这个习惯帮我省掉过很多不必要的麻烦。如果你照着这篇文章把自己的RTMP服务跑起来了可以顺手验证一下/stat页面里的状态数据和实际推流码率是否对得上这个步骤能帮你更直观地理解RTMP流在服务端的表现。遇到其他问题也欢迎在评论区把现象、配置和日志贴出来这种实际场景下的问题往往比文章里的例子更有讨论价值。