2026. 3. 20. 21:44ㆍWebRTC
| OS | Rocky 9.7 |
| coturn 버전 | 4.9.0 |
| Janus 버전 | 1.4.1 |
현재 문제 상황
Janus WebRTC Server를 활용해 실시간 스트리밍 환경을 구축하던 중 예상치 못한 문제를 겪었습니다 😢
외부 인터넷이 차단된 폐쇄망 환경에서 WebRTC 연결이 정상적으로 이루어지지 않았고
클라이언트에서는 아래와 같은 현상이 발생했습니다.
- ICE candidate 수집 실패: 로컬 외 네트워크 경로를 찾지 못하는 문제
- 연결 시도 후 timeout: 미디어 채널 형성 실패
- 미디어 스트림 전송 불가: P2P 연결 단계에서 중단
WebRTC는 NAT 환경에서도 통신하기 위해 ICE 과정을 거칩니다.
이때 외부 네트워크 정보를 확인하기 위해 STUN 서버를 사용하게 되는데
보통 구글 등에서 제공하는 퍼블릭 STUN 서버를 기본값으로 사용합니다.
webRTC stun / turn server list
webRTC stun / turn server list. GitHub Gist: instantly share code, notes, and snippets.
gist.github.com
하지만 외부망과 완전히 차단된 환경에서는 퍼블릭 STUN 서버에 접근할 수 없기 때문에
ICE 과정이 정상적으로 완료되지 않아 WebRTC 연결이 불가능하였습니다.
ICE
= Interactive Connectivity Establishment
ICE는 WebRTC에서 두 클라이언트가 서로 통신할 수 있는 최적의 네트워크 경로를 찾아주는 메커니즘
WebRTC에서 STUN과 TURN 역할
STUN
STUN 서버는 클라이언트가 자신의 공인 IP와 포트 정보를 확인할 수 있게 도와줍니다.
➡️ 상대방이 나를 찾을 수 있도록 / 내가 외부에서 어떤 주소로 보이는지 알려주는 역할
TURN
STUN을 통한 연결이 불가능할 때 데이터를 중간에서 전달하는 중계 서버 역할을 합니다.
현재와 같이 외부 STUN 서버를 사용할 수 없는 환경에서는
내부 네트워크 내에서 통신할 수 있는 대체 수단이 필요합니다.
이때 가장 현실적인 해결 방법은 내부망에 직접 TURN 서버를 구축하는 것입니다.
널리 사용되는 대표적인 오픈소스가 바로 coturn입니다.
coturn 설치 및 적용
폐쇄망 환경에서 외부 레포지토리에 접근할 수 없기에 오프라인 설치로 진행하였습니다.
- 인터넷 접속이 가능한 외부 서버에서 coturn 설치용 RPM 패키지 다운로드
- 다운로드된 rpm 파일을 로컬 PC로 복사
- rpm 파일 폐쇄망 서버에 업로드 후 로컬 RPM 설치 방식을 통해 coturn 설치
RPM 패키지 다운로드
※ 인터넷 접속 가능한 서버 OS도 Rocky 9.7입니다.
dnf download --resolve coturn
로컬 PC로 복사
MobaXTerm을 이용해 서버에 접속한 뒤
내장된 SFTP 기능을 통해 서버의 파일을 로컬 PC로 다운로드합니다.

coturn 설치
# coturn 설치 폴더 생성
sudo mkdir /opt/coturn
cd /opt/coturn
sudo dnf install *.rpm --disablerepo=*
# 패키지 설치되었는지 확인
rpm -qa | grep coturn

# 실행파일 확인
which turnserver

# 버전 확인
turnserver --version

# 자동 재시작 설정
sudo systemctl enable coturn
# coturn 실행
sudo systemctl start coturn
coturn 설정 파일 수정
sudo vi /etc/coturn/turnserver.conf
# 인증 및 보안 설정
# Long-term credential mechanism 사용 (WebRTC에서 필수적인 인증 방식)
lt-cred-mech
# STUN/TURN 서버에 접근할 사용자 계정 설정
user=<계정>:<비밀번호>
# 서버의 권한 영역(Realm) 지정
# 폐쇄망이라 도메인이 없어도 되지만 식별을 위해 임의의 문자열 입력
realm=test.local
# 모든 메시지에 핑거프린트 추가
fingerprint
# 클라이언트가 접속 가능한 서버의 고정 IP(공인 IP)
external-ip=<고정 IP>
# 클라이언트 간 P2P 연결이 실패했을 때 데이터를 중계(Relay)하기 위해 사용할 포트 범위
min-port=49160
max-port=49200
fingerprint
STUN/TURN 패킷의 마지막 부분에 해당 패킷이 손상되지 않았음을 증명하는 32비트 CRC 값을 강제로 추가하는 설정
sudo systemctl restart coturn
설정 파일 작성 후 coturn을 재시작합니다.
(필요한 경우) 방화벽 설정
sudo firewall-cmd --add-port=3478/udp --permanent
sudo firewall-cmd --add-port=3478/tcp --permanent
sudo firewall-cmd --permanent --add-port=49160-49200/udp
sudo firewall-cmd --reload
만약 서버에 firewalld 방화벽이 활성화되어 있다면
위 명령어를 통해 coturn 관련 포트들을 개방해 주어야 합니다 🔥🔥
Janus 설정 파일 수정
cd <Janus 설정 파일 경로>
vi janus.jcfg
nat: {
// STUN 서버 설정
// 앞서 구축한 coturn 서버의 IP와 기본 포트(3478)를 지정합니다.
stun_server = "<고정 IP>"
stun_port = 3478
// 2. Trickle ICE 설정
// 후보자(Candidate)가 수집되는 대로 즉시 전송하여 연결 속도를 높입니다.
full_trickle = true
// 3. NAT 1:1 매핑 ⭐
// Janus 서버가 사설망에 있을 경우, 외부에서 접근 가능한 대표 IP를 명시합니다.
nat_1_1_mapping = "<고정 IP>"
// 4. TURN 서버 설정 (Relay용)
// P2P 연결이 불가능할 때 데이터를 중계할 TURN 서버 정보를 입력합니다.
turn_server = "<고정 IP>"
turn_port = 3478
turn_type = "udp"
// 5. TURN 인증 정보
// turnserver.conf에서 'user' 항목에 설정한 계정 정보를 입력합니다.
turn_user = "<계정>"
turn_pwd = "<비밀번호>"
// 6. 인터페이스 무시 목록
// 가상 환경(VMware 등) 사용 시 불필요한 가상 네트워크 카드의 IP 수집을 방지합니다.
ice_ignore_list = "vmnet"
}
※ 수정한 항목에 대해서만 작성하였습니다.
sudo systemctl restart janus
설정 파일을 수정한 후 변경 사항을 적용하려면 Janus 서비스를 재시작해야 합니다.
시스템 환경에 따라 명령어가 다를 수 있지만
저처럼 systemd 서비스로 등록해 관리하고 있다면 위 명령어를 입력하여 Janus 서비스를 재시작합니다.
👏👏 이제 모든 설정이 끝났습니다 👏👏
외부망이 차단된 폐쇄망 환경에서도 자체 구축한 coturn 서버를 통해
ICE Candidate가 정상적으로 수집되는 것을 확인할 수 있었습니다.
구글 STUN 서버에 의존할 수 없는 상황이라도 직접 중계 서버를 세팅함으로써
WebRTC 스트리밍 환경을 구현할 수 있습니다(๑´ ̫ `๑)