Tự host video conference trên VPS: tính bandwidth
Tính bandwidth theo số người trước khi chọn VPS, rồi so sánh Jitsi, BigBlueButton và Galène về RAM, cổng UDP cần mở và lỗi khi chạy sau NAT.
Video conferencing tự host trên VPS là bài toán bandwidth
Video conferencing tự host trên server nhỏ thường thất bại vì một lý do, và hầu như không bao giờ là do bước cài đặt. Thành phần server mà mọi công cụ hiện đại đều sử dụng là SFU (selective forwarding unit). SFU nhận một video stream từ mỗi participant rồi chuyển tiếp một bản sao đến mọi participant khác. Vì vậy, traffic đi ra từ server tăng theo bình phương số người tham gia. VPS 1 GB hoặc 2 GB dùng chung uplink vẫn chạy phần mềm bình thường. Nhưng nó không đủ khả năng phục vụ buổi họp toàn công ty mà bạn đang hình dung.
Vì vậy, hãy làm theo thứ tự này. Đếm số người, tính nhu cầu megabit, rồi chọn máy chủ. Bước cài đặt chỉ mất hai mươi phút để copy và paste. Uplink mới quyết định liệu mọi người có nghe được bạn hay không.
Tại sao băng thông tăng theo bình phương số người tham gia?
Hãy bắt đầu với mesh. Mỗi trình duyệt mã hóa hình ảnh từ camera rồi gửi trực tiếp một bản sao đến từng trình duyệt khác. Không có media server nào xử lý video. Một cuộc gọi mesh 2 người chỉ cần signalling server, không cần thành phần nào khác. Vì vậy, chi phí host cuộc gọi một-một gần như bằng 0. Mesh không còn hoạt động tốt khi có khoảng 4 hoặc 5 người, vì laptop dùng kết nối gia đình phải upload đồng thời 4 hoặc 5 bản sao riêng của video từ chính nó.
SFU hoạt động khác. Mỗi trình duyệt upload một bản sao lên server. Server đọc các header RTP (real-time transport protocol), rồi chuyển tiếp các packet đó đến những người tham gia khác mà không decode video. Đó là toàn bộ cơ chế, và cũng là lý do SFU nhẹ về CPU nhưng tiêu tốn nhiều network.
Mô hình cũ hơn là MCU (multipoint control unit). Nó decode mọi stream đầu vào, ghép chúng thành một hình ảnh rồi encode lại hình ảnh đó. Băng thông outbound rất thấp. Chi phí CPU rất lớn. Hiện nay gần như không còn hệ thống nào dùng MCU cho video, và guide này cũng không dùng.
Bây giờ tính toán cho SFU. Giả sử mỗi người gửi video ở mức 1.2 Mbps và không ai tắt camera. Server nhận N lần 1.2 Mbps. Con số này tăng tuyến tính và không đáng lo. Server gửi N lần (N trừ 1) lần 1.2 Mbps, vì mỗi người trong số N người phải nhận N trừ 1 stream còn lại. Chính con số thứ hai này thường khiến các dự án phải dừng lại.
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
}
]Các dòng này là phép tính, không phải số đo của một server cụ thể. Cột theo tháng giả định có 20 giờ gọi trong một tháng. Hãy đọc dòng cuối trước. 50 người bật camera cần 2,940 Mbps lưu lượng outbound liên tục từ một máy duy nhất. 30 người cần 1,044 Mbps. 4 người cần 14.4 Mbps. Mức này VPS nào cũng xử lý được mà gần như không nhận thấy tải. Từ dòng 4 người đến dòng 30 người, số người tăng 7.5 lần nhưng lưu lượng outbound tăng hơn 70 lần.
Các hệ thống triển khai thực tế thường thấp hơn những con số này. Bạn cần biết chính xác vì sao. Jitsi và LiveKit đều dùng simulcast: sender publish cùng lúc nhiều layer chất lượng, còn SFU forward layer thấp cho những người không nằm trên màn hình. Jitsi còn có thiết lập last-N, chỉ forward video của những speaker gần đây nhất. Cả hai cách đều tiết kiệm đáng kể traffic. Nhưng không cách nào thay đổi dạng của đường cong. Cả hai cũng không còn giúp được gì khi mọi người bật camera và pin video của nhau.
VPS uplink thực sự cung cấp cho bạn điều gì?
Trang gói dịch vụ ghi “cổng 1 Gbps”. Đây là tốc độ của card mạng ảo, không phải cam kết về hop mạng tiếp theo. Đường truyền được chia sẻ với các tenant khác trên cùng máy chủ vật lý, nên throughput duy trì trong giờ cao điểm sẽ thấp hơn tốc độ cổng. Cuộc gọi hội nghị chính là một tải duy trì. Hầu hết các gói cũng có hạn mức transfer hằng tháng. Sau khi vượt hạn mức, bạn sẽ bị throttle hoặc tính phí.
Hạn mức đó có thể khiến hóa đơn tăng mạnh. Trong một tháng, 20 giờ của cuộc gọi 30 người sẽ truyền 9.4 TB ra khỏi server, với tốc độ 469.8 GB mỗi giờ. 20 giờ của cuộc gọi 50 người sẽ truyền 26.5 TB. Hãy kiểm tra hạn mức transfer trước khi kiểm tra dung lượng RAM. Nếu trang gói dịch vụ mô tả không rõ phần này, chính sự không rõ đó đã là câu trả lời. Đọc đúng một gói VPS giá rẻ quan trọng hơn đối với workload này so với gần như mọi workload khác.
Jitsi Meet: lựa chọn mặc định và các yêu cầu
Jitsi Meet là lựa chọn mà hầu hết mọi người nên bắt đầu. Phần mềm được cài đặt từ Debian repository của dự án, tự cấu hình nginx và certificate trong quá trình cài đặt, còn videobridge (JVB) chỉ sử dụng một UDP port nên các firewall rule vẫn ngắn gọn. Phần mềm cần Debian 11 trở lên hoặc Ubuntu 22.04 trở lên.
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-meetTrình cài đặt yêu cầu hostname rồi đưa ra lựa chọn certificate. Hãy chọn tùy chọn Let's Encrypt và cung cấp domain name đã phân giải đến public address của server này. Certificate được cấp thông qua HTTP challenge, nên nếu tên miền trỏ đến nơi khác thì bước này sẽ thất bại.
Sau đó mở các port. Đây là các port được handbook ghi lại, với SSH đứng trước để ufw enable không khóa bạn khỏi server:
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 enableTCP 80 và 443 phục vụ web app và cho phép gia hạn certificate. UDP 10000 truyền toàn bộ audio và video, và đây là port mọi người thường quên. UDP 3478 và TCP 5349 thuộc về coturn server mà Jitsi package cài cùng với bridge. Đây là đường dự phòng cho những người dùng có network chặn UDP.
sudo systemctl status jitsi-videobridge2
sudo ss -ulnp | grep 10000Lệnh đầu tiên phải báo service đang active. Lệnh thứ hai phải hiển thị bridge đang listen trên UDP 10000. Nếu không in ra gì, bridge chưa khởi động và /var/log/jitsi/jvb.log sẽ cho biết lý do.
Về sizing, handbook của Jitsi công bố một điểm khởi đầu riêng, còn BigBlueButton công bố mức lớn hơn nhiều:
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
}
]Handbook của Jitsi đề xuất 8 GB RAM và 4 core chuyên dụng cho một server nghiêm túc. Network 1,000 Mbps thường là đủ. Handbook cũng lưu ý rằng các setup nhỏ hơn có thể chạy với 4 GB hoặc 2 GB. Có một chi tiết trên trang đó đáng ghi nhớ: Prosody, XMPP server xử lý signalling, chỉ có thể sử dụng một core. Các core bổ sung giúp bridge nhưng không giúp xử lý signalling.
Tại sao mọi người đều tham gia cuộc gọi nhưng không ai thấy video?
Đây là lỗi Jitsi thường gặp trên VPS. Danh sách người tham gia hiển thị, chat vẫn hoạt động, nhưng mọi ô video đều màu đen. Videobridge quảng bá các địa chỉ mà nó tìm thấy trên những interface của chính nó. Với nhà cung cấp cấp cho virtual machine một địa chỉ private và map một địa chỉ public vào đó, địa chỉ duy nhất JVB tìm thấy là địa chỉ private. Vì vậy, mọi client cố gửi media đến địa chỉ như 10.0.0.5, nhưng packet không đến được đích.
Hãy khai báo cả 2 địa chỉ cho bridge. Thêm static mapping vào /etc/jitsi/videobridge/jvb.conf:
ice4j {
harvest {
mapping {
static-mappings = [
{
local-address = "10.0.0.5"
public-address = "203.0.113.10"
}
]
}
}
}Khởi động lại bằng sudo systemctl restart jitsi-videobridge2. Lấy địa chỉ local từ ip -4 addr show và địa chỉ public từ control panel của nhà cung cấp. Các guide cũ đặt cùng cấu hình trong /etc/jitsi/videobridge/sip-communicator.properties bằng các key org.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS và org.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS. Các key này vẫn hoạt động, nhưng bản cài mới nên dùng mapping block ở trên.
Nguyên nhân còn lại là firewall bạn chưa cấu hình. Hầu hết nhà cung cấp có network firewall trong control panel, tách biệt với ufw trên server, và UDP 10000 phải được mở ở cả 2 nơi. Để xác định layer nào đang drop packet, chạy sudo tcpdump -ni any udp port 10000 trên server trong khi một người tham gia từ bên ngoài. Nếu không có packet nào đến, nghĩa là packet chưa tới được máy, nên block nằm ở phía upstream của operating system. Nếu packet đến nhưng các ô video vẫn màu đen, bridge đang trả về một địa chỉ mà client không thể kết nối. Khi đó, nguyên nhân là mapping. Nếu bạn chưa chắc ufw là phần nào, các rule ufw thực sự cần trên VPS giải thích thứ tự rule thường gây nhầm lẫn.
BigBlueButton: nặng, nhiều quyết định có sẵn và cần toàn bộ server
BigBlueButton được thiết kế cho việc giảng dạy. Nó có bảng trắng, phòng nhóm, bình chọn và khu vực trình chiếu. Pipeline ghi hình của nó là tính năng chính thức, không phải phần bổ sung. Đây cũng là lựa chọn nặng nhất trong danh sách này với chênh lệch lớn. Bạn không thể cài nó như một package bổ sung vào server hiện có.
Tính đến tháng 8 năm 2026, cách cài được hỗ trợ là BigBlueButton 3.0 trên Ubuntu 22.04, được chọn bằng version flag jammy-300. Yêu cầu production do dự án công bố là 16 GB memory với swap được bật, 8 CPU core có hiệu năng single-thread cao, 250 Mbps bandwidth đối xứng và 500 GB disk nếu bạn giữ recording (50 GB nếu tắt recording). Các port cần mở là TCP 80 và 443, cùng với dải UDP từ 16384 đến 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 -gCác ví dụ do dự án cung cấp pipe trực tiếp script đó vào bash. Thay vào đó, hãy download và đọc script trước. Script sẽ viết lại cấu hình nginx, cài media stack và audio stack riêng, pin version của package và chiếm hostname. Đây là thiết kế của BigBlueButton, không phải lỗi: BigBlueButton giả định rằng nó có toàn quyền trên máy. Flag -w cấu hình firewall, -s là hostname, -e là địa chỉ mà Let's Encrypt đăng ký, còn -g thêm frontend Greenlight. Nếu box này cũng terminate TLS cho các service khác, hãy chuyển BigBlueButton sang nơi khác hoặc đảm bảo bạn hiểu reverse proxy nginx đang làm gì trước khi script chỉnh sửa cấu hình.
Hãy so sánh cẩn thận hai dòng trong biểu đồ đó. BigBlueButton yêu cầu memory gấp đôi và số core gấp đôi so với đề xuất của Jitsi, nhưng chỉ yêu cầu một phần tư bandwidth. Hai con số này không được đo theo cùng một cách và giả định các room có kích thước khác nhau. Vì vậy, hãy xem mỗi con số là điểm bắt đầu riêng của dự án tương ứng, không phải phép so sánh tương đương trực tiếp. Chênh lệch CPU là có thật. Nguyên nhân là tất cả tác vụ BigBlueButton thực hiện ngoài việc forward video.
Galène: lựa chọn gọn nhẹ
Galène là một SFU nhỏ gọn được viết bằng Go. Phần mềm được build thành một static binary duy nhất, có sẵn web client và tích hợp TURN server, nên bạn không cần duy trì XMPP server, Java runtime hoặc Rails application. Nếu yêu cầu của bạn chỉ là một cuộc gọi ổn định với 10 người trên một máy có cấu hình vừa phải, hãy thử Galène trước khi kết luận rằng bạn cần thêm phần cứng.
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 groupsGói golang-go trên Ubuntu 24.04 là Go 1.22. Nếu go build báo module cần phiên bản Go mới hơn, hãy cài toolchain hiện tại từ go.dev thay vì cố dùng gói của bản phân phối.
Trong Galène, group là cách gọi một room, và mỗi group là một file JSON:
echo '{"users": {"vimes": {"password":"sybil", "permissions":"op"}}}' > groups/night-watch.json
./galene &Mở https://your.server:8443/group/night-watch/ và đăng nhập bằng vimes. Thông tin xác thực này được lấy trực tiếp từ README của project, vì vậy hãy đổi chúng trước khi port có thể truy cập từ nơi khác. Với deployment thực tế, project có tài liệu về systemd unit:
[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.targetCác port gồm TCP 8443 cho web interface, TCP và UDP 1194 cho TURN server tích hợp, cùng một dải UDP port cao cho media. Hãy cố định dải port này để bạn chỉ cần viết một firewall rule cho nó:
./galene -udp-range 40000-40100Tùy chọn -turn là tùy chọn quan trọng trên VPS. -turn ':1194' cho Galène listen trên mọi địa chỉ IPv4 public. -turn '203.0.113.1:1194' cho Galène biết địa chỉ mà client thực sự nhìn thấy. Bạn cần tùy chọn này khi địa chỉ của máy là địa chỉ private. -turn '' tắt server tích hợp để bạn có thể trỏ đến server bên ngoài thông qua data/ice-servers.json. Giá trị mặc định là auto, hoạt động giống :1194 khi không có ice-servers.json.
Bạn có thể đặt nginx phía trước web interface bằng cách cấu hình proxyURL trong data/config.json, rồi proxy location /ws với các header nâng cấp WebSocket. Cần hiểu rõ phạm vi của cách này: client vẫn mở các luồng UDP trực tiếp và các kết nối TCP trực tiếp đến TURN port, nên reverse proxy chỉ xử lý page và signalling. Media không đi qua reverse proxy.
Tài liệu của Galène nói rằng phần mềm cần tài nguyên server ở mức rất vừa phải nhưng không đưa ra con số cụ thể, vì vậy đừng chờ một con số cố định. Phép tính bandwidth ở trên vẫn áp dụng đầy đủ. Phần bạn tiết kiệm được là memory và các thành phần vận hành của mọi thứ không thuộc SFU.
Owncast: một đến nhiều, băng thông tăng tuyến tính
Nhiều nhu cầu “hội nghị video” thực chất là một người thuyết trình cho khán giả, còn khán giả thì nhập tin nhắn trong chat. Nếu nhu cầu của bạn là như vậy, SFU là công cụ không phù hợp và mô hình chi phí cũng thay đổi hoàn toàn. Owncast nhận stream RTMP từ OBS hoặc encoder tương tự, rồi phân phối HLS qua HTTPS thông thường. Băng thông trên mỗi viewer tăng tuyến tính thay vì theo cấp số nhân, và vì đầu ra là các HTTP segment thông thường, bạn có thể đưa chúng qua object storage hoặc CDN để không phải trả chi phí phân phối tại origin.
curl -sL https://owncast.online/install.sh -o install-owncast.sh
less install-owncast.sh
bash install-owncast.shTài liệu của dự án yêu cầu không chạy công cụ này dưới root và phải kiểm tra mọi remote script trước khi thực thi. Vì vậy, bước download được tách riêng ở trên. Installer tải release hiện tại và binary ffmpeg nếu hệ thống chưa có. Chạy ./owncast từ thư mục cài đặt rồi mở admin panel tại /admin trên port 8080. Tài khoản mặc định là user admin, còn stream key mặc định abc123 được dùng làm password. Hãy đổi password trước khi trỏ domain vào server.
Thiết kế HLS dẫn đến 2 hệ quả. Viewer sẽ chậm hơn live vài giây hoặc vài phút vì HLS phân phối từng segment hoàn chỉnh, nên không thể trò chuyện hai chiều theo thời gian thực. Ngoài ra, đường truyền không sử dụng UDP hay TURN ở bất kỳ đâu, nên có thể kết nối đến những network mà cuộc gọi WebRTC hoàn toàn không thể thiết lập.
Owncast cũng là công cụ duy nhất trong danh sách này chủ động thực hiện transcoding. Mỗi output quality bạn bật sẽ tạo thêm một lần encode bằng ffmpeg cho stream đầu vào và chạy trong suốt thời gian broadcast. Trên VPS nhỏ, hãy cung cấp 1 hoặc 2 quality. Nếu cung cấp 5 quality, CPU sẽ bị quá tải trong khi network vẫn không sử dụng hết.
Element Call trên Matrix server bạn đang vận hành
Nếu bạn đã vận hành Matrix, video chỉ là phần bổ sung thay vì một sản phẩm thứ hai cần quản lý. Tuy nhiên, hệ thống vẫn cần nhiều hơn một package. Element Call cần 2 thành phần phía sau homeserver. Thành phần đầu tiên là LiveKit SFU, chịu trách nhiệm chuyển tiếp media. Thành phần thứ hai là MatrixRTC authorisation service, element-hq/lk-jwt-service, cung cấp cho client URL WebSocket của LiveKit và một JWT (JSON web token) đã ký để kết nối. Service này dùng Matrix federation API, nên cần một TLS reverse proxy phía trước và một hostname mà federation có thể truy cập.
Các port được LiveKit tài liệu hóa:
- TCP 7880 cho API và client WebSocket, phía sau proxy thực hiện TLS termination
- TCP 7881 cho ICE over TCP, dùng khi client không thể kết nối ra ngoài qua UDP
- UDP 50000 đến 60000 cho media, trong đó mỗi participant trong một room dùng 2 port
- UDP 3478 và TCP 5349 nếu bật embedded TURN server; TCP 5349 phải chuyển sang 443 trừ khi có load balancer đứng phía trước
Việc mỗi participant dùng 2 port nghe có vẻ đáng lo nhưng thực tế không phải vậy. Dải 10,000 port đủ cho hàng nghìn participant, và uplink của bạn sẽ hết trước khi dải port này hết. Dù vậy, hãy mở toàn bộ dải port, vì dải mở không đầy đủ sẽ khiến một số người kết nối được còn những người khác thì không. Đây là loại lỗi khó debug nhất. Phần homeserver có quy trình riêng, được trình bày trong vận hành Synapse homeserver trên VPS.
Một người không bao giờ kết nối được vì sao? TURN và những mạng chặn UDP
Trước hết là một số thuật ngữ, mỗi thuật ngữ chỉ dùng một lần. ICE (interactive connectivity establishment) là quy trình mà hai endpoint WebRTC dùng để tìm một đường kết nối hoạt động được giữa chúng. STUN (session traversal utilities for NAT) là một dịch vụ nhỏ cho client biết địa chỉ public của chính nó trông như thế nào từ bên ngoài. TURN (traversal using relays around NAT) là một relay: khi không có đường kết nối trực tiếp, hai phía gửi media đến TURN server và server chuyển tiếp dữ liệu.
Bạn cần TURN cho những participant sử dụng các mạng mà bạn không thể kiểm soát. Một người có thể đang ở trên mạng doanh nghiệp hoặc mạng campus chặn hoàn toàn UDP outbound. Một người khác có thể đứng sau carrier-grade NAT cấp một source port khác cho từng destination. Trường hợp này gọi là symmetric NAT và khiến địa chỉ do STUN báo về trở nên vô dụng.
Triệu chứng khá rõ. Hầu hết mọi người tham gia và mọi thứ hoạt động bình thường. Một người vẫn thấy danh sách participant, thấy chat, nhưng chỉ nhận được tile màu đen cùng spinner. Browser của họ đã thu thập candidates, nhưng không cặp candidate nào hoạt động và ICE kết thúc ở trạng thái failed. Trong Chrome, mở chrome://webrtc-internals trong lúc thử kết nối sẽ hiển thị các candidate pair và lỗi đó. Hãy yêu cầu người này thử lại bằng điện thoại qua mobile data. Nếu kết nối được ở đó, nguyên nhân là mạng của họ và TURN là cách khắc phục.
TURN qua TCP trên 443 hoặc 5349 là phương án dự phòng hoạt động ở gần như mọi nơi, vì mạng chặn TLS trên 443 cũng đã chặn web. Package của Jitsi cài đặt và cấu hình coturn cho bạn. Vì vậy, các firewall rule được tài liệu hóa của Jitsi có UDP 3478 và TCP 5349. Galène tích hợp sẵn TURN trên 1194. LiveKit có TURN server tích hợp, chỉ cần bật trong config. Nếu tự chạy coturn:
sudo apt install -y coturn
sudo systemctl enable --now coturnlistening-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-peersTrên Debian và Ubuntu, service do package cung cấp sẽ không khởi động cho đến khi bạn đặt TURNSERVER_ENABLED=1 trong /etc/default/coturn. Một coturn đã được cài nhưng chưa enable trông từ bên ngoài không khác gì hoàn toàn không có TURN. Vì vậy, chỉ một dòng này cũng có thể khiến nhiều người mất cả buổi tối để tìm lỗi.
Bây giờ là chi phí thường không được tính đến. Một relay chuyển tiếp toàn bộ media của từng participant được relay theo cả hai chiều. Khi coturn dùng chung máy với SFU, phần lớn lưu lượng đó đi qua loopback và tiêu tốn CPU thay vì uplink. TLS listener cũng mã hóa mỗi packet thêm một lần, bên cạnh DTLS vốn đã được media sử dụng. Khi chuyển TURN sang máy riêng, máy đó cần một gói bandwidth được tính theo cùng cách như gói bandwidth của SFU. TURN qua TCP biến media thời gian thực thành một reliable stream. Vì vậy, packet bị mất sẽ được truyền lại thay vì bỏ qua. Participant được relay qua một đường truyền mất packet sẽ tích lũy độ trễ thay vì chỉ gặp một glitch ngắn. Relay là phương án dự phòng giúp kết nối được, nhưng chất lượng sẽ kém hơn đường truyền trực tiếp.
Khi nào SFU transcode, và việc đó tốn tài nguyên đến mức nào?
SFU chuyển tiếp packet và không bao giờ decode video. Vì vậy, 4 core có thể phục vụ một phòng họp mà trên lý thuyết có vẻ vượt quá khả năng. Có 2 tính năng phá vỡ đặc điểm này. Cả hai thường khiến người bật chúng bằng một checkbox bất ngờ.
Tính năng đầu tiên là recording. Jitsi dùng Jibri để recording. Tài liệu của Jibri mô tả chính xác cách nó hoạt động: Jibri khởi chạy một instance Chrome được render trong virtual framebuffer, sau đó capture và encode output bằng ffmpeg. Đây là một trình duyệt render toàn bộ cuộc họp, cùng với một video encoder, chạy liên tục trong suốt cuộc gọi. Tài liệu cũng nêu rằng một Jibri chỉ hỗ trợ 1 recording tại một thời điểm. Jibri được thiết kế để chạy trên một máy hoặc virtual machine riêng, không có ứng dụng nào khác sử dụng display hoặc audio device. Recording cần một server thứ hai, không phải chỉ bật một checkbox.
Tính năng thứ hai là telephone dial-in. Kết nối một đường điện thoại vào conference có nghĩa là chuyển đổi Opus ở 48 kHz sang định dạng mà mạng điện thoại chấp nhận, thường là G.711 ở 8 kHz, theo cả hai chiều và liên tục trong suốt cuộc gọi. Audio transcoding rẻ hơn nhiều so với video transcoding, nhưng nó chạy cho từng call leg và không bao giờ tạm dừng. Vì vậy, chi phí tăng theo số người gọi. Nếu muốn có một số dial-in, VoIP server tự host là component thực hiện việc đó. Component này nên chạy trên một máy riêng, vì cùng lý do với Jibri.
Bạn thực sự cần máy chủ lớn đến mức nào?
Với 2 người thì hầu như không cần tài nguyên đáng kể. Jitsi mặc định bật chế độ peer-to-peer khi có đúng 2 người tham gia. Ở chế độ này, conference không gửi dữ liệu qua videobridge mà dùng kết nối trực tiếp. Khi người thứ 3 tham gia, Jitsi chuyển lại sang bridge. Vì vậy, một VPS 1 GB chạy Jitsi phù hợp để thực hiện cuộc gọi 1-1, nhưng không phù hợp cho cuộc gọi 4 người. Đây là lý do câu “khi tôi test thì nó vẫn hoạt động” xuất hiện rất thường xuyên.
Với tối đa khoảng 10 người bật camera, 67.2 Mbps ở 8 người tham gia vẫn nằm trong mức uplink mà một VPS thông thường có thể duy trì. 2 vCPU và 4 GB đủ để chạy Jitsi hoặc Galène ở quy mô này, miễn là bạn không recording. Hãy theo dõi bộ đếm transfer thay vì biểu đồ CPU.
Với 30 người, trường hợp xấu nhất là 1,044 Mbps liên tục, và 20 giờ ở mức đó tương đương 9.4 TB. Ở quy mô này, bạn cần tính chi phí bandwidth trước khi tính chi phí máy chủ. Bật last-N để bridge chỉ chuyển tiếp những người vừa phát biểu, đặt camera-off làm mặc định cho người tham dự, và đặt SFU ở nơi có hạn mức transfer đủ sau khi tính toán.
Trên mức đó, một VPS không còn phù hợp. Hoặc sự kiện thực chất là một buổi phát sóng, khi đó Owncast kết hợp với CDN có chi phí chỉ bằng một phần nhỏ, hoặc bạn cần nhiều videobridge phía sau một lớp signalling duy nhất. Đây là một dự án khác với dự án ban đầu.
Cuối cùng là một phần về routing. Hầu hết các nhóm cần chat nhiều giờ hơn trong ngày so với video. Chat cũng rẻ và dễ duy trì hơn. Dựng một lựa chọn thay thế Slack tự host cho hoạt động hằng ngày, rồi chỉ dùng server conference cho các cuộc gọi đã lên lịch, là mô hình có thể duy trì trong phạm vi ngân sách VPS nhỏ.
FAQ
Vì sao mọi người có thể tham gia cuộc họp Jitsi nhưng không nghe hoặc nhìn thấy nhau?
Chat và danh sách người tham gia đi qua kênh signalling, sử dụng TCP trên cổng 443, còn audio và video sử dụng UDP 10000 đến videobridge. Nếu danh sách người tham gia hiển thị đầy đủ nhưng mọi ô video vẫn màu đen, media path đã hỏng trong khi signalling path vẫn hoạt động. Kiểm tra UDP 10000 trên cả hai firewall: firewall trên máy chủ và firewall mạng riêng trong control panel của nhà cung cấp. Sau đó kiểm tra bridge đã biết địa chỉ public của nó chưa: trên virtual machine có địa chỉ private và địa chỉ public được map, hãy thêm static mapping trong ice4j.harvest.mapping tại /etc/jitsi/videobridge/jvb.conf rồi restart jitsi-videobridge2. Chạy sudo tcpdump -ni any udp port 10000 trong lúc có người tham gia sẽ cho biết vấn đề nằm ở đâu, vì hoàn toàn không có packet nào nghĩa là block xảy ra trước khi packet đến operating system.
Một cuộc gọi video 30 người sử dụng bao nhiêu bandwidth?
Trong trường hợp xấu nhất, khi mọi người đều bật camera và SFU forward một layer chất lượng đầy đủ đến tất cả người khác, server sẽ gửi ra khoảng 1,044 Mbps, tương đương 469.8 GB mỗi giờ. Đây là phép tính từ N nhân với (N trừ 1) stream ở mức 1.2 Mbps mỗi stream, không phải số đo của setup của bạn. Simulcast và setting last-N thường giảm con số này đáng kể, vì tại một thời điểm bất kỳ, phần lớn người tham gia không xuất hiện trên màn hình. Dù vậy, hãy sizing gần với trường hợp xấu nhất, vì trường hợp xấu nhất là lúc tất cả mọi người cùng bật camera trong một cuộc họp toàn thể.
Tôi có thể chạy Jitsi Meet trên VPS 1 GB không?
Jitsi sẽ cài đặt được và cuộc gọi 2 người sẽ hoạt động, một phần vì Jitsi dùng chế độ peer to peer khi có đúng 2 người tham gia và bỏ qua videobridge hoàn toàn. Đây không phải server phù hợp cho cuộc gọi nhóm. Prosody, videobridge và Java runtime đều cần memory; handbook của dự án khuyến nghị 8 GB cho deployment nghiêm túc, và phép tính bandwidth sẽ trở thành giới hạn trước memory. Nếu bạn chỉ có một máy 1 GB, Galène phù hợp với kích thước này hơn Jitsi.
VPS có public IP thì tôi vẫn cần TURN server không?
Có. Vấn đề mà TURN giải quyết nằm ở đầu bên kia của cuộc gọi. Người tham gia sử dụng corporate network chặn UDP outbound, hoặc đứng sau carrier-grade NAT cấp một source port khác cho mỗi destination, sẽ không thể tạo media path trực tiếp dù server của bạn có public address. TURN qua TCP trên cổng 443 hoặc 5349 cung cấp cho họ một relay mà firewall nhận diện giống web traffic thông thường. Package install của Jitsi mặc định thiết lập coturn, nên các firewall rule được tài liệu hóa của Jitsi mở UDP 3478 và TCP 5349.
Vì sao BigBlueButton cần nhiều hardware hơn Jitsi Meet đến vậy?
Vì BigBlueButton làm nhiều việc hơn là chỉ forward video. Yêu cầu production được công bố là 16 GB RAM và 8 core, so với 8 GB và 4 core trong handbook của Jitsi. BigBlueButton chạy full audio conferencing stack, shared whiteboard và presentation layer, recording và post-processing pipeline, cùng web front end có user account, tất cả trên cùng một máy. BigBlueButton cũng yêu cầu chặt chẽ về platform: tính đến tháng 8 năm 2026, bản cài đặt được hỗ trợ là version 3.0 trên Ubuntu 22.04. Cả hai bộ số liệu đều lấy từ tài liệu riêng của từng dự án và chỉ là điểm bắt đầu, không phải số đo cho workload của bạn.