VPS 화상 회의 서버 구축: 대역폭 계산 및 소프트웨어 비교
VPS에서 Jitsi, BigBlueButton, Galene을 직접 호스팅할 때 필요한 대역폭 계산법을 안내합니다. 참가자 수에 따른 서버 사양 선정 기준과 NAT 환경에서 발생하는 포트 차단 문제 등 실제 운영 시 겪게 되는 기술적 제약 사항을 상세히 비교 분석합니다.
VPS에서 직접 호스팅하는 화상 회의는 대역폭 문제가 발생합니다
소규모 서버에서 직접 호스팅하는 화상 회의가 실패하는 이유는 단 하나이며, 설치 과정의 문제는 거의 없습니다. 현대적인 모든 도구가 사용하는 서버 구성 요소는 SFU(Selective Forwarding Unit)입니다. 이 장치는 각 참가자로부터 하나의 비디오 스트림을 받아 다른 모든 참가자에게 복사본을 전달하므로, 서버를 나가는 트래픽은 참가자 수의 제곱에 비례하여 증가합니다. 1 GB 또는 2 GB 용량의 VPS를 공유 업링크 환경에서 사용하면 소프트웨어는 정상적으로 실행됩니다. 하지만 여러분이 생각하는 전체 회의를 감당할 수는 없습니다.
따라서 다음 순서대로 작업을 진행하십시오. 참가자 수를 세고, 필요한 메가비트(megabits)를 계산한 뒤, 서버 사양을 선택하십시오. 설치는 복사하고 붙여넣는 20분이면 충분합니다. 하지만 업링크 성능이 상대방에게 여러분의 목소리가 들릴지 여부를 결정합니다.
참가자 수의 제곱에 비례하여 대역폭이 증가하는 이유는 무엇입니까?
메시(mesh) 방식부터 살펴보겠습니다. 각 브라우저는 자신의 카메라 영상을 인코딩하여 다른 모든 브라우저로 직접 복사본을 전송하며, 미디어 서버는 비디오 처리에 관여하지 않습니다. 2인 메시 통화는 시그널링 서버만 있으면 충분하므로 호스팅 비용이 거의 들지 않습니다. 하지만 참가자가 4~5명 정도가 되면 메시 방식은 한계에 부딪힙니다. 가정용 네트워크를 사용하는 노트북이 자신의 비디오 복사본 4~5개를 동시에 업로드해야 하기 때문입니다.
SFU(Selective Forwarding Unit)는 다르게 작동합니다. 각 브라우저는 서버로 복사본을 하나만 업로드합니다. 서버는 RTP(real-time transport protocol) 헤더를 읽고 비디오를 디코딩하지 않은 채로 다른 참가자들에게 패킷을 전달합니다. 이것이 핵심 원리이며, SFU가 CPU 부하는 적고 네트워크 부하는 큰 이유입니다.
더 오래된 방식으로는 MCU(multipoint control unit)가 있습니다. MCU는 들어오는 모든 스트림을 디코딩하고, 하나의 화면으로 합성한 뒤 다시 인코딩합니다. 이 경우 아웃바운드 대역폭은 매우 작지만, CPU 비용은 엄청납니다. 현재 비디오 서비스에서 MCU를 사용하는 경우는 거의 없으며, 이 가이드에서도 다루지 않습니다.
이제 SFU의 산술적 계산을 해보겠습니다. 모든 사람이 1.2 Mbps로 비디오를 전송하고 아무도 카메라를 끄지 않는다고 가정합니다. 서버가 수신하는 데이터는 N 곱하기 1.2 Mbps로, 이는 선형적이며 문제가 되지 않습니다. 하지만 서버가 송신하는 데이터는 N 곱하기 (N 마이너스 1) 곱하기 1.2 Mbps가 됩니다. N명의 참가자 각각이 나머지 N 마이너스 1개의 스트림을 모두 받아야 하기 때문입니다. 이 두 번째 수치가 프로젝트의 성패를 결정짓습니다.
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
}
]위 표의 행들은 산술적인 계산 결과이며 특정 서버의 측정값이 아닙니다. 월간 데이터 열은 한 달에 20시간 통화를 기준으로 합니다. 마지막 행부터 확인해 보십시오. 50명이 카메라를 켜면 단일 서버에서 2,940 Mbps의 지속적인 아웃바운드 트래픽이 필요합니다. 30명은 1,044 Mbps가 필요합니다. 4명은 14.4 Mbps가 필요한데, 이는 어떤 VPS에서도 무리 없이 처리할 수 있는 수준입니다. 4명일 때와 30명일 때를 비교하면 참가자 수는 7.5배 증가하지만, 아웃바운드 트래픽은 70배 이상 증가합니다.
실제 배포 환경에서는 이 수치보다 낮게 나오는데, 그 이유를 정확히 아는 것이 중요합니다. Jitsi와 LiveKit은 모두 시뮬캐스트(simulcast)를 사용합니다. 송신자가 여러 품질 계층을 동시에 게시하면, SFU는 화면에 보이지 않는 사람에게는 낮은 품질의 계층을 전달합니다. Jitsi에는 최근 발언자의 비디오만 전달하는 last-N 설정도 있습니다. 두 방식 모두 트래픽을 크게 절약해 줍니다. 하지만 이 기능들이 곡선의 형태 자체를 바꾸지는 않으며, 모든 사람이 카메라를 켜고 서로를 고정(pin)하는 순간 효과는 사라집니다.
VPS 업링크는 실제로 무엇을 제공하는가?
요금제 페이지에는 "1 Gbps 포트"라고 명시되어 있습니다. 이는 가상 네트워크 카드의 속도일 뿐, 다음 홉(next hop)에 대한 보장 속도가 아닙니다. 해당 링크는 동일한 물리적 호스트를 사용하는 다른 임차인들과 공유되므로, 사용량이 많은 시간대의 지속적인 처리량은 포트 속도보다 낮으며, 화상 회의는 정확히 이러한 지속적 부하를 발생시킵니다. 대부분의 요금제에는 월간 데이터 전송 허용량이 포함되어 있으며, 이를 초과하면 속도가 제한되거나 추가 요금이 청구됩니다.
이 허용량이 바로 청구서에서 문제가 되는 부분입니다. 30명 규모의 회의를 한 달에 20시간 진행하면 서버에서 9.4 TB의 데이터가 전송되며, 시간당 469.8 GB를 소비합니다. 50명 규모의 회의를 20시간 진행하면 26.5 TB가 이동합니다. 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설치 프로그램은 호스트 이름을 물어본 뒤 인증서 선택 옵션을 제공합니다. Let's Encrypt 옵션을 선택하고, 이 서버의 공인 IP 주소로 이미 도메인 연결이 완료된 도메인 이름을 입력하십시오. 인증서는 HTTP 챌린지 방식을 통해 발급되므로, 다른 곳을 가리키는 도메인 이름을 입력하면 해당 단계에서 실패합니다.
그다음 포트를 개방하십시오. 아래는 핸드북에 명시된 포트이며, ufw enable를 통해 접속이 차단되는 일을 방지하기 위해 SSH를 가장 먼저 설정해야 합니다.
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번과 443번 포트는 웹 애플리케이션을 서비스하고 인증서 갱신을 처리합니다. UDP 10000번 포트는 모든 오디오와 비디오 데이터를 전송하며, 사용자가 가장 자주 잊는 포트입니다. UDP 3478번과 TCP 5349번 포트는 Jitsi 패키지가 브리지와 함께 설치하는 coturn 서버용이며, 네트워크에서 UDP를 차단하는 사용자를 위한 대체 경로로 사용됩니다.
sudo systemctl status jitsi-videobridge2
sudo ss -ulnp | grep 10000첫 번째 명령을 실행하면 서비스가 active 상태로 보고되어야 합니다. 두 번째 명령은 브리지가 UDP 10000번 포트에서 수신 대기 중임을 보여주어야 합니다. 아무것도 출력되지 않는다면 브리지가 시작되지 않은 것이며, /var/log/jitsi/jvb.log를 통해 그 이유를 확인할 수 있습니다.
서버 규모 산정과 관련하여, Jitsi 핸드북은 자체적인 권장 사양을 제시하며 BigBlueButton은 훨씬 더 큰 사양을 권장합니다.
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 GB의 RAM과 4개의 전용 코어를 제안하며, 네트워크 대역폭은 1,000 Mbps면 충분한 경우가 많다고 설명합니다. 또한 소규모 설정은 4 GB 또는 2 GB RAM으로도 실행 가능하다고 언급합니다. 해당 페이지에서 기억해 둘 만한 세부 사항이 하나 있습니다. 시그널링을 처리하는 XMPP 서버인 Prosody는 오직 하나의 코어만 사용할 수 있습니다. 추가적인 코어는 브리지 성능에는 도움이 되지만 시그널링에는 아무런 영향을 주지 않습니다.
모두가 통화에 참여했지만 아무도 비디오를 볼 수 없는 이유는 무엇입니까?
이는 VPS에서 발생하는 전형적인 Jitsi 오류입니다. 참가자 목록은 채워지고 채팅은 작동하지만, 모든 비디오 타일이 검은색으로 유지됩니다. videobridge는 자체 인터페이스에서 발견한 주소를 광고합니다. 가상 머신에 사설 주소를 할당하고 공인 주소를 매핑하는 제공업체의 환경에서는 JVB가 사설 주소만 찾게 되므로, 모든 클라이언트가 10.0.0.5와 같은 주소로 미디어 전송을 시도하게 되어 패킷이 전달되지 않습니다.
브리지에 두 주소를 모두 알려주어야 합니다. /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를 실행하십시오. 패킷이 전혀 보이지 않는다면 서버에 도달하기 전에 차단된 것이므로 운영 체제 상위 단계에서 문제가 발생한 것입니다. 패킷은 도착하는데 타일이 검은색으로 유지된다면 브리지가 클라이언트가 도달할 수 없는 주소로 응답하고 있는 것이므로 매핑 문제입니다. ufw 설정 자체가 확실하지 않다면, VPS에 실제로 필요한 ufw 규칙에서 사용자들이 자주 실수하는 규칙 순서에 대해 다루고 있으니 참고하십시오.
BigBlueButton: 무겁고 독단적이며 서버 전체를 요구함
BigBlueButton은 교육용으로 설계되었습니다. 화이트보드, 소그룹 회의실, 설문 조사, 프레젠테이션 영역을 갖추고 있으며, 녹화 파이프라인은 부가 기능이 아닌 핵심 기능으로 제공됩니다. 또한 이 목록에서 압도적으로 가장 무거운 옵션이며, 기존 서버에 패키지 형태로 추가할 수 있는 소프트웨어가 아닙니다.
2026년 8월 기준으로 지원되는 경로는 Ubuntu 22.04 환경의 BigBlueButton 3.0이며, jammy-300 버전 플래그를 사용하여 선택합니다. 프로젝트에서 명시한 운영 요구 사항은 16 GB 메모리(스왑 활성화 필수), 8 개의 CPU 코어(높은 단일 스레드 성능 필요), 250 Mbps의 대칭형 대역폭, 그리고 녹화본을 보관할 경우 500 GB의 디스크 공간(녹화 기능을 비활성화하면 50 GB)입니다. 사용하는 포트는 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 설정을 재작성하고, 자체 미디어 및 오디오 스택을 설치하며, 패키지 버전을 고정하고, 호스트 이름을 점유합니다. 이는 결함이 아니라 설계 방식입니다. BigBlueButton은 해당 머신 전체를 독점적으로 사용하도록 설계되었습니다. -w 플래그는 방화벽을 구성하고, -s은 호스트 이름이며, -e은 Let's Encrypt가 등록할 주소이고, -g은 Greenlight 프런트엔드를 추가합니다. 만약 동일한 서버에서 다른 서비스를 위해 TLS를 종료하고 있다면, BigBlueButton을 다른 곳으로 옮기거나 스크립트가 설정을 수정하기 전에 nginx 리버스 프록시 설정이 수행하는 작업을 확실히 이해해야 합니다.
차트에 있는 두 행을 주의 깊게 비교하십시오. BigBlueButton은 Jitsi가 권장하는 사양보다 두 배의 메모리와 두 배의 코어를 요구하는 반면, 대역폭은 4분의 1 수준을 요구합니다. 두 수치는 측정 방식이 다르고 가정하는 회의실 규모도 다르므로, 직접적인 비교보다는 각 프로젝트의 시작점으로 간주해야 합니다. CPU 요구 사항의 차이는 실재하며, 이는 BigBlueButton이 단순히 비디오를 전달하는 것 외에 수행하는 수많은 작업에서 기인합니다.
Galène: 가벼운 선택지
Galène은 Go로 작성된 소형 SFU입니다. 단일 정적 바이너리로 빌드되며 자체 웹 클라이언트를 포함하고, 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 groupsUbuntu 24.04의 golang-go 패키지는 Go 1.22 버전을 제공합니다. 만약 go build 실행 시 더 최신 버전의 Go가 필요하다는 오류가 발생하면, 배포판 패키지와 씨름하지 말고 go.dev에서 최신 툴체인을 직접 설치하십시오.
Galène에서 그룹(group)은 회의실을 의미하며, 각 그룹은 JSON 파일로 정의됩니다.
echo '{"users": {"vimes": {"password":"sybil", "permissions":"op"}}}' > groups/night-watch.json
./galene &https://your.server:8443/group/night-watch/을 열고 vimes로 로그인하십시오. 해당 자격 증명은 프로젝트의 README에 명시된 기본값이므로, 외부에서 포트에 접근할 수 있게 되기 전에 반드시 변경해야 합니다. 실제 운영 환경을 위해 프로젝트에서는 다음과 같은 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, 내장 TURN 서버용 TCP 및 UDP 1194, 그리고 미디어 전송을 위한 높은 번호의 UDP 포트 범위입니다. 방화벽 규칙을 간소화할 수 있도록 이 포트 범위를 고정하십시오.
./galene -udp-range 40000-40100VPS 환경에서는 -turn 옵션이 중요합니다. -turn ':1194'는 모든 공인 IPv4 주소에서 수신 대기합니다. -turn '203.0.113.1:1194'는 클라이언트가 실제로 인식하게 될 주소를 Galène에 알려주며, 서버의 자체 주소가 사설 IP일 때 필수적입니다. -turn ''은 내장 서버를 비활성화하여 data/ice-servers.json을 통해 외부 서버를 지정할 수 있게 합니다. 기본값은 auto이며, ice-servers.json이 존재하지 않을 때는 :1194와 동일하게 동작합니다.
data/config.json에서 proxyURL을 설정하고 WebSocket 업그레이드 헤더와 함께 /ws 위치를 프록시 처리하여 nginx를 웹 인터페이스 앞에 둘 수 있습니다. 단, 이 구성의 범위를 이해해야 합니다. 클라이언트는 여전히 TURN 포트로 직접 UDP 흐름과 TCP 연결을 생성하므로, 리버스 프록시는 페이지와 시그널링만 처리합니다. 미디어 데이터는 프록시를 거치지 않습니다.
Galène의 문서에 따르면 매우 적은 서버 자원만 필요로 하며 구체적인 수치를 제시하지 않으므로, 특정 사양을 기대하지 마십시오. 앞서 언급한 대역폭 계산 방식은 동일하게 적용됩니다. SFU 외의 불필요한 구성 요소를 제거함으로써 메모리와 운영 복잡도를 절감할 수 있습니다.
Owncast: 대역폭이 선형적으로 유지되는 일대다 스트리밍
많은 "화상 회의" 요구 사항은 사실 한 사람이 발표하고 청중은 채팅으로 참여하는 형태입니다. 이런 경우라면 SFU는 적절한 도구가 아니며 경제성 측면에서도 완전히 다른 접근이 필요합니다. Owncast는 OBS와 같은 인코더에서 RTMP 스트림을 받아 일반적인 HTTPS를 통해 HLS로 송출합니다. 시청자당 대역폭 소모가 제곱이 아닌 선형적으로 증가하며, 출력물이 단순 HTTP 세그먼트이므로 객체 스토리지나 CDN 뒤에 배치하여 오리진 서버의 비용 부담을 없앨 수 있습니다.
curl -sL https://owncast.online/install.sh -o install-owncast.sh
less install-owncast.sh
bash install-owncast.sh이 프로젝트의 문서에서는 root 권한으로 실행하지 말 것과 원격 스크립트를 실행하기 전에 내용을 검토할 것을 권장합니다. 따라서 위와 같이 다운로드 단계를 분리하였습니다. 설치 프로그램은 최신 릴리스와 ffmpeg 바이너리(시스템에 없는 경우)를 가져옵니다. 설치 디렉터리에서 ./owncast를 실행하고 /admin의 8080 포트에서 관리자 패널을 엽니다. 기본 로그인 계정은 admin이며, 기본 스트림 키인 abc123이 비밀번호로 설정되어 있습니다. 서버에 도메인을 연결하기 전에 반드시 비밀번호를 변경하십시오.
HLS 설계 방식에는 두 가지 결과가 따릅니다. HLS는 전체 세그먼트 단위로 전송되므로 시청자는 실시간보다 수 초에서 수 분 정도 지연된 화면을 보게 되며, 따라서 양방향 대화는 불가능합니다. 또한 경로상에 UDP나 TURN이 전혀 없으므로 WebRTC 호출이 연결되지 않는 네트워크 환경에서도 원활하게 작동합니다.
Owncast는 이 문서에서 다루는 도구 중 유일하게 의도적으로 트랜스코딩을 수행합니다. 활성화하는 출력 품질마다 들어오는 스트림을 ffmpeg로 다시 인코딩하며, 이는 방송 시간 내내 지속됩니다. 소규모 VPS를 사용한다면 한두 가지 품질만 제공하십시오. 다섯 가지 품질을 모두 활성화하면 네트워크는 유휴 상태인데 CPU만 포화 상태가 될 수 있습니다.
이미 운영 중인 Matrix 서버에서 Element Call 사용하기
이미 Matrix를 운영 중이라면, 비디오 기능은 별도의 제품을 추가하는 것이 아니라 기존 환경에 기능을 더하는 것입니다. 다만 여전히 여러 패키지를 다루어야 합니다. Element Call이 홈 서버 뒤에서 정상적으로 작동하려면 두 가지가 필요합니다. 첫 번째는 미디어 전달을 담당하는 LiveKit SFU입니다. 두 번째는 클라이언트에 LiveKit WebSocket URL과 연결을 위한 서명된 JWT(JSON web token)를 전달하는 MatrixRTC 인증 서비스인 element-hq/lk-jwt-service입니다. 이 서비스는 Matrix federation API를 사용하므로, 앞단에 TLS 리버스 프록시가 필요하며 federation이 접근할 수 있는 도메인 이름이 있어야 합니다.
LiveKit에서 사용하는 포트는 다음과 같습니다.
- TCP 7880: API 및 클라이언트 WebSocket용이며, TLS를 종료하는 프록시 뒤에 배치합니다.
- TCP 7881: ICE over TCP용이며, 클라이언트가 UDP로 통신할 수 없을 때 사용합니다.
- UDP 50000 ~ 60000: 미디어 통신용이며, 방에 참여하는 각 사용자는 2개의 포트를 사용합니다.
- UDP 3478 및 TCP 5349: 내장 TURN 서버를 활성화할 경우 사용합니다. 로드 밸런서가 앞단에 있지 않다면 5349 포트를 443으로 변경해야 합니다.
참가자당 2개의 포트를 사용한다는 점이 부담스럽게 느껴질 수 있으나 실제로는 그렇지 않습니다. 10,000개의 포트 범위는 수천 명의 참가자를 수용할 수 있으며, 포트 범위가 부족해지기 전에 서버의 업링크 대역폭이 먼저 한계에 도달하게 됩니다. 포트 범위는 전체를 개방하십시오. 일부만 개방할 경우 특정 사용자에게는 작동하고 다른 사용자에게는 실패하는 현상이 발생하며, 이는 디버깅하기 가장 어려운 유형의 오류입니다. 홈 서버 측 설정은 별도의 작업이며, VPS에서 Synapse 홈 서버 운영하기에서 다룹니다.
왜 특정 사용자만 연결할 수 없는가? TURN과 UDP를 차단하는 네트워크
먼저 용어를 정리합니다. ICE(interactive connectivity establishment)는 두 WebRTC 엔드포인트가 서로 연결 가능한 경로를 찾는 과정입니다. STUN(session traversal utilities for NAT)은 클라이언트가 외부에서 보이는 자신의 공인 IP 주소를 확인하게 해주는 작은 서비스입니다. TURN(traversal using relays around NAT)은 중계 서버입니다. 직접 연결 경로가 없을 때 양측은 미디어를 TURN 서버로 보내고, 서버가 이를 전달합니다.
네트워크를 직접 연결할 수 없는 참가자를 위해 TURN이 필요합니다. 한 명은 아웃바운드 UDP가 완전히 차단된 기업이나 캠퍼스 네트워크에 있을 수 있습니다. 다른 한 명은 목적지마다 다른 소스 포트를 할당하는 캐리어급 NAT(symmetric NAT) 뒤에 있을 수 있는데, 이 경우 STUN이 보고한 주소는 사용할 수 없게 됩니다.
증상은 명확합니다. 대부분의 사용자는 정상적으로 참여합니다. 특정 사용자만 참가자 목록과 채팅은 보이지만, 영상 화면은 검은색으로 나오고 로딩 아이콘만 돌아갑니다. 브라우저가 후보(candidate)를 수집했지만 어떤 쌍도 연결되지 않았고, ICE가 실패 상태로 종료된 것입니다. Chrome에서 시도 중에 chrome://webrtc-internals를 열면 후보 쌍과 실패 내역을 확인할 수 있습니다. 해당 사용자에게 모바일 데이터를 사용하여 다시 시도해 보라고 하십시오. 모바일 데이터에서 작동한다면 네트워크가 원인이며, TURN이 해결책입니다.
443 또는 5349 포트를 통한 TCP 기반 TURN은 거의 모든 곳에서 작동하는 대체 수단입니다. 443 포트의 TLS를 차단하는 네트워크라면 이미 웹 접속 자체가 차단되었을 것이기 때문입니다. Jitsi 패키지는 coturn을 자동으로 설치하고 설정해주며, 이것이 방화벽 규칙에 UDP 3478과 TCP 5349가 포함된 이유입니다. Galène은 1194 포트에 TURN이 내장되어 있습니다. LiveKit은 설정에서 켤 수 있는 내장 TURN 서버를 제공합니다. 직접 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-peers이 설정들은 /etc/turnserver.conf에 입력합니다. Debian과 Ubuntu에서는 패키지 설치 즉시 기본 설정 파일로 coturn이 시작되므로, 위 enable --now을 실행해도 이미 실행 중인 프로세스에는 아무런 변화가 없습니다. 설정은 sudo systemctl restart coturn를 실행해야 적용되며, 이후 파일을 수정할 때마다 동일하게 재시작해야 합니다. 오래된 가이드에서는 /etc/default/coturn에 TURNSERVER_ENABLED=1을 설정하라고 안내하기도 합니다. 하지만 이는 구형 init 스크립트에서만 읽는 설정입니다. 현재 패키지가 사용하는 systemd 유닛은 이를 참조하지 않으므로 해당 줄을 수정해도 아무런 변화가 없으며, 재시작하지 않은 coturn은 여전히 이전 설정 파일을 사용하게 됩니다.
이제 아무도 언급하지 않는 비용에 대해 설명합니다. 중계 서버는 중계되는 모든 참가자의 미디어 데이터를 양방향으로 처리합니다. coturn이 SFU와 같은 서버에 있다면 대부분의 트래픽은 루프백을 통과하므로 업링크 대역폭 대신 CPU 자원을 소모하며, TLS 리스너는 미디어에 이미 포함된 DTLS 위에 패킷을 한 번 더 암호화합니다. TURN을 별도의 서버로 분리하면 해당 서버는 SFU와 동일한 수준의 대역폭 계획이 필요합니다. 또한 TCP 기반 TURN은 실시간 미디어를 신뢰성 있는 스트림으로 변환하므로, 패킷 손실 시 건너뛰는 대신 재전송이 발생합니다. 따라서 손실이 잦은 링크에 있는 중계 참가자는 짧은 끊김 대신 지연 시간이 누적됩니다. 중계는 연결을 가능하게 하는 대체 수단일 뿐, 직접 연결보다 품질이 좋을 수는 없습니다.
SFU는 언제 트랜스코딩을 수행하며, 그 비용은 어느 정도입니까?
SFU는 패킷을 전달만 할 뿐 비디오를 디코딩하지 않으므로, 이론상 불가능해 보이는 규모의 회의실도 4개의 코어만으로 처리할 수 있습니다. 하지만 두 가지 기능은 이러한 특성을 깨뜨리며, 체크박스를 눌러 기능을 활성화한 사용자들을 당황하게 만듭니다.
첫 번째는 녹화입니다. Jitsi는 Jibri를 사용하여 녹화하며, Jibri의 자체 문서에는 수행 작업이 정확히 명시되어 있습니다. Jibri는 가상 프레임버퍼에서 렌더링되는 Chrome 인스턴스를 실행하고, ffmpeg를 사용하여 출력을 캡처 및 인코딩합니다. 이는 전체 회의를 렌더링하는 완전한 브라우저와 비디오 인코더가 통화 시간 내내 지속적으로 실행되는 것을 의미합니다. 동일한 문서에 따르면 단일 Jibri에서는 한 번에 하나의 녹화만 지원하며, Jibri는 디스플레이나 오디오 장치를 사용하는 다른 애플리케이션이 없는 별도의 물리 서버나 가상 머신에서 실행하도록 설계되었습니다. 즉, 녹화는 단순한 체크박스 설정이 아니라 별도의 서버가 필요한 작업입니다.
두 번째는 전화 접속입니다. 전화선을 회의에 연결한다는 것은 48 kHz의 Opus를 전화 네트워크가 수용하는 형식(보통 8 kHz의 G.711)으로 양방향에서 통화 내내 지속적으로 변환해야 함을 의미합니다. 오디오 트랜스코딩은 비디오 트랜스코딩보다 훨씬 저렴하지만, 통화 연결마다 실행되며 멈추지 않으므로 비용은 발신자 수에 비례하여 증가합니다. 전화 접속 번호가 필요한 경우, 해당 작업을 수행하는 구성 요소는 자체 호스팅 VoIP 서버이며, Jibri와 마찬가지로 전용 서버에서 운영해야 합니다.
실제로 어느 정도 규모의 서버가 필요한가?
두 명의 사용자라면 거의 아무것도 필요하지 않습니다. Jitsi는 참가자가 정확히 두 명일 때 기본적으로 피어 투 피어(peer to peer) 모드를 활성화합니다. 이 모드에서는 videobridge를 통해 데이터를 전송하지 않고 직접 연결을 사용합니다. 세 번째 사람이 참여하면 다시 브리지 모드로 전환됩니다. 따라서 1 GB VPS는 일대일 통화 서버로는 훌륭하지만 4인용 서버로는 부족합니다. "테스트할 때는 잘 작동했다"는 보고가 흔한 이유가 바로 이것입니다.
카메라를 켠 상태로 최대 10명 정도가 참여한다면, 8명 참여 시 67.2 Mbps의 대역폭은 일반적인 VPS 업링크가 감당할 수 있는 수준입니다. 녹화를 하지 않는다면 2개의 가상 CPU와 4 GB RAM으로 Jitsi나 Galène을 해당 규모로 운영할 수 있습니다. CPU 그래프보다는 전송량 카운터를 확인하십시오.
30명의 경우, 최악의 상황에서는 1,044 Mbps의 지속적인 대역폭이 필요하며, 이를 20시간 동안 사용하면 9.4 TB가 됩니다. 이 규모에서는 서버 가격보다 대역폭 비용을 먼저 고려해야 합니다. last-N 기능을 켜서 브리지가 최근 발언자의 영상만 전달하도록 하고, 참가자의 카메라를 기본적으로 끄도록 설정하십시오. 또한 SFU는 계산된 전송량을 감당할 수 있는 곳에 배치해야 합니다.
그 이상의 규모라면 단일 VPS는 적합하지 않습니다. 이벤트가 사실상 방송 형태라면 Owncast와 CDN을 사용하는 것이 비용 면에서 훨씬 유리합니다. 혹은 단일 시그널링 계층 뒤에 여러 개의 videobridge를 배치해야 하는데, 이는 처음 시작한 프로젝트와는 다른 차원의 작업입니다.
마지막으로 라우팅에 관한 조언입니다. 대부분의 팀은 영상보다 채팅을 훨씬 더 많은 시간 동안 사용하며, 채팅은 호스팅 비용이 저렴하고 유지 관리도 쉽습니다. 일상적인 트래픽을 위해 자체 호스팅 Slack 대안을 구축하고, 예약된 통화에만 화상 회의 서버를 사용하는 방식이 적은 VPS 예산으로 운영을 지속할 수 있는 방법입니다.
FAQ
Jitsi 회의에 참여한 사람들이 서로를 보거나 들을 수 없는 이유는 무엇입니까?
채팅과 참가자 목록은 TCP 443 포트를 사용하는 시그널링 채널을 통해 전송되지만, 오디오와 비디오는 videobridge로 UDP 10000 포트를 사용합니다. 참가자 목록은 표시되는데 모든 화면이 검게 나온다면, 시그널링 경로는 정상이나 미디어 경로가 차단된 상태입니다. 서버 방화벽과 클라우드 제공업체 제어판의 네트워크 방화벽에서 UDP 10000 포트가 열려 있는지 확인하십시오. 그 후 브리지가 자신의 공인 IP 주소를 알고 있는지 확인해야 합니다. 사설 IP를 사용하고 공인 IP가 매핑된 가상 머신이라면 /etc/jitsi/videobridge/jvb.conf 파일의 ice4j.harvest.mapping 항목에 정적 매핑을 추가하고 jitsi-videobridge2 서비스를 재시작하십시오. 누군가 참여할 때 sudo tcpdump -ni any udp port 10000 명령을 실행하면 원인을 파악할 수 있습니다. 패킷이 전혀 들어오지 않는다면 운영체제 외부의 상위 네트워크에서 차단되고 있는 것입니다.
30명 규모의 화상 통화에는 대역폭이 얼마나 필요합니까?
모든 참가자가 카메라를 켜고 SFU가 모든 사람에게 최고 품질의 스트림을 전달하는 최악의 경우, 서버에서 나가는 트래픽은 대략 1,044 Mbps이며, 이는 시간당 469.8 GB에 해당합니다. 이는 스트림당 1.2 Mbps를 기준으로 N 곱하기 (N 마이너스 1)을 계산한 산술적 수치이며, 실제 환경의 측정값은 아닙니다. 실제 사용 시에는 Simulcast와 last-N 설정 덕분에 대부분의 참가자가 화면에 표시되지 않으므로 대역폭이 크게 절감됩니다. 하지만 모든 참가자가 동시에 카메라를 켜는 전체 회의 상황을 대비하여 최악의 경우에 맞춰 자원을 산정하십시오.
1 GB RAM의 VPS에서 Jitsi Meet를 실행할 수 있습니까?
설치는 가능하며 2인 통화는 원활하게 작동합니다. 이는 참가자가 2명일 때 Jitsi가 videobridge를 거치지 않는 P2P 모드를 사용하기 때문입니다. 하지만 그룹 통화 서버로는 적합하지 않습니다. Prosody, videobridge, Java 런타임 모두 메모리를 많이 점유합니다. 공식 가이드에서는 안정적인 운영을 위해 8 GB를 권장하며, 메모리 부족보다 대역폭 계산 결과가 먼저 한계에 도달할 것입니다. 1 GB 사양의 서버를 사용해야 한다면 Jitsi보다 Galène이 더 적합합니다.
VPS에 공인 IP 주소가 있어도 TURN 서버가 여전히 필요합니까?
네, 필요합니다. TURN은 통화 상대방 측의 문제를 해결합니다. 아웃바운드 UDP를 차단하는 기업 네트워크나 목적지마다 다른 소스 포트를 할당하는 CGNAT(Carrier-Grade NAT) 환경에 있는 참가자는 서버의 IP가 공인 주소라 하더라도 직접적인 미디어 경로를 생성할 수 없습니다. TCP 443 또는 5349 포트를 통한 TURN은 방화벽이 일반적인 웹 트래픽으로 인식하도록 릴레이를 제공합니다. Jitsi 패키지 설치 시 기본적으로 coturn이 설정되는 이유가 바로 이것이며, 문서화된 방화벽 규칙에서 UDP 3478과 TCP 5349 포트를 여는 이유이기도 합니다.
BigBlueButton은 왜 Jitsi Meet보다 훨씬 높은 하드웨어 사양을 요구합니까?
단순히 비디오를 전달하는 것 이상의 기능을 수행하기 때문입니다. BigBlueButton의 공식 권장 사양은 16 GB RAM과 8 코어인 반면, Jitsi 가이드의 권장 사양은 8 GB RAM과 4 코어입니다. BigBlueButton은 오디오 회의 스택, 공유 화이트보드 및 프레젠테이션 레이어, 녹화 및 후처리 파이프라인, 사용자 계정을 포함한 웹 프론트엔드를 모두 동일한 머신에서 실행합니다. 또한 플랫폼에 대한 요구 사항이 엄격하여 2026년 8월 기준 Ubuntu 22.04에서 버전 3.0 설치만을 지원합니다. 이 수치들은 각 프로젝트의 문서에서 제공하는 시작점일 뿐, 실제 사용자의 워크로드를 측정한 값은 아닙니다.