WebRTC에서 “연결이 왜 안 되지?”라는 문제를 파고들면 결국 ICE(Interactive Connectivity Establishment) 과정과 마주하게 된다. ICE는 두 단말이 서로 통신 가능한 경로 후보(candidate)를 수집하고, 그중 최적의 경로를 선택하여 연결하는 절차다.
COTURN은 ICE 과정에서 필요한 STUN/TURN 서버 역할을 수행하는 대표적인 오픈소스 구현체다. P2P가 가능한 환경에서는 연결을 빠르고 간편하게 만들고, P2P가 불가능한 환경에서는 Relay(중계) 경로를 제공해 연결 실패를 막아주는 안전장치 역할을 한다.
이 문서는 Coturn을 Docker 기반으로 배포하고, 방화벽·포트 제한 환경에서도 안정적으로 운영할 수 있도록 설정한 뒤, Trickle ICE를 통해 relay 후보(typ relay)까지 검증하는 과정을 정리한다.
1.1 COTURN이 하는 일 (ICE 관점)
ICE는 크게 세 가지 후보를 수집한다.
Host candidate: 단말의 로컬 IP (동일 네트워크 내 통신 시 사용)
Srflx(Server Reflexive) candidate: STUN을 통해 확인한 “외부에서 보이는 IP/Port” 후보
Relay candidate: TURN 서버를 통해 미디어를 중계하는 후보
COTURN은 이 중 STUN 기능으로 srflx 후보를 생성하고, TURN 기능으로 relay 후보를 생성한다. 실제 운영 시 P2P(srflx)에만 의존하면 연결 성공률이 불안정해질 수 있으므로, TURN을 통해 성공률을 보장하는 인프라를 구축하는 것이 핵심이다.
1.2 STUN으로 NAT 넘어보기 (P2P)
대부분의 클라이언트는 사설 IP를 사용하는 NAT 환경 뒤에 있다. 이 상태에서는 상대 피어가 로컬 주소로 직접 접속할 수 없다. 그래서 ICE는 STUN을 통해 “외부에서 보이는 나의 주소”를 먼저 확인한다.
과정은 다음과 같다.
클라이언트 → STUN 서버로 요청
STUN 서버 → “외부에서는 <공인 IP:포트>로 보인다”라고 응답
클라이언트는 이를 srflx candidate로 등록
이 방식이 정상 동작하면 미디어는 TURN을 거치지 않고 P2P로 직접 전달된다. 레이턴시와 서버 비용 측면에서도 가장 유리하다.
하지만 STUN은 어디까지나 “주소를 알아내는 단계”일 뿐이다. NAT 유형이나 방화벽 정책에 따라 후보는 수집되지만 실제 미디어 경로는 성립하지 않는 경우가 자주 발생한다.
1.3 연결 정책이 복잡하다면? “TURN” (RELAY)
현실 환경에서는 다음과 같은 상황이 빈번하게 발생한다.
기업·학교 망에서 UDP가 제한되거나 차단됨
Symmetric NAT 구조로 외부 매핑이 까다로운 환경
공용 Wi-Fi처럼 임의 포트가 쉽게 차단되는 네트워크
이때 TURN은 사실상 우회 경로 역할을 한다.
클라이언트가 TURN 서버에 인증 후 relay allocation을 요청한다.
두 단말은 서로 직접 통신하지 않는다.
TURN 서버가 중간에서 미디어를 중계한다.
“STUN은 가능성을 높이고, TURN은 실패를 막는다.”
이 문서의 최종 목표도 여기에 있다. 어떤 네트워크 환경에서도 relay 후보가 안정적으로 생성되고, 실제 연결까지 이어지는지를 검증하는 것이다.
2. 언제 TURN이 필요한가? (결정 기준)
WebRTC에서는 “되면 P2P가 최고”다. 하지만 서비스 관점에서는 “안 되는 환경이 언제, 얼마나 자주 발생하느냐”가 더 중요하다. STUN만 구성하면 특정 네트워크에서 연결이 실패하거나 성공률이 사용자 환경에 따라 크게 흔들릴 수 있다.
따라서 TURN은 성능 옵션이 아니라 가용성(availability)을 보장하기 위한 보험으로 보는 편이 정확하다.
2.1 STUN만으로 충분한 경우
사용자가 주로 가정용 공유기나 일반 모바일 환경을 이용할 때
UDP 통신이 대부분 허용될 때
Symmetric NAT 비율이 낮을 때
2.2 TURN이 필요한 대표 케이스
(1) Symmetric NAT 환경
Symmetric NAT는 외부 매핑이 통신 대상(IP/Port)에 따라 달라진다. 이로 인해 STUN으로 얻은 srflx 후보가 상대 피어에게 그대로 유효하지 않은 경우가 발생한다. 이 환경에서는 TURN relay가 사실상 유일한 해결책이다.
참고로 NAT는 Static/Dynamic, SNAT/DNAT 등 다양한 기준으로 분류되지만, WebRTC 성공률 관점에서는 Cone 타입과 Symmetric 타입 구분이 가장 직접적인 영향을 준다.
(2) 기업·학교·공공기관 망
UDP 제한, 특정 포트만 허용되는 경우가 많다. TURN over TCP/TLS까지 준비하면 성공률이 눈에 띄게 개선된다.
(3) 정책이 자주 변하는 공용 Wi-Fi
어제는 되던 연결이 오늘은 실패하는 환경이다. TURN은 이런 변동성을 흡수하는 역할을 한다.
(4) 허용 포트가 제한된 환경
min-port/max-port를 통한 포트 범위 고정과 방화벽 정책의 1:1 매칭이 필요하다.
2.3 서비스 관점 결론: TURN은 보험이다
실무적으로 선택지는 세 가지다.
STUN only
내부 테스트나 PoC에는 가능
실서비스에는 리스크가 큼
STUN + TURN(UDP)
기본적으로 추천되는 구성
UDP 제한 환경에서는 여전히 실패 가능
STUN + TURN(UDP + TCP + TLS)
성공률 최우선 구성
운영 복잡도는 증가
실서비스에서는 STUN + TURN(UDP + TCP + TLS) 조합을 가장 권장한다. 이는 운영 복잡도는 증가하지만, 어떤 네트워크 환경에서도 연결 성공률을 극대화할 수 있는 가장 안전한 선택지다.
“될 때는 P2P, 안 되면 반드시 relay로 살린다.”
3. 전체 구성 & 네트워크 요구사항
TURN/STUN은 서버만 띄운다고 끝나지 않는다. 어떤 포트와 프로토콜로 접근하는지, 미디어가 어떤 포트 대역으로 흐르는지가 핵심이다.
3.1 구성 요소 (Architecture)
Client A / Client B: WebRTC 피어(브라우저 또는 앱)
Signaling 서버(WSS/HTTPS): SDP·ICE 후보 교환
Coturn 서버: STUN/TURN 역할 수행
흐름은 다음과 같다.
Signaling으로 SDP 교환
ICE 후보(host/srflx/relay) 수집
P2P 가능 시 직접 연결
실패 시 TURN relay를 통해 중계
Signaling은 제어 경로이고, Coturn은 ICE 및 미디어 경로를 담당한다.
3.2 포트 & 프로토콜 요구사항
제어/할당 포트: 3478 (UDP/TCP)
TLS(turns): 5349/TCP
Relay 미디어 포트: min-port ~ max-port 범위
가장 흔한 장애는 3478은 열려 있지만 relay 포트 범위가 막혀 있는 경우다. 이 경우 relay 후보는 생성되지만 실제 연결은 실패한다.
3.3 방화벽/보안그룹 정책 예시
용도
프로토콜
포트
방향
비고
STUN/TURN 기본
UDP
3478
Inbound
srflx/relay 영향
TURN over TCP
TCP
3478
Inbound
UDP 제한 fallback
TURN over TLS
TCP
5349
Inbound
turns(성공률 옵션)
Relay 미디어
UDP
50000-50100
Inbound
min-port~max-port와 동일
(선택) 관리/모니터링
TCP
조직 정책
Inbound
별도 네트워크 권장
Outbound 정책이 있는 환경이라면 별도 협의가 필요하다.
3.4 NAT/LB 환경의 핵심 (external-ip)
서버가 NAT 또는 LB 뒤에 있다면 Coturn이 내부 IP를 candidate로 광고할 수 있다. 클라이언트가 실제로 접속하는 공인 IP와 광고되는 주소는 반드시 일치해야 한다.
대표 증상은 다음과 같다.
relay 후보는 보이는데 ICE failed
특정 네트워크에서만 연결 실패
결론적으로 NAT/LB 환경에서는 external-ip 설정이 필수다.
3.5 체크리스트
UDP 제한 대비 TCP/TLS fallback 고려
3478/5349 및 relay 포트 범위 방화벽 허용
min-port/max-port와 방화벽 정책 일치
NAT/LB 환경이면 external-ip 설정
4. 오픈소스 세팅 레시피
목표는 다음과 같다.
Coturn을 컨테이너 기반으로 운영
relay 포트 범위를 제한해 방화벽 정책과 정합
TCP/TLS 확장과 운영 안정성 확보
4.1 Docker 이미지 구축 가이드
운영 환경에서는 검증된 Coturn 이미지를 사용하고, 설정 파일과 인증서를 볼륨으로 주입하는 방식이 관리 측면에서 유리하다.
listening-port: STUN/TURN 기본 포트다. 일반적으로 3478을 사용한다.
realm: long-term credential 인증의 기준 값이다. 운영 환경에서는 서비스 도메인을 기준으로 고정하는 것이 좋다.
lt-cred-mech / user: 장기 인증 방식이다. MVP 단계에서는 정적 유저로 시작할 수 있지만, 운영 환경에서는 turnadmin 기반 관리가 권장된다.
fingerprint / no-loopback-peers / no-multicast-peers: 기본적인 안전 옵션이다. 불필요한 트래픽과 오남용 가능성을 줄여준다.
이 구성만으로도 STUN 및 TURN allocation 자체는 가능하다. 다만 실서비스에 바로 적용하기에는 부족하다.
5.2 운영용 추천 베이스
relay 포트 범위(min-port/max-port)는 방화벽 허용 범위와 반드시 동일해야 하며, 서버가 NAT/LB 뒤에 있다면 external-ip를 설정해 candidate에 광고되는 주소가 클라이언트가 접속하는 공인 주소와 일치하도록 맞춰야 한다. 또한 기업망/공공망처럼 UDP 제약이 있는 환경을 대비하려면 turns(5349/TCP)와 인증서(cert/pkey)를 준비해 TLS fallback까지 확보하는 편이 안정적이다.
# /etc/turnserver.conf (Recommended)# TURN/STUN + TURNS포트listening-port=3478tls-listening-port=5349# Identityrealm=example.comserver-name=coturn-example# Auth (운영에서는turnadmin권장)lt-cred-mechuser=testuser:testpassword# NAT/LB환경이면설정 (공인/사설주소정합)# external-ip=<PUBLIC_IP> # 공인 IP 직결# external-ip=<PUBLIC_IP>/<PRIVATE_IP> # NAT/LB 뒤(공인/사설 분리)# external-ip=<PUBLIC_IP>/<PRIVATE_IP># Relay 포트 범위 (방화벽과 1:1 매칭)min-port=50000max-port=50100# TLS(turns)cert=/etc/ssl/certs/fullchain.pempkey=/etc/ssl/private/privkey.pem# Securityfingerprintno-loopback-peersno-multicast-peers# no-cli # 운영 정책에 따라
이 설정의 핵심 포인트는 다음과 같다.
relay 포트 범위는 반드시 방화벽 정책과 동일해야 한다.
NAT/LB 뒤에 있다면 external-ip 설정은 선택이 아니라 필수다.
UDP 제한 환경을 대비해 turns(5349/TCP)를 함께 열어두는 것이 안전하다.
운영에서 흔한 함정은 다음과 같다. TLS 인증서 경로/권한 문제로 turns만 실패하거나, relay 범위 방화벽 미허용으로 relay가 실패하거나, external-ip 문제로 후보는 나오는데 연결이 실패하는 경우다.
6. Docker 실행 및 정상 가동 확인
TLS 인증서 경로/권한 → turns만 실패
relay 범위 방화벽 미허용 → relay 실패
external-ip 문제 → 후보는 나오는데 연결 실패
TURN 서버는 “컨테이너가 떠 있다”와 “실제로 연결이 된다”가 완전히 다른 문제다. 운영 중 가장 흔한 문제는 설정은 맞아 보이는데 실제 연결이 실패하는 상황이다.
6.1 실행 및 상태 확인
dockercomposeup -ddockercomposeps
컨테이너 상태 확인 후 로그를 바로 확인하는 것이 좋다.
dockerlogs -fcoturn
6.2 포트 리스닝 확인
ss -lntup | grep -E'3478|5349'
여기서 주의할 점은 relay 포트다. relay 포트는 allocation이 발생했을 때 동적으로 사용되므로, 항상 리스닝 상태로 보이지 않을 수 있다. 따라서 단순 포트 체크만으로는 충분하지 않다. 이후 TURN allocation/Trickle ICE로 검증한다.
6.3 기능 검증 핵심: STUN → TURN
운영에서 자주 발생하는 착각은 다음과 같다.
STUN이 된다 = TURN도 된다 ❌
TURN은 allocation 단계가 정상적으로 완료되어야 relay 후보가 안정적으로 생성된다. 이 단계를 반드시 별도로 검증해야 한다.
6.4 빠른 진단 가이드
증상
주요 원인
turns(TLS) 접속 실패
인증서 경로/권한 문제 또는 5349 포트 미개방
relay 후보 미생성
인증 정보(ID/PW) 불일치 또는 3478 포트 접근 불가
후보는 나오지만 연결 실패
external-ip 설정 오류 또는 relay 범위 방화벽 차단
7. Trickle ICE 테스트 방법
TURN 서버가 “정말로 준비되었는지”를 확인하는 가장 확실한 방법은 Trickle ICE 테스트다. 로그보다 빠르고, 클라이언트 관점에서 결과를 바로 확인할 수 있다.