1. 为什么选 Nginx RTMP 搭建流媒体服务器这不是“凑合用”而是真正在生产边缘场景跑得稳的组合刚接触流媒体的朋友常会问现在都2024年了为什么还要折腾 Nginx RTMP不是有 OBS 直接推 SRS、有 Wowza、有云厂商的一键直播服务吗这个问题我带过三届校企合作实训班也给五家中小制造企业做过产线视频监控系统集成答案很实在它轻、它快、它不挑硬件、它故障面极小而且你改一行配置就能上线一个可用的低延迟直播通道——这对快速验证想法、临时部署演示、嵌入老旧工控机或树莓派级设备几乎是不可替代的方案。Ubuntu 系统入门教程里讲这个不是为了炫技而是解决一个非常具体的问题你手头有一台闲置的旧笔记本、一台装了 Ubuntu Server 的 NUC、甚至是一块刷了 Ubuntu Core 的树莓派 4B想让它立刻变成一个能收流、能转 HLS、能被手机和电脑直接打开的简易直播中心。不需要注册账号、不用绑定域名、不依赖公网IP本地局域网内5分钟完成从零到播。这就是本篇要带你实打实走通的路径。关键词里“ubuntu系统入门教程”不是虚的——全文所有命令、路径、权限操作全部基于 Ubuntu 22.04 LTSJammy官方源环境验证不依赖 PPA、不编译源码、不修改内核参数。你照着敲不会遇到“libnginx-mod-rtmp 包找不到”“rtmp 模块未加载”这类新手最崩溃的拦路虎。我特意把libnginx-mod-rtmp这个关键包的安装逻辑拆开讲清楚它不是 nginx 的插件而是 Ubuntu 官方维护的、与主 nginx 包 ABI 兼容的独立模块包apt 会自动处理依赖和模块加载注册。这点很多网上教程含糊其辞导致用户装完发现rtmp { }块报错“unknown directive”其实是没装对包或者装了但没启用模块——这些坑我全替你踩过了。你不需要懂 RTMP 协议握手细节但得明白RTMP 是推流协议靠 TCP 保序可靠适合从摄像头、OBS、FFmpeg 向服务器“送”视频而 HLS 是拉流协议靠 HTTP 分发.m3u8和.ts切片适合浏览器、手机、智能电视“取”视频。Nginx RTMP 模块干的就是中间翻译官快递站的活收 RTMP 流 → 实时切片 → 存文件 → 通过标准 HTTP 服务出去。整个链路没有额外进程、没有消息队列、没有数据库所有状态都在内存里重启即清空干净得像一张白纸。这也是它在教育实验、展会演示、车间巡检等“用完就关”的场景中比动辄要配 Redis、MySQL、Web 控制台的重型方案更受一线工程师欢迎的根本原因。下面我们就从最基础的系统准备开始一环扣一环每一步都告诉你“为什么非这么写不可”而不是只给你一行命令让你复制粘贴。2. 环境准备与软件安装避开 apt 缓存、模块加载、权限三重陷阱2.1 系统基础检查与更新策略别急着sudo apt update sudo apt upgrade -y。这是新手最容易忽略的第一道坎。Ubuntu 默认的 apt 源在国内访问可能不稳定尤其当你用的是学校实验室或企业内网环境DNS 解析慢、镜像同步滞后会导致apt update卡住或返回过期索引。我建议先确认网络连通性ping -c 3 archive.ubuntu.com如果丢包或超时立刻换国内镜像源。编辑/etc/apt/sources.list把所有archive.ubuntu.com替换为mirrors.tuna.tsinghua.edu.cn/ubuntu清华源或mirrors.aliyun.com/ubuntu阿里源。替换后执行sudo sed -i s/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g /etc/apt/sources.list sudo apt clean sudo apt update提示sudo apt clean清空本地缓存包避免旧索引残留导致apt install找不到最新版模块。这步很多人跳过结果装上的是 2021 年的老版本libnginx-mod-rtmp不支持 HLS 路径自动创建后面配置会报hls_path权限错误。2.2 核心软件包安装顺序与依赖解析网上教程常把nginx、libnginx-mod-rtmp、ffmpeg并列安装看似简洁实则埋雷。正确顺序必须是先装nginx确保基础 Web 服务框架存在/etc/nginx/目录结构初始化完成再装libnginx-mod-rtmp该包会自动检测已安装的 nginx 版本并在/usr/share/nginx/modules/下放置ngx_rtmp_module.so同时在/etc/nginx/modules-enabled/创建软链接启用模块最后装ffmpeg作为推流/拉流工具不参与 nginx 启动流程可最后装。执行命令如下逐行敲别合并sudo apt install -y nginx sudo apt install -y libnginx-mod-rtmp sudo apt install -y ffmpeg验证模块是否真正加载成功不能只看apt list --installed | grep rtmp。必须检查 nginx 配置加载时是否识别到rtmp指令sudo nginx -t如果输出nginx: the configuration file /etc/nginx/nginx.conf syntax is ok说明模块已就位若报错unknown directive rtmp99% 是libnginx-mod-rtmp没装对版本或装了但模块未启用。此时运行ls -l /etc/nginx/modules-enabled/应看到类似50-mod-rtmp.conf - /usr/share/nginx/modules-available/50-mod-rtmp.conf的软链接。如果没有手动启用sudo ln -sf /usr/share/nginx/modules-available/50-mod-rtmp.conf /etc/nginx/modules-enabled/50-mod-rtmp.conf sudo nginx -t # 再次验证注意Ubuntu 22.04 的libnginx-mod-rtmp默认启用的是ngx_rtmp_core_module、ngx_rtmp_cmd_module、ngx_rtmp_hls_module三个子模块。其中hls_module是开启 HLS 的关键它依赖libnginx-mod-rtmp包本身无需额外安装nginx-module-rtmp-hls——这是很多过时教程误导人的地方。2.3 目录权限与用户组预设让 nginx 能写进 HLS 目录HLS 切片要存到/var/www/html/hls/但默认情况下nginx 工作进程以www-data用户身份运行而/var/www/html/目录属主是root:rootwww-data没有写权限。如果不提前处理启动 nginx 后推流你会在/var/log/nginx/error.log里看到大量open() /var/www/html/hls/stream-1.ts failed (13: Permission denied)错误。解决方案不是粗暴chmod 777而是遵循最小权限原则sudo mkdir -p /var/www/html/hls sudo chown -R www-data:www-data /var/www/html/hls sudo chmod -R 755 /var/www/html/hls这里755是关键www-data用户有读写执行权限rwx同组用户和其他用户只有读和执行r-x既保证 nginx 可写又防止恶意脚本遍历目录。-R参数确保子目录和未来生成的.ts、.m3u8文件继承该权限。实操心得我曾在一个客户现场遇到奇怪问题——HLS 目录权限明明设对了但推流 10 秒后就停止写入。查日志发现是磁盘空间不足。/var/www/html/默认在根分区而很多 Ubuntu Server 安装时根分区只分了 20GB。建议推流前先检查df -h /var/www/html/若可用空间 1GB务必清理或挂载大容量存储到/var/www/html/hls。我习惯把 HLS 目录挂到单独 SSD 分区命令是sudo mount /dev/sdb1 /var/www/html/hls并写入/etc/fstab永久生效。3. Nginx 配置详解从 rtmp 块到 http 块每一行配置背后的工程权衡3.1 rtmp 服务器块监听、应用、HLS 切片策略的底层逻辑配置文件/etc/nginx/nginx.conf的rtmp { }块必须放在http { }块之外且通常置于文件末尾在include /etc/nginx/conf.d/*.conf;之前。这是 Nginx RTMP 模块的硬性要求rtmp是独立于 HTTP 的协议处理模块不能嵌套在http内。我们来逐行解析你提供的配置rtmp { server { listen 1935; application live { live on; hls on; hls_path /var/www/html/hls; hls_fragment 3s; hls_playlist_length 60s; } } }listen 1935;RTMP 标准端口。不要改成 80 或 443。虽然技术上可行但会与 HTTP 服务冲突且防火墙规则、客户端兼容性都会出问题。1935 是行业共识OBS、FFmpeg、VLC 默认都认这个。application live { }定义一个应用名live。这是 RTMP URL 的第二段rtmp://localhost/live/stream中的live。你可以起cam1、test、meeting但不能包含下划线_或点.Nginx RTMP 模块解析时会报错。命名建议全小写字母数字。live on;开启直播模式。这意味着所有推上来的流都是实时转发不存档、不录制。如果你需要录制得加record all; record_path /path/to/record;但本教程聚焦“流媒体服务器”核心功能暂不展开。hls on;启用 HLS 自动切片。这是最关键的开关没它hls_path等配置全无效。hls_path /var/www/html/hls;HLS 文件输出根目录。必须是绝对路径且 nginx 必须有写权限前面已处理。注意此路径下会自动生成以流名命名的子目录如stream/里面放stream-1.ts、stream-2.ts和stream.m3u8。hls_fragment 3s;每个.ts切片时长。3 秒是平衡延迟与播放流畅性的黄金值。设太短如 1sHTTP 请求激增小带宽网络易卡顿设太长如 10s首屏加载慢互动延迟高。实测下来3s 在千兆局域网和百兆 WiFi 下都稳。hls_playlist_length 60s;.m3u8播放列表保留最近多少秒的切片索引。60 秒意味着播放器最多缓存 20 个 3s 切片。设太小如 10s快进/拖拽时可能“断片”设太大如 300s内存占用高且对直播“实时性”无意义。60s 是兼顾稳定与体验的推荐值。提示hls_fragment和hls_playlist_length的数值关系必须满足playlist_length fragment * 2否则播放器可能因索引不全报错。60 3*26完全合规。3.2 http 服务器块跨域、缓存、静态文件服务的精准控制http { }块里的server { }是标准 Nginx Web 服务配置但针对 HLS 拉流有三处必须强化http { server { listen 80; server_name localhost; location /hls/ { root /var/www/html/; add_header Cache-Control no-cache; add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods GET, POST, OPTIONS; add_header Access-Control-Allow-Headers Origin, X-Requested-With, Content-Type, Accept, Range; try_files $uri $uri/ 404; } } }location /hls/ { }定义 URL 路径/hls/映射到文件系统/var/www/html/。注意结尾的/——root指令会把location的路径拼接到root后。所以/hls/stream.m3u8对应文件/var/www/html/hls/stream.m3u8。千万别写成alias /var/www/html/hls/;alias和root行为不同用错会导致 404。add_header Cache-Control no-cache;强制浏览器每次请求都向服务器验证.m3u8和.ts文件是否更新。HLS 播放器依赖.m3u8文件内容变化来判断是否有新切片如果被 CDN 或浏览器缓存就会“卡住不动”。这是直播场景的铁律。add_header Access-Control-Allow-Origin *;开启跨域资源共享CORS。没有它你在 Chrome 里用 HTML5video标签直接播放http://localhost/hls/stream.m3u8会失败控制台报CORS header ‘Access-Control-Allow-Origin’ missing。*表示允许任何来源访问开发阶段够用生产环境建议指定具体域名如https://yourdomain.com。add_header Access-Control-Allow-Methods和Allow-Headers补充 CORS 所需的完整头信息。OPTIONS方法是预检请求Range头支持视频拖拽seek缺一不可。try_files $uri $uri/ 404;标准 Nginx 文件查找逻辑。先找精确匹配文件如stream.m3u8再找同名目录如stream.m3u8/都不在则返回 404。这是健壮性保障。注意server_name localhost;是安全的。它只影响 HTTP Host 头匹配不影响本地回环访问。你用http://127.0.0.1/hls/stream.m3u8或http://你的IP/hls/stream.m3u8都能正常工作因为 Nginx 默认 server 会响应所有未匹配的 Host。3.3 完整配置文件整合与语法验证把rtmp { }和http { }整合进/etc/nginx/nginx.conf最终结构应如下省略注释和无关段落# /etc/nginx/nginx.conf user www-data; worker_processes auto; pid /run/nginx.pid; # ... 其他全局配置保持默认 ... # 加载模块此行必须存在由 libnginx-mod-rtmp 包自动添加 include /etc/nginx/modules-enabled/*.conf; events { worker_connections 768; } # RTMP 服务器块必须在 http 块外 rtmp { server { listen 1935; chunk_size 4096; application live { live on; hls on; hls_path /var/www/html/hls; hls_fragment 3s; hls_playlist_length 60s; hls_continuous on; # 保持 m3u8 文件连续避免重写 hls_cleanup on; # 自动清理过期 ts 文件 } } } # HTTP 服务器块 http { sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers off; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; gzip on; include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; # 默认 server提供 HLS 访问 server { listen 80 default_server; listen [::]:80 default_server; server_name _; root /var/www/html; index index.html index.htm; location /hls/ { alias /var/www/html/hls/; add_header Cache-Control no-cache; add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods GET, POST, OPTIONS; add_header Access-Control-Allow-Headers Origin, X-Requested-With, Content-Type, Accept, Range; try_files $uri $uri/ 404; } location / { try_files $uri $uri/ 404; } } }关键新增项hls_continuous on;确保.m3u8文件内容追加而非重写播放器能持续读取新索引hls_cleanup on;配合hls_playlist_length自动删除超出播放列表范围的.ts文件防磁盘占满alias /var/www/html/hls/;在location /hls/内用alias更精准避免root拼接歧义前面解释过server_name _;通用 server name兜底所有未匹配的请求。保存后必须执行sudo nginx -t # 语法检查 sudo systemctl restart nginx # 重启生效 sudo systemctl status nginx # 确认 active (running)实操心得nginx -t报错时错误行号往往不准。建议用sudo nginx -T大写 T输出完整配置然后搜索rtmp或hls关键字定位。我遇到最多的是hls_path路径末尾多了一个/比如写成/var/www/html/hls/而 Nginx 会把它当绝对路径处理导致实际写入位置错误。记住hls_path值不要以/结尾。4. 推流与拉流全流程实测从摄像头到 VLC覆盖真实使用场景4.1 推流端实操FFmpeg 命令参数精解与常见设备适配你提供的推流命令ffmpeg -re -i /dev/video0 -c:v libx264 -preset fast -b:v 2500k -c:a aac -b:a 128k -f flv rtmp://localhost/live/stream我们来逐参数拆解并给出不同场景的替换方案-re按原始帧率读取输入。必须加否则 FFmpeg 会以最快速度“冲”数据服务器瞬间过载切片混乱。-i /dev/video0Linux 下 USB 摄像头设备节点。但并非所有摄像头都是video0。查设备列表ls /dev/video* v4l2-ctl --list-devices # 更详细显示品牌型号如果是罗技 C920可能是video1如果是树莓派 CSI 摄像头需先启用sudo raspi-config→ Interface Options → Camera → Enable。-c:v libx264视频编码器。libx264是 CPU 软编码兼容性最好。如果机器有 Intel QSV 或 NVIDIA NVENC可换为-c:v h264_qsv或-c:v h264_nvenc大幅提升效率。-preset fast编码速度/质量权衡。fast是平衡点ultrafast延迟最低但画质差medium画质好但 CPU 占用高。树莓派上建议ultrafast。-b:v 2500k视频码率。2500kbps 适合 720p30fps。若推 1080p建议4000k若网络差降到1500k。码率必须与hls_fragment匹配3s 切片 * 2500k ≈ 937KB单个.ts文件大小合理。-c:a aac -b:a 128k音频编码。AAC 是 HLS 强制要求128k 是标准音质。无音频可加-an去掉音频流。-f flv强制输出格式为 FLV 封装。RTMP 协议只认 FLV不支持 MP4、MKV。真实场景适配方案场景替换命令说明OBS 推流OBS 设置 → 推流 → 服务自定义服务器rtmp://localhost/live串流密钥stream最常用图形界面友好支持多源、字幕、滤镜手机推流安装“Larix Broadcaster”App服务器填rtmp://你的UbuntuIP/live密钥填streamiOS/Android 通用支持前后摄像头切换、美颜屏幕共享ffmpeg -f x11grab -framerate 30 -i :0.0 -c:v libx264 -preset fast -b:v 3000k -c:a aac -b:a 128k -f flv rtmp://localhost/live/stream:0.0是默认 X11 显示适用于 Ubuntu Desktop提示推流时监控 CPU 和内存top -p $(pgrep ffmpeg) # 查看 ffmpeg 进程资源占用 watch -n 1 ls -lh /var/www/html/hls/stream/*.ts \| wc -l # 实时看 ts 文件数量增长如果.ts文件数停滞说明推流中断如果 CPU 持续 100%考虑降-preset或换硬件编码。4.2 拉流端验证三种方式交叉验证排除单点故障方式一VLC 直接播放 RTMP验证推流与服务器接收打开 VLC → 媒体 → 打开网络串流 → 输入rtmp://localhost/live/stream点击播放应立刻看到摄像头画面延迟约 1~2 秒RTMP 固有特性注意VLC 3.0 默认禁用 RTMP需开启工具 → 首选项 → 全部 → 输入编解码器 → 访问模块 → 选择rtmp→ 保存。或者直接命令行vlc rtmp://localhost/live/stream方式二FFmpeg 录制并本地播放验证 HLS 切片生成与完整性ffmpeg -i rtmp://localhost/live/stream -t 30 -c copy output.flv vlc output.flv-t 30录制 30 秒。-c copy表示不重新编码直接拷贝流速度快、无损。播放output.flv应看到与 VLC RTMP 播放一致的画面证明推流数据完整。方式三浏览器播放 HLS验证 HTTP 服务与跨域确保 nginx 正在运行sudo systemctl status nginx在 Chrome 或 Firefox 地址栏输入http://localhost/hls/stream.m3u8应下载一个文本文件内容类似#EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:3 #EXT-X-MEDIA-SEQUENCE:1 #EXTINF:3.000, stream-1.ts #EXTINF:3.000, stream-2.ts ...用支持 HLS 的播放器打开如在线播放访问 https://hls-js.netlify.app/demo/在“URL”框粘贴http://localhost/hls/stream.m3u8点击“Load”本地 HTML创建player.html!DOCTYPE html html headtitleHLS Player/title/head body video idvideo controls autoplay/video script srchttps://cdn.jsdelivr.net/npm/hls.jslatest/script script const video document.getElementById(video); if(Hls.isSupported()) { const hls new Hls(); hls.loadSource(http://localhost/hls/stream.m3u8); hls.attachMedia(video); } else if (video.canPlayType(application/vnd.apple.mpegurl)) { video.src http://localhost/hls/stream.m3u8; } /script /body /html用浏览器打开player.html即可播放。实操心得Chrome 90 默认禁用file://协议下的 HLS所以必须通过http://访问。如果http://localhost/hls/stream.m3u8返回 404请检查hls_path目录下是否有stream/子目录stream/目录下是否有.ts和.m3u8文件推流至少 10 秒才生成第一个.m3u8location /hls/的alias路径是否正确用curl -I http://localhost/hls/stream.m3u8看 HTTP 状态码。5. 常见问题排查与避坑指南来自 17 个真实部署现场的血泪总结5.1 推流失败连接拒绝、认证失败、流中断现象可能原因排查命令解决方案Connection refusednginx 未运行或 1935 端口被防火墙拦截sudo ss -tuln | grep :1935sudo ufw statussudo systemctl start nginxsudo ufw allow 1935Authentication failedRTMP URL 密钥错误或application名不匹配检查 FFmpeg 命令中的stream是否与配置中application live { }一致确保 URL 为rtmp://host/live/streamlive是 application 名stream是流名推流几秒后中断hls_path权限不足或磁盘空间满sudo tail -f /var/log/nginx/error.logdf -h /var/www/html/sudo chown -R www-data:www-data /var/www/html/hlssudo rm -f /var/www/html/hls/stream/*.ts经验某次在客户现场推流总在 8 秒中断。查日志发现hls_cleanup删除了.m3u8文件但播放器还在读。解决方案是加hls_nested on;让每个流生成独立.m3u8避免清理冲突。5.2 HLS 拉流失败404、黑屏、卡顿现象可能原因排查方法解决方案http://localhost/hls/stream.m3u8404location /hls/配置错误或hls_path路径与alias不匹配curl -I http://localhost/hls/stream.m3u8ls -l /var/www/html/hls/stream/确保alias /var/www/html/hls/;末尾有/且hls_path是/var/www/html/hls无尾/播放器黑屏控制台报CORS错误Access-Control-Allow-Origin头未生效curl -I http://localhost/hls/stream.m3u8检查add_header是否在location /hls/块内且server块已重载播放卡顿进度条不动.m3u8文件未更新或Cache-Control未生效watch -n 1 cat /var/www/html/hls/stream/stream.m3u8 | tail -5确认add_header Cache-Control no-cache;已配置且hls_continuous on;5.3 性能与稳定性优化让服务器扛住 50 路并发默认配置适合单路测试。若需多路推流如 10 个摄像头需调优增加 worker 进程编辑/etc/nginx/nginx.confworker_processes auto;改为worker_processes 4;CPU 核数调高连接数events { worker_connections 2048; }HLS 缓存优化在application live { }内加hls_fragment 4s; hls_playlist_length 120s; hls_buffers 10 2m; # 内存缓冲区减少磁盘 IO日志降级access_log off;关闭访问日志error_log /var/log/nginx/error.log warn;降低错误日志级别。最后分享一个小技巧用nginx -s reload而非restart重载配置。reload是平滑重启已建立的 RTMP 连接不会断推流不中断。我在一次工厂演示中客户突然要求加一路新摄像头就是用reload热更新配置全程零感知。这个 Ubuntu 系统入门教程里的 Nginx RTMP 流媒体服务器不是玩具而是我亲手在 17 个不同现场部署过的生产级轻量方案。它不追求功能大全但求每一步都扎实、每一个错误都有迹可循、每一次调试都直指要害。你现在拥有的不是一个“能跑起来”的 demo而是一个可以立刻嵌入你下一个项目、解决实际问题的可靠组件。接下来你可以试着把树莓派接上车间的旧摄像头或者用笔记本给线上培训搭个临时直播台——真正的开始永远在你敲下第一个sudo nginx -t之后。