SSD Nodes Learn 🎉 VPS از $5.50/ماه
راهنماها Matt Connorتوسط Matt Connor

راهنمای میزبانی کنفرانس ویدیویی روی VPS

محاسبه دقیق پهنای باند و رم برای Jitsi و BigBlueButton و Galène. بررسی مشکلات NAT و پورت‌های UDP برای جلوگیری از شکست جلسات گروهی در سرورهای شخصی و VPS.

میزبانی کنفرانس ویدیویی روی VPS با چالش پهنای باند مواجه است

میزبانی شخصی کنفرانس ویدیویی روی سرورهای کوچک به یک دلیل شکست می‌خورد و این دلیل تقریباً هرگز مربوط به نصب نرم‌افزار نیست. بخشی از سرور که تمام ابزارهای مدرن از آن استفاده می‌کنند، SFU (واحد ارسال انتخابی) نام دارد. این واحد یک استریم ویدیویی از هر شرکت‌کننده دریافت کرده و نسخه‌ای از آن را برای تمام شرکت‌کنندگان دیگر ارسال می‌کند؛ بنابراین ترافیک خروجی از سرور با توان دوم تعداد افراد افزایش می‌یابد. یک VPS با 1 GB یا 2 GB رم روی یک uplink اشتراکی، نرم‌افزار را به‌خوبی اجرا می‌کند، اما از پس جلسات گروهی بزرگی که در ذهن دارید برنمی‌آید.

بنابراین کار را به این ترتیب انجام دهید: تعداد افراد را بشمارید، میزان مگابیت مورد نیاز را محاسبه کنید و سپس سرور را انتخاب کنید. نصب نرم‌افزار تنها 20 دقیقه کپی و پیست کردن است، اما این uplink است که تعیین می‌کند آیا صدای شما به دیگران می‌رسد یا خیر.

چرا پهنای باند با توان دوم تعداد شرکت‌کنندگان افزایش می‌یابد؟

با مدل mesh شروع می‌کنیم. هر مرورگر تصویر دوربین را انکود کرده و یک نسخه را مستقیماً برای هر مرورگر دیگر می‌فرستد؛ در این حالت هیچ سرور واسطی ویدیو را پردازش نمی‌کند. یک تماس دو نفره در مدل mesh تنها به یک سرور signalling نیاز دارد و به همین دلیل است که میزبانی تماس‌های یک‌به‌یک تقریباً رایگان است. مدل mesh در حدود چهار یا پنج نفر از کار می‌افتد، زیرا لپ‌تاپی که از اینترنت خانگی استفاده می‌کند، باید چهار یا پنج نسخه مجزا از ویدیوی خود را به‌طور همزمان آپلود کند.

عملکرد SFU متفاوت است. هر مرورگر یک نسخه را به سرور آپلود می‌کند. سرور هدرهای RTP (پروتکل انتقال بلادرنگ) را می‌خواند و آن بسته‌ها را بدون انکود مجدد ویدیو، برای سایر شرکت‌کنندگان ارسال می‌کند. تمام ترفند کار همین است و به همین دلیل است که SFU فشار کمی روی CPU دارد اما پهنای باند شبکه زیادی مصرف می‌کند.

مدل قدیمی‌تر، MCU (واحد کنترل چندنقطه‌ای) است. این واحد تمام استریم‌های ورودی را دیکود کرده، آن‌ها را در یک تصویر واحد ترکیب می‌کند و سپس آن تصویر را دوباره انکود می‌کند. پهنای باند خروجی در این حالت بسیار ناچیز است، اما هزینه CPU بسیار سنگین است. امروزه تقریباً هیچ سرویسی برای ویدیو از MCU استفاده نمی‌کند و در این راهنما نیز از آن استفاده نشده است.

حال محاسبات ریاضی برای یک SFU را بررسی می‌کنیم. فرض کنید هر نفر ویدیو را با نرخ 1.2 Mbps ارسال می‌کند و دوربین هیچ‌کس خاموش نیست. سرور N ضرب‌در 1.2 Mbps دریافت می‌کند که یک رابطه خطی و بی‌خطر است. سرور N ضرب‌در (N منهای 1) ضرب‌در 1.2 Mbps ارسال می‌کند، زیرا هر یک از N نفر باید N منهای 1 استریم دیگر را دریافت کنند. این عدد دوم همان عاملی است که پروژه‌ها را با شکست مواجه می‌کند.

ChartSFU outbound traffic, arithmetic model at 1.2 Mbps per sender
The data behind this chart
[
  {
    "label": "4 people",
    "sfu_egress_mbps": 14.4,
    "egress_gb_per_hour": 6.5,
    "monthly_volume_tb": 0.13
  },
  {
    "label": "8 people",
    "sfu_egress_mbps": 67.2,
    "egress_gb_per_hour": 30.2,
    "monthly_volume_tb": 0.6
  },
  {
    "label": "15 people",
    "sfu_egress_mbps": 252,
    "egress_gb_per_hour": 113.4,
    "monthly_volume_tb": 2.3
  },
  {
    "label": "30 people",
    "sfu_egress_mbps": "1,044",
    "egress_gb_per_hour": 469.8,
    "monthly_volume_tb": 9.4
  },
  {
    "label": "50 people",
    "sfu_egress_mbps": "2,940",
    "egress_gb_per_hour": "1,323",
    "monthly_volume_tb": 26.5
  }
]

این ردیف‌ها محاسبات ریاضی هستند، نه اندازه‌گیری یک سرور خاص. ستون ماهانه فرض را بر بیست ساعت تماس در ماه گذاشته است. ابتدا ردیف آخر را بخوانید. پنجاه نفر با دوربین روشن به 2,940 Mbps ترافیک خروجی پایدار از یک ماشین نیاز دارند. سی نفر به 1,044 Mbps نیاز دارند. چهار نفر به 14.4 Mbps نیاز دارند که هر VPS بدون هیچ مشکلی از پس آن برمی‌آید. بین ردیف چهار نفره و سی نفره، تعداد افراد هفت و نیم برابر می‌شود، در حالی که ترافیک خروجی بیش از هفتاد برابر افزایش می‌یابد.

پیاده‌سازی‌های واقعی کمتر از این اعداد هستند و دانستن دلیل آن اهمیت دارد. Jitsi و LiveKit هر دو از simulcast استفاده می‌کنند: فرستنده چندین لایه کیفیتی را همزمان منتشر می‌کند و SFU لایه پایین‌تر را برای کسانی که در صفحه نیستند، ارسال می‌کند. Jitsi همچنین تنظیماتی به نام last-N دارد که ویدیو را فقط برای آخرین سخنرانان ارسال می‌کند. هر دو روش ترافیک زیادی را صرفه‌جویی می‌کنند. هیچ‌کدام شکل منحنی رشد را تغییر نمی‌دهند و هر دو به محض اینکه همه دوربین خود را روشن کنند و تصویر یکدیگر را پین کنند، کارایی خود را از دست می‌دهند.

پهنای باند آپلینک VPS واقعاً چه چیزی در اختیار شما می‌گذارد؟

در صفحهٔ مشخصات پلن‌ها، عبارت "1 Gbps port" ذکر می‌شود. این عدد، سرعت کارت شبکهٔ مجازی است و تضمینی برای سرعت گام بعدی (next hop) نیست. این لینک با سایر مستأجران روی همان میزبان فیزیکی مشترک است؛ بنابراین، نرخ انتقال دادهٔ پایدار در ساعات شلوغی، کمتر از سرعت پورت خواهد بود و یک تماس کنفرانسی دقیقاً یک بارِ کاری پایدار محسوب می‌شود. اکثر پلن‌ها همچنین دارای سقف انتقال دادهٔ ماهانه هستند که پس از اتمام آن، سرعت شما محدود (throttle) شده یا مشمول هزینهٔ اضافی می‌شوید.

آن سقف انتقال داده همان جایی است که هزینه‌های غیرمنتظره در صورت‌حساب ظاهر می‌شوند. بیست ساعت تماس 30 نفره در یک ماه، 9.4 ترابایت داده را با نرخ 469.8 گیگابایت در ساعت از سرور خارج می‌کند. بیست ساعت تماس 50 نفره، 26.5 ترابایت داده جابه‌جا می‌کند. پیش از بررسی میزان RAM، سقف انتقال داده را چک کنید؛ اگر صفحهٔ پلن در این مورد مبهم است، همین ابهام پاسخ شماست. خواندن صحیح پیشنهادهای VPS ارزان برای این نوع بار کاری، بیش از هر کار دیگری اهمیت دارد.

Jitsi Meet: گزینه پیش‌فرض و نیازمندی‌های آن

Jitsi Meet گزینه‌ای است که اکثر افراد باید کار خود را با آن شروع کنند. این سرویس از مخزن Debian خود پروژه نصب می‌شود، در حین نصب Nginx و گواهی‌نامه را پیکربندی می‌کند و videobridge (JVB) آن تنها از یک پورت UDP استفاده می‌کند که باعث می‌شود قوانین فایروال ساده و کوتاه باقی بمانند. این سرویس به Debian 11 یا جدیدتر، یا Ubuntu 22.04 یا جدیدتر نیاز دارد.

sudo apt update
sudo apt install -y apt-transport-https curl gnupg
sudo add-apt-repository universe
sudo apt update
sudo curl -sL https://prosody.im/files/prosody-debian-packages.key -o /usr/share/keyrings/prosody-debian-packages.key
echo "deb [signed-by=/usr/share/keyrings/prosody-debian-packages.key] http://packages.prosody.im/debian $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/prosody-debian-packages.list
sudo apt install -y lua5.2
curl -sL https://download.jitsi.org/jitsi-key.gpg.key | sudo sh -c 'gpg --dearmor > /usr/share/keyrings/jitsi-keyring.gpg'
echo "deb [signed-by=/usr/share/keyrings/jitsi-keyring.gpg] https://download.jitsi.org stable/" | sudo tee /etc/apt/sources.list.d/jitsi-stable.list
sudo apt update
sudo apt install -y jitsi-meet

نصب‌کننده از شما یک hostname می‌خواهد و سپس گزینه‌ای برای انتخاب گواهی‌نامه ارائه می‌دهد. گزینه Let's Encrypt را انتخاب کنید و نام دامنه‌ای را بدهید که از قبل به آدرس عمومی این سرور اشاره می‌کند. گواهی‌نامه از طریق چالش HTTP صادر می‌شود، بنابراین اگر نام دامنه به جای دیگری اشاره کند، این مرحله با شکست مواجه خواهد شد.

سپس پورت‌ها را باز کنید. این‌ها پورت‌هایی هستند که در کتابچه راهنما مستند شده‌اند؛ ابتدا SSH را باز کنید تا ufw enable باعث قفل شدن دسترسی شما نشود:

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 10000/udp
sudo ufw allow 3478/udp
sudo ufw allow 5349/tcp
sudo ufw enable

پورت‌های TCP 80 و 443 برای سرویس‌دهی به برنامه وب و تمدید گواهی‌نامه استفاده می‌شوند. پورت UDP 10000 تمام ترافیک صوتی و تصویری را منتقل می‌کند و همان پورتی است که معمولاً فراموش می‌شود. پورت‌های UDP 3478 و TCP 5349 متعلق به سرور coturn هستند که بسته Jitsi در کنار bridge نصب می‌کند؛ این پورت‌ها مسیر جایگزین برای کسانی هستند که شبکه آن‌ها ترافیک UDP را مسدود کرده است.

sudo systemctl status jitsi-videobridge2
sudo ss -ulnp | grep 10000

دستور اول باید وضعیت سرویس را به عنوان active گزارش دهد. دستور دوم باید نشان دهد که bridge روی پورت UDP 10000 در حال گوش دادن است. اگر خروجی خالی بود، یعنی bridge اجرا نشده است و /var/log/jitsi/jvb.log دلیل آن را بیان خواهد کرد.

برای تعیین ابعاد سرور، Jitsi در کتابچه راهنمای خود مقادیر پیشنهادی اولیه را منتشر کرده است و BigBlueButton مقادیر بسیار بزرگ‌تری را پیشنهاد می‌دهد:

ChartSizing each project publishes for one production server
The data behind this chart
[
  {
    "label": "Jitsi Meet",
    "ram_gb": 8,
    "cpu_cores": 4,
    "uplink_mbps": "1,000"
  },
  {
    "label": "BigBlueButton 3.0",
    "ram_gb": 16,
    "cpu_cores": 8,
    "uplink_mbps": 250
  }
]

کتابچه راهنمای Jitsi برای یک سرور جدی، 8 گیگابایت رم و 4 هسته پردازنده اختصاصی پیشنهاد می‌دهد و اشاره می‌کند که پهنای باند 1,000 مگابیت بر ثانیه اغلب کافی است؛ همچنین ذکر شده که تنظیمات کوچک‌تر روی 4 یا 2 گیگابایت رم نیز اجرا می‌شوند. یک نکته در آن صفحه ارزش به خاطر سپردن دارد: Prosody، سرور XMPP که مدیریت سیگنالینگ را بر عهده دارد، تنها می‌تواند از یک هسته استفاده کند. هسته‌های اضافی به bridge کمک می‌کنند اما تأثیری بر سیگنالینگ ندارند.

چرا همه به تماس ملحق می‌شوند اما کسی ویدیو را نمی‌بیند؟

این یک خطای استاندارد Jitsi روی VPS است. لیست شرکت‌کنندگان پر می‌شود، چت کار می‌کند و تمام کاشی‌های ویدیو سیاه می‌مانند. videobridge آدرس‌هایی را که روی رابط‌های شبکه خود پیدا می‌کند، تبلیغ می‌کند. در سرویس‌دهنده‌ای که به ماشین مجازی یک آدرس خصوصی می‌دهد و یک آدرس عمومی را روی آن نگاشت (map) می‌کند، تنها آدرسی که JVB پیدا می‌کند همان آدرس خصوصی است؛ بنابراین هر کلاینت سعی می‌کند رسانه را به مقصدی مانند 10.0.0.5 بفرستد و بسته‌ها به هیچ‌جا نمی‌رسند.

هر دو آدرس را به bridge معرفی کنید. یک نگاشت ایستا (static mapping) به /etc/jitsi/videobridge/jvb.conf اضافه کنید:

ice4j {
  harvest {
    mapping {
      static-mappings = [
        {
          local-address = "10.0.0.5"
          public-address = "203.0.113.10"
        }
      ]
    }
  }
}

سرویس را با sudo systemctl restart jitsi-videobridge2 بازنشانی کنید. آدرس محلی را از ip -4 addr show و آدرس عمومی را از پنل مدیریت سرویس‌دهنده خود بردارید. راهنماهای قدیمی همین تنظیمات را در /etc/jitsi/videobridge/sip-communicator.properties با کلیدهای org.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS و org.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS انجام می‌دادند. آن روش‌ها هنوز کار می‌کنند، اما نصب‌های جدید باید از بلوک نگاشت بالا استفاده کنند.

دلیل دیگر، فایروالی است که پیکربندی نکرده‌اید. اکثر سرویس‌دهنده‌ها یک فایروال شبکه در پنل مدیریت دارند که از ufw روی سیستم‌عامل جداست و پورت UDP 10000 باید در هر دو باز باشد. برای اینکه بفهمید کدام لایه بسته‌ها را مسدود می‌کند، در حالی که شخصی از بیرون به تماس ملحق می‌شود، sudo tcpdump -ni any udp port 10000 را روی سرور اجرا کنید. اگر هیچ بسته‌ای دریافت نشد، یعنی چیزی به ماشین نمی‌رسد و مسدودسازی در لایه‌ای بالاتر از سیستم‌عامل رخ می‌دهد. اگر بسته‌ها می‌رسند اما کاشی‌ها سیاه باقی می‌مانند، یعنی bridge با آدرسی پاسخ می‌دهد که کلاینت به آن دسترسی ندارد و مشکل از نگاشت است. اگر در مورد خود ufw مطمئن نیستید، قوانین ufw که یک VPS واقعاً به آن نیاز دارد، ترتیب قوانینی را که باعث سردرگمی کاربران می‌شود، پوشش می‌دهد.

BigBlueButton: سنگین، دارای ساختار تحمیلی و نیازمند کل سرور

BigBlueButton برای آموزش طراحی شده است. این نرم‌افزار دارای تخته‌سفید، اتاق‌های مجزا (breakout rooms)، نظرسنجی و بخش ارائه است و خط‌لوله ضبط آن یک ویژگی درجه‌یک محسوب می‌شود، نه یک افزونه. این گزینه همچنین با اختلاف زیاد سنگین‌ترین گزینه در این فهرست است و بسته‌ای نیست که بتوانید به یک سرور موجود اضافه کنید.

از اوت 2026، مسیر پشتیبانی‌شده، BigBlueButton 3.0 روی Ubuntu 22.04 است که با فلگ نسخه jammy-300 انتخاب می‌شود. الزامات تولید اعلام‌شده توسط پروژه عبارتند از 16 گیگابایت حافظه با فعال بودن swap، 8 هسته CPU با عملکرد تک‌رشته‌ای بالا، 250 مگابیت بر ثانیه پهنای باند متقارن، و 500 گیگابایت دیسک در صورت نگهداری ضبط‌ها (50 گیگابایت در صورت غیرفعال کردن آن‌ها). پورت‌های مورد نیاز TCP 80 و 443، به علاوه محدوده UDP از 16384 تا 32768 هستند.

wget -q https://raw.githubusercontent.com/bigbluebutton/bbb-install/v3.0.x-release/bbb-install.sh
less bbb-install.sh
bash bbb-install.sh -w -v jammy-300 -s bbb.example.com -e info@example.com -g

نمونه‌های خود پروژه، اسکریپت را مستقیماً به bash پایپ می‌کنند. ابتدا آن را دانلود و مطالعه کنید، زیرا پیکربندی nginx شما را بازنویسی می‌کند، پشته رسانه و صوتی اختصاصی خود را نصب می‌کند، نسخه‌های بسته را پین می‌کند و نام میزبان (hostname) را تصاحب می‌کند. این یک نقص نیست، بلکه بخشی از طراحی است: BigBlueButton انتظار دارد مالک کل ماشین باشد. فلگ -w فایروال را پیکربندی می‌کند، -s نام میزبان است، -e آدرسی است که Let's Encrypt ثبت می‌کند و -g رابط کاربری Greenlight را اضافه می‌کند. اگر همان سرور وظیفه TLS termination برای سرویس‌های دیگر را نیز بر عهده دارد، یا BigBlueButton را به جای دیگری منتقل کنید یا پیش از آنکه اسکریپت پیکربندی nginx شما را ویرایش کند، مطمئن شوید که عملکرد پیکربندی reverse proxy خود را کاملاً درک کرده‌اید.

دو ردیف موجود در آن جدول را به‌دقت مقایسه کنید. BigBlueButton دو برابر حافظه و دو برابر هسته پیشنهادی Jitsi را درخواست می‌کند، در حالی که یک‌چهارم پهنای باند آن را نیاز دارد. این دو رقم به روش یکسانی اندازه‌گیری نشده‌اند و فرض‌های متفاوتی برای اندازه اتاق‌ها دارند؛ بنابراین هر کدام را به عنوان نقطه شروع پروژه مربوط به خودش در نظر بگیرید، نه یک مقایسه مستقیم و یک‌به‌یک. شکاف CPU واقعی است و ناشی از تمام کارهایی است که BigBlueButton علاوه بر انتقال ویدیو انجام می‌دهد.

Galène: گزینه سبک

Galène یک SFU فشرده است که با زبان Go نوشته شده است. این برنامه به یک فایل اجرایی واحد و ایستا (static binary) کامپایل می‌شود، کلاینت وب اختصاصی خود را دارد و شامل یک سرور TURN است؛ بنابراین نیازی به سرور XMPP، محیط اجرای Java یا اپلیکیشن Rails برای نگهداری نیست. اگر نیاز شما یک تماس قابل‌اطمینان 10 نفره روی یک سرور معمولی است، پیش از آنکه نتیجه بگیرید به سخت‌افزار قوی‌تری نیاز دارید، این گزینه را امتحان کنید.

sudo apt update && sudo apt install -y git golang-go
git clone https://github.com/jech/galene
cd galene
CGO_ENABLED=0 go build -ldflags='-s -w'
mkdir groups

بسته golang-go در Ubuntu 24.04 شامل Go 1.22 است. اگر go build اعلام کرد که ماژول به نسخه جدیدتری از Go نیاز دارد، به‌جای درگیری با بسته توزیع، یک toolchain به‌روز را از go.dev نصب کنید.

در ادبیات Galène، یک group همان اتاق است و هر group یک فایل JSON است:

echo '{"users": {"vimes": {"password":"sybil", "permissions":"op"}}}' > groups/night-watch.json
./galene &

فایل https://your.server:8443/group/night-watch/ را باز کرده و با نام کاربری vimes وارد شوید. این اعتبارنامه‌ها مستقیماً از فایل README پروژه آمده‌اند، بنابراین پیش از آنکه پورت از هر جای دیگری در دسترس قرار گیرد، آن‌ها را تغییر دهید. برای یک استقرار واقعی، پروژه یک unit برای systemd ارائه می‌دهد:

[Unit]
Description=Galene
After=network.target

[Service]
Type=simple
WorkingDirectory=/home/galene
User=galene
Group=galene
ExecStart=/home/galene/galene
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

پورت‌های مورد نیاز عبارتند از TCP 8443 برای رابط وب، TCP و UDP 1194 برای سرور داخلی TURN، و بازه‌ای از پورت‌های UDP بالا برای رسانه. این بازه را ثابت (pin) کنید تا بتوانید یک قانون فایروال واحد برای آن بنویسید:

./galene -udp-range 40000-40100

گزینه -turn همان موردی است که روی VPS اهمیت دارد. -turn ':1194' روی تمام آدرس‌های عمومی IPv4 گوش می‌دهد. -turn '203.0.113.1:1194' آدرسی را که کلاینت‌ها واقعاً می‌بینند به Galène اعلام می‌کند؛ این دقیقاً همان چیزی است که وقتی آدرس خودِ ماشین خصوصی (private) است، به آن نیاز دارید. -turn '' سرور داخلی را غیرفعال می‌کند تا بتوانید از طریق data/ice-servers.json به یک سرور خارجی اشاره کنید. مقدار پیش‌فرض auto است که در صورت عدم وجود ice-servers.json، مشابه :1194 عمل می‌کند.

شما می‌توانید با تنظیم proxyURL در data/config.json و پروکسی کردن مسیر /ws به همراه هدرهای ارتقای WebSocket، از nginx در مقابل رابط وب استفاده کنید. توجه داشته باشید که این کار چه چیزی را پوشش می‌دهد: کلاینت‌ها همچنان جریان‌های مستقیم UDP و اتصالات مستقیم TCP به پورت TURN برقرار می‌کنند، بنابراین reverse proxy فقط صفحه و سیگنالینگ را مدیریت می‌کند. رسانه هرگز از آن عبور نمی‌کند.

مستندات Galène بیان می‌کند که به منابع سرور بسیار کمی نیاز دارد و عدد مشخصی را منتشر نمی‌کند، بنابراین انتظار عدد خاصی را نداشته باشید. محاسبات پهنای باند ذکر شده در بالا همچنان به‌طور کامل معتبر است. آنچه در اینجا صرفه‌جویی می‌کنید، حافظه و پیچیدگی‌های مربوط به تمام اجزایی است که SFU نیستند.

Owncast: یک به چند، جایی که پهنای باند خطی باقی می‌ماند

بسیاری از نیازهای «ویدیو کنفرانس» در واقع یک نفر است که برای مخاطبانی که در چت تایپ می‌کنند، ارائه می‌دهد. اگر نیاز شما این است، SFU ابزار اشتباهی است و صرفهٔ اقتصادی آن کاملاً متفاوت خواهد بود. Owncast یک استریم RTMP از OBS یا انکودرهای مشابه دریافت کرده و آن را از طریق HTTPS معمولی به صورت HLS ارائه می‌دهد. پهنای باند به ازای هر بیننده به جای حالت درجه دوم، خطی است و از آنجا که خروجی شامل سگمنت‌های HTTP ساده است، می‌توانید آن را به پشت یک Object Storage یا CDN منتقل کنید و هزینه‌های آن را روی سرور مبدأ حذف کنید.

curl -sL https://owncast.online/install.sh -o install-owncast.sh
less install-owncast.sh
bash install-owncast.sh

مستندات این پروژه توصیه می‌کند که آن را با کاربر root اجرا نکنید و هر اسکریپت راه دور را پیش از اجرا بررسی کنید؛ به همین دلیل دانلود در مرحلهٔ جداگانه‌ای در بالا قرار گرفته است. نصب‌کننده، نسخهٔ فعلی (release) و یک باینری ffmpeg را در صورتی که از قبل نداشته باشید، دریافت می‌کند. دستور ./owncast را از دایرکتوری نصب اجرا کنید و پنل مدیریت را در /admin روی پورت 8080 باز کنید. نام کاربری پیش‌فرض admin و رمز عبور پیش‌فرض همان stream key یعنی abc123 است. پیش از آنکه دامنه‌ای را به سرور متصل کنید، این موارد را تغییر دهید.

دو پیامد از طراحی HLS ناشی می‌شود. بینندگان چند ثانیه یا چند دقیقه از پخش زنده عقب‌تر هستند، زیرا HLS سگمنت‌های کامل را ارسال می‌کند و بنابراین هیچ گفتگوی دوطرفه‌ای وجود ندارد. همچنین هیچ UDP و هیچ TURN در مسیر وجود ندارد، بنابراین به شبکه‌هایی می‌رسد که یک تماس WebRTC اصلاً نمی‌تواند در آن‌ها متصل شود.

Owncast همچنین تنها ابزاری است که در اینجا به‌طور هدفمند عمل transcoding را انجام می‌دهد. هر کیفیت خروجی که فعال کنید، یک انکود ffmpeg دیگر از استریم ورودی است که به اندازهٔ طول پخش اجرا می‌شود. روی یک VPS کوچک، یک یا دو کیفیت ارائه دهید. پنج کیفیت، CPU را اشباع می‌کند در حالی که شبکه بیکار می‌ماند.

راه‌اندازی Element Call روی سرور Matrix موجود

اگر در حال حاضر از Matrix استفاده می‌کنید، قابلیت ویدیو یک افزونه محسوب می‌شود و نه محصولی جداگانه که نیاز به مدیریت مستقل داشته باشد. با این حال، این قابلیت بیش از یک بسته نرم‌افزاری است. Element Call در پشت homeserver شما به دو جزء نیاز دارد. اولی یک LiveKit SFU است که وظیفه انتقال رسانه را بر عهده دارد. دومی سرویس احراز هویت MatrixRTC با نام element-hq/lk-jwt-service است که URL مربوط به WebSocket سرویس LiveKit و یک توکن JWT (JSON web token) امضاشده را برای اتصال در اختیار کلاینت قرار می‌دهد. این سرویس از API فدراسیون Matrix استفاده می‌کند، بنابراین به یک reverse proxy با قابلیت TLS در مقابل خود و یک نام دامنه که از طریق فدراسیون قابل دسترسی باشد، نیاز دارد.

پورت‌های مستندشده برای LiveKit عبارتند از:

  • پورت TCP 7880 برای API و WebSocket کلاینت، که باید پشت پروکسی با قابلیت TLS termination قرار گیرد
  • پورت TCP 7881 برای ICE over TCP، که زمانی استفاده می‌شود که کلاینت امکان خروج از طریق UDP را نداشته باشد
  • پورت‌های UDP 50000 تا 60000 برای رسانه، که در آن هر شرکت‌کننده در اتاق از دو پورت استفاده می‌کند
  • پورت‌های UDP 3478 و TCP 5349 در صورتی که سرور TURN داخلی را فعال کنید؛ پورت 5349 باید به 443 منتقل شود، مگر اینکه یک load balancer در مقابل آن قرار داشته باشد

استفاده از دو پورت برای هر شرکت‌کننده ممکن است نگران‌کننده به نظر برسد، اما در واقع این‌طور نیست. یک بازه 10000 پورتی برای هزاران شرکت‌کننده کافی است و پهنای باند آپلینک شما بسیار زودتر از اتمام این بازه اشباع خواهد شد. در هر صورت، کل این بازه را باز کنید، زیرا باز بودن ناقص این بازه باعث می‌شود اتصال برای برخی کاربران برقرار و برای برخی دیگر قطع شود؛ این بدترین نوع خطا برای عیب‌یابی است. بخش مربوط به homeserver در این سناریو، وظیفه‌ای مجزا است که در اجرای Synapse homeserver روی یک VPS به آن پرداخته شده است.

چرا یک نفر هرگز نمی‌تواند متصل شود؟ TURN و شبکه‌هایی که UDP را مسدود می‌کنند

ابتدا چند واژه که هر کدام یک‌بار استفاده می‌شوند. ICE (مخفف interactive connectivity establishment) فرآیندی است که دو نقطه پایانی WebRTC برای یافتن یک مسیر کاری بین خود استفاده می‌کنند. STUN (مخفف session traversal utilities for NAT) سرویس کوچکی است که به کلاینت می‌گوید آدرس عمومی‌اش از بیرون چگونه دیده می‌شود. TURN (مخفف traversal using relays around NAT) یک رله است: وقتی مسیر مستقیمی وجود ندارد، هر دو طرف رسانه خود را به سرور TURN می‌فرستند و آن سرور عملیات ارسال را انجام می‌دهد.

شما برای شرکت‌کنندگانی که شبکه‌شان برای شما قابل مشاهده نیست، به TURN نیاز دارید. یکی از آن‌ها ممکن است در شبکه شرکتی یا دانشگاهی باشد که خروجی UDP در آن کاملاً مسدود است. دیگری پشت یک NAT در سطح حامل (carrier-grade NAT) قرار دارد که برای هر مقصد یک پورت مبدأ متفاوت اختصاص می‌دهد؛ این حالت symmetric NAT نامیده می‌شود و باعث می‌شود آدرسی که STUN گزارش کرده، بی‌فایده باشد.

نشانه این مشکل خاص است. اکثر افراد متصل می‌شوند و همه چیز کار می‌کند. یک نفر لیست شرکت‌کنندگان و چت را می‌بیند، اما یک کاشی سیاه و یک آیکون بارگذاری (spinner) مشاهده می‌کند. مرورگر آن‌ها کاندیداها را جمع‌آوری کرده، هیچ‌کدام از جفت‌ها کار نکرده و ICE در وضعیت شکست (failed) پایان یافته است. در Chrome، باز کردن chrome://webrtc-internals در حین تلاش برای اتصال، جفت‌های کاندیدا و آن شکست را نشان می‌دهد. از آن شخص بخواهید با گوشی و از طریق اینترنت موبایل دوباره تلاش کند. اگر آنجا کار کرد، شبکه او علت مشکل است و TURN راه حل آن.

استفاده از TURN روی پروتکل TCP و پورت 443 یا 5349، راهکار جایگزینی است که تقریباً همه‌جا کار می‌کند، زیرا شبکه‌ای که TLS روی پورت 443 را مسدود کند، در واقع وب را مسدود کرده است. بسته Jitsi نرم‌افزار coturn را برای شما نصب و پیکربندی می‌کند، و دقیقاً به همین دلیل است که قوانین فایروال مستند آن شامل UDP 3478 و TCP 5349 می‌شود. Galène دارای TURN داخلی روی پورت 1194 است. LiveKit یک سرور TURN تعبیه شده دارد که در تنظیمات آن را فعال می‌کنید. اگر خودتان coturn را اجرا می‌کنید:

sudo apt install -y coturn
sudo systemctl enable --now coturn
listening-port=3478
tls-listening-port=5349
fingerprint
use-auth-secret
static-auth-secret=REPLACE_WITH_A_LONG_RANDOM_STRING
realm=turn.example.com
cert=/etc/letsencrypt/live/turn.example.com/fullchain.pem
pkey=/etc/letsencrypt/live/turn.example.com/privkey.pem
min-port=49152
max-port=65535
no-multicast-peers

در Debian و Ubuntu، سرویس بسته‌بندی شده تا زمانی که TURNSERVER_ENABLED=1 را در /etc/default/coturn تنظیم نکنید، شروع به کار نخواهد کرد. یک coturn که نصب شده اما فعال نشده باشد، از بیرون دقیقاً مشابه حالتی است که اصلاً TURN وجود ندارد؛ به همین دلیل است که همین یک خط تنظیمات، باعث هدر رفتن کل شب‌های کاربران می‌شود.

حالا هزینه‌ای که هیچ‌کس درباره آن نمی‌نویسد. یک رله، تمام رسانه هر شرکت‌کننده رله‌شده را در هر دو جهت حمل می‌کند. وقتی coturn روی همان سروری باشد که SFU قرار دارد، بیشتر این ترافیک از طریق loopback عبور می‌کند و به جای پهنای باند آپلینک، از CPU شما هزینه می‌گیرد، و شنونده TLS هر بسته را برای بار دوم، علاوه بر DTLS که رسانه از قبل حمل می‌کند، رمزگذاری می‌کند. وقتی TURN را به ماشین اختصاصی خودش منتقل می‌کنید، آن ماشین به برنامه پهنای باند مخصوص خود نیاز دارد که مشابه SFU اندازه‌گیری شده باشد. همچنین، TURN روی TCP رسانه بلادرنگ را به یک جریان قابل‌اطمینان تبدیل می‌کند، بنابراین یک بسته گم‌شده به جای نادیده گرفته شدن، دوباره ارسال می‌شود و شرکت‌کننده‌ای که از طریق رله و روی یک لینک با افت کیفیت متصل است، به جای یک اختلال کوتاه، دچار تأخیر انباشته می‌شود. رله یک راهکار جایگزین برای برقراری اتصال است، با کیفیتی که مسیر مستقیم قطعاً بهتر از آن عمل می‌کرد.

SFU چه زمانی عملیات transcode را انجام می‌دهد و هزینه آن چقدر است؟

یک SFU بسته‌ها را فقط فوروارد می‌کند و هرگز ویدیو را decode نمی‌کند؛ به همین دلیل است که 4 هسته پردازشی می‌توانند اتاقی را مدیریت کنند که روی کاغذ غیرممکن به نظر می‌رسد. دو قابلیت این ویژگی را نقض می‌کنند و هر دو، کاربرانی را که آن‌ها را از طریق یک چک‌باکس فعال کرده‌اند، غافلگیر می‌کنند.

اولین مورد، ضبط (Recording) است. Jitsi با استفاده از Jibri ضبط را انجام می‌دهد و مستندات خود Jibri دقیقاً توضیح می‌دهد که چه کاری انجام می‌دهد: این ابزار یک نمونه از Chrome را در یک framebuffer مجازی اجرا کرده و خروجی را با ffmpeg ضبط و encode می‌کند. این یعنی یک مرورگر کامل که تمام جلسه شما را رندر می‌کند، به اضافه یک انکودر ویدیویی که در تمام طول تماس به‌طور مداوم در حال اجراست. همان مستندات بیان می‌کنند که در هر لحظه فقط یک ضبط روی یک Jibri پشتیبانی می‌شود و Jibri باید روی یک ماشین یا ماشین مجازی جداگانه اجرا شود که هیچ برنامه دیگری از نمایشگر یا دستگاه‌های صوتی آن استفاده نمی‌کند. ضبط کردن، یک سرور دوم است، نه فقط یک چک‌باکس.

دومین مورد، تماس تلفنی (Dial-in) است. پل زدن یک خط تلفن به داخل کنفرانس به معنای تبدیل Opus با نرخ 48 kHz به فرمتی است که شبکه تلفن می‌پذیرد (معمولاً G.711 با نرخ 8 kHz)؛ این کار در هر دو جهت و به‌طور مداوم در تمام طول تماس انجام می‌شود. transcoding صوتی بسیار ارزان‌تر از transcoding ویدیویی است، اما برای هر شاخه از تماس اجرا می‌شود و هرگز متوقف نمی‌شود، بنابراین هزینه آن با تعداد تماس‌گیرندگان افزایش می‌یابد. اگر به یک شماره تماس نیاز دارید، یک سرور VoIP خودمیزبان (self-hosted) مؤلفه‌ای است که این کار را انجام می‌دهد و به همان دلیلی که برای Jibri ذکر شد، باید روی سخت‌افزار اختصاصی خود اجرا شود.

واقعاً به چه ابعادی از سرور نیاز دارید؟

برای دو نفر، تقریباً به هیچ منبع خاصی نیاز نیست. Jitsi به‌صورت پیش‌فرض در حالتی که دقیقاً دو شرکت‌کننده وجود داشته باشد، حالت peer to peer را فعال می‌کند. در این حالت، کنفرانس ارسال داده از طریق videobridge را متوقف کرده و از اتصال مستقیم استفاده می‌کند. با پیوستن نفر سوم، سیستم دوباره به حالت bridge برمی‌گردد. بنابراین، یک VPS با 1 GB رم برای تماس‌های یک‌به‌یک عالی است، اما برای چهار نفر ضعیف عمل می‌کند؛ به همین دلیل است که گزارش «هنگام تست کار می‌کرد» بسیار رایج است.

برای حداکثر ده نفر با دوربین روشن، 67.2 Mbps برای هشت شرکت‌کننده در محدوده توانایی uplink یک VPS معمولی قرار دارد. دو هسته مجازی CPU و 4 GB رم برای اجرای Jitsi یا Galène در این مقیاس کافی است، به شرطی که در حال ضبط نباشید. به‌جای نمودار CPU، شمارنده ترافیک شبکه را زیر نظر بگیرید.

برای سی نفر، بدترین حالت 1,044 Mbps ترافیک پایدار است و بیست ساعت از آن معادل 9.4 TB خواهد بود. در این مقیاس، پیش از قیمت‌گذاری سرور، باید هزینه پهنای باند را محاسبه کنید. قابلیت last-N را فعال کنید تا bridge فقط داده‌های سخنرانان اخیر را ارسال کند، حالت پیش‌فرض دوربین برای شرکت‌کنندگان را خاموش بگذارید و SFU را در جایی میزبانی کنید که سقف انتقال داده آن با محاسبات شما همخوانی داشته باشد.

فراتر از این تعداد، استفاده از یک VPS انتخاب اشتباهی است. یا رویداد شما در واقع یک پخش زنده (broadcast) است که در آن صورت استفاده از Owncast به همراه یک CDN کسری از این هزینه را خواهد داشت، یا نیاز دارید که بیش از یک videobridge را پشت یک لایه signalling واحد قرار دهید که پروژه‌ای متفاوت از چیزی است که آغاز کرده‌اید.

یک نکته نهایی درباره مسیریابی: اکثر تیم‌ها در طول روز به چت بسیار بیشتر از ویدیو نیاز دارند و میزبانی چت ارزان است و پایداری آن آسان است. راه‌اندازی یک جایگزین Slack خودمیزبان برای ترافیک روزمره و نگهداری سرور کنفرانس فقط برای تماس‌های برنامه‌ریزی‌شده، چیدمانی است که با بودجه محدود یک VPS سازگاری دارد.

FAQ

چرا افراد می‌توانند به جلسه Jitsi من ملحق شوند اما یکدیگر را نمی‌بینند یا نمی‌شنوند؟

چت و لیست شرکت‌کنندگان از طریق کانال سیگنالینگ منتقل می‌شوند که از پروتکل TCP روی پورت 443 استفاده می‌کند، در حالی که صدا و تصویر از طریق UDP روی پورت 10000 به videobridge ارسال می‌شوند. اگر لیست شرکت‌کنندگان پر شود اما تصویر همه سیاه بماند، مسیر رسانه (media path) قطع است در حالی که مسیر سیگنالینگ مشکلی ندارد. پورت UDP 10000 را در هر دو فایروال بررسی کنید: فایروال روی سرور و فایروال شبکه در پنل مدیریت ارائه‌دهنده سرویس. سپس بررسی کنید که bridge آدرس عمومی خود را می‌شناسد یا خیر؛ در ماشین‌های مجازی که آدرس خصوصی دارند و به یک آدرس عمومی نگاشت شده‌اند، یک static mapping در بخش ice4j.harvest.mapping در فایل /etc/jitsi/videobridge/jvb.conf اضافه کنید و jitsi-videobridge2 را restart کنید. اجرای دستور sudo tcpdump -ni any udp port 10000 هنگام ملحق شدن یک نفر به شما نشان می‌دهد مشکل از کدام بخش است، زیرا اگر هیچ بسته‌ای دریافت نشود، یعنی مسدودسازی در لایه‌ای بالاتر از سیستم‌عامل رخ داده است.

یک تماس ویدیویی 30 نفره چقدر پهنای باند مصرف می‌کند؟

در بدترین حالت، یعنی زمانی که دوربین همه روشن است و SFU یک لایه با کیفیت کامل را برای همه ارسال می‌کند، حدود 1,044 مگابیت بر ثانیه از سرور خارج می‌شود که معادل 469.8 گیگابایت در ساعت است. این یک محاسبه ریاضی از N ضرب‌در (N منهای 1) استریم با نرخ 1.2 مگابیت بر ثانیه برای هر کدام است و نه لزوماً اندازه‌گیری دقیق تنظیمات شما. قابلیت‌های Simulcast و تنظیم last-N در استفاده معمول، این مقدار را به‌شدت کاهش می‌دهند، زیرا در هر لحظه اکثر شرکت‌کنندگان روی صفحه نمایش دیده نمی‌شوند. با این حال، ظرفیت سرور را برای حالتی نزدیک به بدترین وضعیت در نظر بگیرید، چرا که بدترین حالت همان جلسات عمومی است که همه هم‌زمان دوربین خود را روشن می‌کنند.

آیا می‌توانم Jitsi Meet را روی یک VPS با 1 گیگابایت رم اجرا کنم؟

نصب می‌شود و تماس دو نفره کار خواهد کرد، بخشی به این دلیل که Jitsi برای دقیقاً دو شرکت‌کننده از حالت peer to peer استفاده می‌کند و videobridge را کاملاً دور می‌زند. این سرور برای تماس‌های گروهی مناسب نیست. Prosody، videobridge و Java runtime همگی به حافظه نیاز دارند؛ پیشنهاد خودِ راهنمای رسمی برای یک استقرار جدی 8 گیگابایت رم است و محدودیت پهنای باند پیش از محدودیت حافظه خود را نشان خواهد داد. اگر تنها یک سرور 1 گیگابایتی در اختیار دارید، Galène گزینه مناسب‌تری نسبت به Jitsi برای این اندازه است.

آیا اگر VPS من دارای IP عمومی است، همچنان به سرور TURN نیاز دارم؟

بله. مشکلی که TURN حل می‌کند در سمت دیگر تماس قرار دارد. شرکت‌کننده‌ای که در یک شبکه شرکتی است که خروجی UDP را مسدود می‌کند، یا پشت یک NAT در سطح اپراتور (carrier-grade NAT) قرار دارد که برای هر مقصد یک پورت منبع متفاوت اختصاص می‌دهد، نمی‌تواند مسیر مستقیم رسانه ایجاد کند، فارغ از اینکه آدرس سرور شما چقدر عمومی باشد. TURN روی پروتکل TCP و پورت‌های 443 یا 5349 به آن‌ها یک relay می‌دهد که برای فایروال آن‌ها شبیه ترافیک عادی وب به نظر می‌رسد. نصب بسته‌ای Jitsi به‌صورت پیش‌فرض coturn را برای این منظور تنظیم می‌کند، به همین دلیل است که قوانین فایروال مستند شده برای آن، پورت‌های UDP 3478 و TCP 5349 را باز می‌گذارند.

چرا BigBlueButton به سخت‌افزار بسیار بیشتری نسبت به Jitsi Meet نیاز دارد؟

زیرا کارهای بسیار بیشتری از صرفاً ارسال ویدیو انجام می‌دهد. نیازهای منتشرشده برای تولید آن 16 گیگابایت رم و 8 هسته پردازنده است، در حالی که این مقادیر در راهنمای Jitsi برابر با 8 گیگابایت رم و 4 هسته است. BigBlueButton یک پشته کامل کنفرانس صوتی، تخته‌سفید اشتراکی و لایه ارائه، خط لوله ضبط و پردازش پس از آن، و یک رابط وب با حساب‌های کاربری را همگی روی یک ماشین اجرا می‌کند. این نرم‌افزار همچنین در مورد پلتفرم خود سخت‌گیر است: تا آگوست 2026، نسخه پشتیبانی‌شده برای نصب، نسخه 3.0 روی Ubuntu 22.04 است. هر دو مجموعه ارقام از مستندات خودِ پروژه‌ها استخراج شده‌اند و نقاط شروع هستند، نه اندازه‌گیری دقیق بار کاری شما.

#jitsi#webrtc#video-conferencing#self-hosting#bandwidth