
به اشتراک بگذارید

به اشتراک بگذارید
راهاندازی پخش زنده روی سایت یعنی سه قطعه را به هم وصل کنید. یک ورودی RTMP تصویر را از نرمافزار ضبط میگیرد، یک بخش آن را به قطعههای HLS میبرد و یک پلیر در مرورگر بیننده پخش میکند. ماژول RTMP برای nginx هر سه کار را روی یک سرور انجام میدهد.
| قطعه زنجیره | ابزار | آنچه تنظیم میکنید |
|---|---|---|
| فرستنده | نرمافزار OBS یا FFmpeg | نشانی rtmp و کلید استریم |
| ورودی سرور | بلوک rtmp در nginx.conf | دایرکتیو listen روی پورت 1935 و یک application |
| تبدیل به قطعه | همان ماژول RTMP | دایرکتیوهای hls، hls_path و hls_fragment |
| تحویل به بیننده | بلوک server در http | سرو کردن پوشه HLS با HTTPS |
| پخش | کتابخانه hls.js | یک تگ video و نشانی m3u8 |
💡 خلاصه فنی پیش از شروع
ماژول RTMP یک افزونه جداگانه برای nginx است؛ nginx خالی این قابلیت را ندارد.
✅ در دبیان و اوبونتو بسته آماده libnginx-mod-rtmp ماژول را داینامیک نصب و خودش فعال میکند، پس خط load_module لازم نیست.
✅ بلوک rtmp فقط در سطح main فایل /etc/nginx/nginx.conf معتبر است، نه در sites-available.
بیشتر راهنماهای این موضوع فهرست دستورهای نصب را میآورند و همانجا تمام میشوند. اما چیزی که بعد از اولین پخش موفق دردسر میسازد، دستور نصب نیست. حجم ترافیکی است که از پورت سرور بیرون میرود و تأخیری که بیننده میبیند. پس ترتیب این مقاله برعکس است: اول مسیر ویدیو، بعد انتخاب بیلد و تنظیم، و در پایان حساب مصرف. برای زیرساخت یک سرور مجازی ایران کافی است.
📌 آنچه در این مقاله میخوانید
◀️ زنجیره پخش از OBS تا مرورگر
◀️ کدام بیلد nginx ماژول RTMP را دارد؟
◀️ تنظیم بلوک rtmp و سرو کردن HLS روی دامنه
◀️ حسابوکتاب پهنای باند، تأخیر و بار CPU

تصویر شما با پروتکل RTMP و پورت 1935 به سرور میرسد و در یک application داخل بلوک rtmp دریافت میشود. همانجا به قطعههای چندثانیهای و یک پلیلیست m3u8 روی دیسک تبدیل میشود. بلوک http هم این فایلها را مثل محتوای ساده سایت به پلیر میدهد.
پروتکل RTMP قدیمی است و پلیرش سالها پیش از مرورگرها حذف شد، ولی در سمت ارسال باقی ماند. نرمافزارهای ضبط مثل OBS و دستور FFmpeg همین را مقصد پیشفرض میشناسند.
یک نکته امنیتی را از همینجا بدانید: ترافیک RTMP در این ماژول رمزنگاری نمیشود. پس کلید استریم به شکل متن ساده روی شبکه میرود و باید انتشار را محدود کنید.
ماژول، جریان ورودی را به فایلهای کوتاه با پسوند ts و یک فایل m3u8 میشکند. فایل m3u8 فهرست نام و مدت قطعهها است و پلیر هر چند ثانیه آن را دوباره میخواند. مشخصات این قالب در RFC 8216 ثبت شده و همین باعث میشود پخش HLS در iOS و سافاری بدون کتابخانه جاوااسکریپتی کار کند.
🔸 مسیر داده روی سرور
مسیر داده اینگونه است. OBS → rtmp://IP:1935/src → nginx (rtmp) → /var/www/hls/src/<name>/index.m3u8 + قطعههای ts → nginx (http, 443) → پلیر مرورگر
ماژول RTMP در nginx رسمی گنجانده نشده و باید جداگانه بیاید. سه مسیر دارید: بسته داینامیک آماده در دبیان و اوبونتو، کامپایل nginx از سورس با --add-dynamic-module، و ماژول تجاری روی NGINX Plus. اولین قدم راهاندازی پخش زنده روی سایت همین انتخاب است، چون محل فایل تنظیم و روش ارتقا را عوض میکند.
| سیستمعامل | مسیر پیشنهادی | نکته |
|---|---|---|
| اوبونتو و دبیان | بسته libnginx-mod-rtmp | در دبیان از مخزن رسمی و در اوبونتو از بخش universe؛ خودش فعال میشود |
| آلمالینوکس و راکی | کامپایل از سورس یا مخزن ثالث | مسیر رایج، کامپایل است |
| نسخه دلخواه nginx | کامپایل با add-dynamic-module | کنترل کامل، ولی هر ارتقا دوباره کامپایل میخواهد |
| NGINX Plus | بسته nginx-plus-module-rtmp | مسیر تجاری و پشتیبانیشده با دستور load_module |
سادهترین مسیر همین است. بسته libnginx-mod-rtmp فایل ماژول را در /usr/lib/nginx/modules/ میگذارد و فایل فعالسازی را از modules-available به modules-enabled میبرد. پس ماژول از همان لحظه بار میشود و نباید load_module را دستی اضافه کنید، وگرنه nginx -t با خطای بارگذاری دوباره رد میشود.
sudo apt update
sudo apt install nginx libnginx-mod-rtmp ffmpeg
ls /etc/nginx/modules-enabled/
sudo systemctl restart nginx
یک محدودیت را در نظر بگیرید: نسخه این بسته به نسخه nginx همان مخزن قفل است، چون وابستگی آن روی بسته ABI نوشته شده. اگر nginx را از مخزن nginx.org نصب کرده باشید، باید سراغ روش دوم بروید.
طبق مستندات configure در nginx.org، گزینه --add-module=path یک ماژول بیرونی را ثابت داخل باینری میبرد و --add-dynamic-module=path همان ماژول را داینامیک میسازد تا با load_module بارگذاری شود. نسخه داینامیک را انتخاب کنید؛ ارتقای nginx سادهتر میشود.
sudo apt install build-essential libpcre3-dev zlib1g-dev libssl-dev git
git clone https://github.com/arut/nginx-rtmp-module.git
wget https://nginx.org/download/nginx-1.30.6.tar.gz
tar xf nginx-1.30.6.tar.gz && cd nginx-1.30.6
./configure --with-http_ssl_module --add-dynamic-module=../nginx-rtmp-module
make && sudo make install
نسخه stable روی nginx.org در زمان نوشتن این مقاله 1.30.6 و mainline 1.31.8 است؛ شماره را از همان صفحه دانلود بردارید. اگر nginx را قبلاً با apt نصب کردهاید، make install نکنید. این کار یک nginx دوم با مسیر و سرویس جدا میسازد. بهجایش خروجی nginx -V را بردارید و همان گزینهها را با افزودن ماژول دوباره اجرا کنید.
روی NGINX Plus هم بسته nginx-plus-module-rtmp از مخزن رسمی نصب و با خط load_module modules/ngx_rtmp_module.so; در سطح main بارگذاری میشود.
⚠️ یک نکته درباره نگهداری ماژول
این ماژول بخشی از پروژه nginx نیست و با چرخه انتشار آن همقدم نمیشود. پس پیش از ارتقای nginx، روی یک سرور تست بیلد را بسازید و پخش را امتحان کنید.

تنظیم از دو تکه ساخته میشود که در دو جای متفاوت مینشینند. بلوک rtmp باید در سطح main فایل /etc/nginx/nginx.conf و بیرون از http {} باشد؛ بلوک server مثل هر سایت دیگر در /etc/nginx/sites-available/live.conf میرود و به sites-enabled لینک میشود. هسته کار همین دو تکه است و بقیه، تنظیم امنیت و کیفیت است.
دایرکتیوهای این بلوک پیشفرضهای مستندشده دارند و همینها لحن راهاندازی پخش زنده روی سایت را تعیین میکنند: hls_fragment پنج ثانیه، hls_playlist_length سی ثانیه، hls_nested خاموش و hls_cleanup روشن. مقدار chunk_size هم پیشفرض 4096 است.
# /etc/nginx/nginx.conf (سطح main، بیرون از http)
rtmp {
server {
listen 1935;
chunk_size 4096;
application src {
live on;
record off;
hls on;
hls_path /var/www/hls/src;
hls_fragment 4s;
hls_playlist_length 20s;
hls_nested on;
hls_cleanup on;
drop_idle_publisher 10s;
allow publish 192.0.2.10; # IP اتاق ضبط خودتان
deny publish all;
allow play all;
}
}
}
hls_fragment 4s: طول هر قطعه. هرچه کوچکتر، تأخیر کمتر و درخواست HTTP بیشتر.hls_playlist_length 20s: عمق پلیلیست، یعنی پلیر چند قطعه گذشته را میبیند.hls_nested on: برای هر نام استریم یک پوشه جدا میسازد.hls_cleanup on: قطعههای بیرونافتاده از پلیلیست را پاک میکند.drop_idle_publisher 10s: اتصال فرستنده بیداده را میبندد.دایرکتیو hls_path اگر پوشه نباشد خودش میسازد، پس نگرانی اصلی مجوز نوشتن در مسیر والد است. کاربر اجراکننده nginx در دبیان و اوبونتو www-data و در آلما و راکی nginx است. مسیر را پیش از زدن Enter دوباره بخوانید، چون chown -R روی مسیر اشتباه جبرانناپذیر است.
قطعهها فایل ساده هستند، پس بلوک server همیشگی کار را انجام میدهد. سه چیز را تنظیم کنید: گواهی TLS، نوع MIME فایلهای m3u8 و ts، و هدر Cache-Control روی no-cache، چون پلیر پلیلیست را مدام دوباره میخواند.
# /etc/nginx/sites-available/live.conf
server {
listen 443 ssl;
server_name live.example.ir;
ssl_certificate /etc/letsencrypt/live/live.example.ir/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/live.example.ir/privkey.pem;
location /hls/ {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root /var/www;
add_header Cache-Control no-cache always;
}
}
بدون دو خط گواهی، nginx با خطای نبودن ssl_certificate بالا نمیآید. در نسخههای تازه، فایل mime.types خود nginx هر دو نوع را دارد و بلوک types محض اطمینان است. دقت کنید که root /var/www با مسیر /hls/ به همان hls_path میرسد. در پایان sudo nginx -t و سپس reload.
کتابخانه hls.js طبق مستندات خودش فقط روی مرورگرهای دارای Media Source Extensions کار میکند و پیشنهاد میدهد اول Hls.isSupported() را بسنجید. همان مستندات میگوید canPlayType در کروم هم مقدار غیرخالی برمیگرداند ولی پشتیبانی همهجا یکسان نیست، پس ترتیب سنجش مهم است. سافاری نشانی m3u8 را مستقیم در تگ video باز میکند.
<video id="live" controls playsinline></video>
<script src="https://cdn.jsdelivr.net/npm/hls.js@1"></script>
<script>
var v = document.getElementById('live');
var src = 'https://live.example.ir/hls/src/mystream/index.m3u8';
if (window.Hls && Hls.isSupported()) {
var hls = new Hls();
hls.loadSource(src);
hls.attachMedia(v);
} else if (v.canPlayType('application/vnd.apple.mpegurl')) {
v.src = src;
}
</script>
در OBS نوع سرویس را Custom بگذارید، در فیلد Server نشانی rtmp://IP:1935/src و در فیلد Stream Key نام استریم را بنویسید. همین نام در مسیر پلیلیست ظاهر میشود، پس قابل حدس نگذارید. در فایروال هم پورت را فقط به همان IP باز کنید: sudo ufw allow from 192.0.2.10 to any port 1935 proto tcp.
برای کنترل جدیتر دو ابزار دیگر هم دارید. نشانی 192.0.2.10 در نمونهها یک آدرس مستندسازی است و اگر عوضش نکنید هیچکس نمیتواند پخش کند. دایرکتیو on_publish نشانی یک وبسرویس را پیش از شروع پخش صدا میزند؛ پاسخ موفق اجازه میدهد و ناموفق اتصال را رد میکند، پس توکن یکبارمصرف ممکن میشود. تفاوت مفهومی دو حالت پخش را در راهنمای تفاوت استریمینگ و برادکستینگ آوردهایم.

هزینههای این معماری قابل محاسبه است. ترافیک خروجی از مجموع نرخ بیت بینندهها میآید و تأخیر از طول قطعه و عمق پلیلیست ساخته میشود. بار پردازنده هم با هر کیفیت اضافه بالا میرود. این عددها را با مقدارهای تنظیم خودتان حساب کنید، نه با عدد نمونه مقالهها.
ویدیو با نرخ بیت ثابت بیرون میرود، پس حساب آن ضرب ساده است. نرخ بیت هر کیفیت را در تعداد بیننده همان کیفیت ضرب کنید و جمع بزنید. برای حجم ترافیک هم یک مگابیت بر ثانیه در یک ساعت برابر 450 مگابایت است (3600 تقسیم بر 8).
| کیفیت | نرخ بیت ویدیو و صدا | مصرف یک بیننده در یک ساعت |
|---|---|---|
| 720p | 2500 + 128 کیلوبیت بر ثانیه | حدود ۱.۲ گیگابایت |
| 480p | 900 + 96 کیلوبیت بر ثانیه | حدود ۴۵۰ مگابایت |
| 360p | 600 + 64 کیلوبیت بر ثانیه | حدود ۳۰۰ مگابایت |
عدد ستون آخر از همان فرمول درآمده و گرد شده است. قالب MPEG-TS و درخواستهای مکرر پلیلیست هم سرباری دارند. بهتر است اندازهاش را بگیرید: یک پخش کوتاه انجام دهید، حجم پوشه خروجی را با du -sh /var/www/hls ببینید و تقسیم بر مدت پخش کنید.
🔶 نکته زیرساخت
برای تماشای بینندهها باید فایلهای HLS از اینترنت در دسترس باشند. سرور مجازی ایران وبداده IP مستقیم دارد که از اینترنت بینالملل هم قابل دسترسی است و IPv4 و IPv6 را پشتیبانی میکند. پنل آن اسنپشات هم دارد، پس پیش از دستکاری تنظیم nginx یک اسنپشات بگیرید.
تأخیر HLS تصادفی نیست و بیشترش از دو عددی میآید که خودتان نوشتهاید. قطعهای که در حال ساخت است تا کامل نشود در پلیلیست نمیآید و پلیر هم پیش از شروع، چند قطعه را بافر میکند. پس با hls_fragment 4s فاصله واقعیت و تصویر بیننده معمولاً از ده ثانیه بالاتر میرود.
کم کردن hls_fragment تأخیر را پایین میآورد، ولی تعداد فایل و درخواست HTTP را بالا میبرد. یک نکته را از خود مستندات ماژول بردارید: برش قطعهها دایرکتیو جدای hls_fragment_slicing دارد و برای شروع جریان از فریم کلیدی هم wait_key هست که پیشفرضش خاموش است. در عمل فاصله فریمهای کلیدی فرستنده را با طول قطعه هماندازه کنید؛ در FFmpeg همان -g است که مستندات آن را اندازه GOP تعریف کرده. برای 30 فریم و قطعه 4 ثانیه یعنی -g 120.
اگر کاربرد شما تأخیر زیر چند ثانیه میخواهد، مثل مزایده یا کلاس تعاملی، فهرست دایرکتیوهای این ماژول چنین چیزی را پوشش نمیدهد و باید سراغ پروتکلهای کمتأخیر بروید.
اگر بینندهها اینترنت یکسانی ندارند، به چند کیفیت نیاز دارید و این یعنی ترانسکد. دایرکتیو exec هنگام شروع پخش یک دستور بیرونی را اجرا میکند. مستندات ماژول دو شرط دارد: مسیر کامل باینری را بنویسید و چون nginx محیط را پاک میکند، env PATH; را هم نگه دارید. بلوک زیر جایگزین application src قبلی است و دو application خروجی را هم اضافه میکند.
env PATH;
application src {
live on;
hls on;
hls_path /var/www/hls/src;
allow publish 192.0.2.10;
deny publish all;
exec /usr/bin/ffmpeg -i rtmp://127.0.0.1:1935/src/$name
-c:a aac -b:a 128k -c:v libx264 -preset veryfast -b:v 2500k -maxrate 2500k -bufsize 5000k -g 120 -s 1280x720 -f flv rtmp://127.0.0.1:1935/hls720/$name
-c:a aac -b:a 96k -c:v libx264 -preset veryfast -b:v 900k -maxrate 900k -bufsize 1800k -g 120 -s 854x480 -f flv rtmp://127.0.0.1:1935/hls480/$name;
}
application hls720 {
live on;
hls on;
hls_nested on;
hls_path /var/www/hls/720;
allow publish 127.0.0.1;
deny publish all;
}
# application hls480 هم همین پنج خط را با hls_path /var/www/hls/480 میگیرد
دو خط deny publish all در applicationهای خروجی اختیاری نیستند. پیشفرض کنترل دسترسی این ماژول اجازه دادن است، پس بدون آنها هر کسی میتواند روی همان نام پخش کند و تصویرش روی سایت شما برود. مستندات FFmpeg هم -maxrate را سقف تحمل نرخ بیت تعریف کرده که به -bufsize نیاز دارد.
هزینه را بیتعارف بگوییم: کدکردن نرمافزاری با libx264 سنگینترین بخش این معماری است و هر کیفیت اضافه بار تازهای روی پردازنده میگذارد. عدد قطعی برای تعداد هسته وجود ندارد، چون به رزولوشن، نرخ فریم و مقدار -preset بستگی دارد. با یک کیفیت شروع کنید و مصرف را با top ببینید. اگر پردازنده جواب نداد، با -c:v copy همان کیفیت فرستنده را پخش کنید.
برای اینکه پلیر بین کیفیتها جابهجا شود، یک پلیلیست مادر در /var/www/hls/live.m3u8 بسازید و نشانی https://live.example.ir/hls/live.m3u8 را به پلیر بدهید.
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=2800000,RESOLUTION=1280x720,CODECS="avc1.4d401f,mp4a.40.2"
/hls/720/mystream/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1100000,RESOLUTION=854x480,CODECS="avc1.4d401e,mp4a.40.2"
/hls/480/mystream/index.m3u8
برای رفع خطا سه دستور کافی است: curl -I https://live.example.ir/hls/720/mystream/index.m3u8 برای سنجش Content-Type، tail -f /var/log/nginx/error.log برای خطای ماژول، و ffprobe rtmp://127.0.0.1:1935/src/mystream برای دیدن جریان ورودی.
حق پخش هر محتوایی که روی این سرور میفرستید باید متعلق به خودتان باشد یا مجوز داشته باشید.
بله، پورت 1935 مسیر ورود تصویر است و باید برای IP فرستنده باز باشد. برای بینندهها لازم نیست، چون تماشا روی پورت 443 انجام میشود.
از نظر فنی بله، چون قطعهها روی HTTP ساده هم سرو میشوند. ولی اگر سایت شما روی HTTPS باشد، مرورگر محتوای HTTP را بلاک میکند و پلیر چیزی نشان نمیدهد.
کروم به کتابخانهای نیاز دارد که از Media Source Extensions استفاده کند و پخش بومی آن مثل سافاری کامل نیست. اول نوع MIME را با curl بسنجید، بعد لود شدن کتابخانه را در کنسول مرورگر.
طول قطعه و عمق پلیلیست را کم کنید و فاصله فریم کلیدی فرستنده را با طول قطعه هماهنگ کنید. به جایی میرسید که کم کردن بیشتر پخش را ناپایدار میکند؛ برای تأخیر زیر چند ثانیه این ماژول مناسب نیست.
دایرکتیو record حالتهایی مثل all و keyframes میگیرد و مسیر ذخیره با record_path تعیین میشود. حواستان به فضای دیسک باشد، چون فایل ضبط جدا از قطعههای HLS نگه داشته میشود.
با روشن بودن hls_cleanup که پیشفرض است، قطعههای بیرونافتاده از پلیلیست پاک میشوند. اگر آن را خاموش کنید، باید خودتان چرخه پاکسازی بنویسید.
بله، دایرکتیو push جریان یک application را به نشانی RTMP دیگری ارسال میکند. هر مقصد اضافه پهنای باند خروجی سرور را بیشتر میکند.
همین ماژول دایرکتیوهای dash و dash_path را هم دارد. تفاوت عملی در پشتیبانی پلیرها است: HLS روی iOS و سافاری بومی کار میکند و DASH به کتابخانه پلیر نیاز دارد.
جمعبندی؛ راهاندازی پخش زنده روی سایت از نصب تا حساب ترافیک
این کار سه مرحله روشن دارد. اول بیلدی از nginx را انتخاب میکنید که ماژول RTMP داشته باشد؛ در دبیان و اوبونتو بسته libnginx-mod-rtmp سریعترین راه است و خودش ماژول را فعال میکند. دوم بلوک rtmp را در سطح main فایل nginx.conf مینویسید تا ورودی پورت 1935 را بگیرد و قطعهها را بسازد. بعد همان پوشه را با گواهی TLS و نوع MIME درست روی دامنه سرو میکنید و در مرورگر با hls.js نشان میدهید. سوم، و مهمتر از آنچه به نظر میرسد، عددها را خودتان حساب میکنید: ترافیک از ضرب نرخ بیت در تعداد بیننده و ساعت پخش، و تأخیر از طول قطعه و عمق پلیلیست. دو محدودیت را هم در نظر بگیرید؛ این ماژول برای تأخیر زیر چند ثانیه ساخته نشده و ترافیک RTMP ورودی رمزنگاری نمیشود. اگر ترانسکد چندکیفیتی میسازید، applicationهای خروجی را هم با deny publish all ببندید.
🚀 زیرساخت پخش را روی سرور خودتان بسازید
برای ورودی RTMP و تحویل HLS به یک سرور با IP مستقیم و منابع قابل ارتقا نیاز دارید. امکان تست ساعتی رایگان سرور هم هست تا پیش از رویداد، تنظیم را بسنجید.
اگر در تنظیم بلوک rtmp یا پخش در مرورگر به مشکلی خوردید، نسخه nginx و خروجی nginx -t را در کامنت بنویسید.
منابع