WebRTC 이중 NAT 검은 화면 디버깅 — P2P를 성공으로 오판할 때 미디어 기반 릴레이 강제 전환

연결 5단계는 다 통과하는데 영상만 검은 화면. 이중 NAT VM에서 ICE가 P2P를 성공으로 오판해 릴레이로 넘어가지 않던 문제를, '연결 성공'이 아니라 '실제 미디어 도착'을 기준으로 릴레이 전환하도록 고친 트러블슈팅.

증상

특정 외부망(가정용 회선)에서 이중 NAT VM 원격제어 시, 연결 5단계는 다 통과하는데 영상만 검은 화면. 같은 VM을 다른 경로(내부·모바일 테더링·다른 사무실)에서는 정상.

관측 (실측)

접속 경로결과흐름도
내부(사내망)✅ 영상coturn 192.168.0.2 UDP 릴레이
모바일 테더링✅ 영상coturn(:3184) UDP 릴레이
다른 사무실(고정 외부망)✅ 영상coturn(:3184) UDP 릴레이 (10ms)
가정용 회선❌ 검정P2P / ? · 지표 전부 공란
  • 가정용 회선에서도 일반 노드(단일 NAT)는 정상 — VM만 실패.
  • 외부 coturn 릴레이 자체는 멀쩡(테더링·다른 사무실이 증명). 특정 회선만 이상.

원인

  • VM은 NAT가 한 겹 더 있어 P2P 홀펀칭 불가 → 릴레이 필수 노드.
  • 문제 회선은 P2P에 고착되어 coturn 릴레이로 넘어가지 않는다. ICE는 P2P(host/srflx)를 릴레이보다 우선하는데, 미디어가 실제로 안 흘러도 P2P를 성공으로 오판해 릴레이 fallback을 하지 않음.
  • 다른 사무실은 P2P가 깔끔히 실패 → 릴레이로 전환 → 정상. 문제 회선은 P2P가 "붙은 것처럼" 되어 릴레이 미전환 → VM은 미디어 0 → 검정.

기여 요인 — 사설 대역 재사용 충돌: 크레덴셜 iceServers에 사설 stun/turn:192.168.0.2가 섞여 있는데, 문제 LAN이 192.168.0.x이고 192.168.0.2가 그 내부의 다른 서버라, STUN/TURN이 우리 coturn이 아닌 엉뚱한 서버로 새어 잘못된 후보를 생성. (같은 사설 대역을 여러 사업장이 재사용하므로 주소만으론 구분 불가.)

수정

1차 — 미디어 기반 릴레이 능동 전환 (브라우저)

ICE가 붙어도 ~3초 안에 프레임(미디어)이 안 오면 → 릴레이(iceTransportPolicy: 'relay')로 재연결.

  • 이중 NAT VM·문제 회선: P2P는 붙지만 미디어 0 → 릴레이 전환 → 정상 경로로 붙음 → 영상.
  • 일반 노드·UDP 되는 망: 프레임 즉시 도착 → 전환 없음. UDP P2P 그대로(빠름).

판단 기준은 연결 성공 여부가 아니라 실제 미디어 도착. "무조건 릴레이/TCP"가 아니라 "P2P가 영상을 못 나르면 그때 릴레이". 재전환은 1회(릴레이도 실패면 종료 — 무한 재연결 금지).

  • 파일: web/manager-web/.../tabs/RemoteControlTab.tsx

2차 — 사설 coturn 주소 정리 (후속)

충돌의 근본. 사설 raw IP(192.168.0.2) 대신 이름 기반/위치 인지로 관리 → 외부 클라이언트가 사설 후보를 받지 않게. 단 "무조건 외부 전환" 금지 — 매니저·노드가 각자 위치에서 닿는 coturn을 능동 선택(둘 다 내부면 사내 coturn). 이름 기반이면 "둘 다 주고 각자 해석"이라 능동 스위칭 원칙을 유지한다.

지원 조건 (명문화)

  • 최소 요건: outbound TCP/UDP 3184 도달.
  • 그마저 막는 망(80/443만 허용 등)은 지원 안 함(TLS 443은 필요 시 후속).
  • 이 조건 안에서는 결정적으로 붙는다가 목표(best-effort 아님).

검증

  • 문제 회선에서 최종 확인(VM 영상). 내부·다른 사무실은 회귀 없어야 한다.
  • 1차만으로 문제 접속 해결. 2차는 엉뚱한 P2P 후보 자체를 제거해 더 깔끔.

Orange Platform 원격 화면 제어의 WebRTC 연결 안정화 트러블슈팅 리포트입니다.