TUN 모드는 Android의 VpnService로 가상 인터페이스를 만들어 기기 트래픽을 통째로 v2rayNG 내장 Xray 코어에 넘깁니다. 글은 네 단계로 진행합니다. 먼저 기본 로컬 프록시와의 차이를 비교하고, 데이터 경로를 뜯어본 뒤, 활성화와 권한 승인 순서를 제시하고, 마지막으로 재현 가능한 세 가지 점검으로 적용 범위를 확인하면서 백그라운드 생존과 DNS 해석의 흔한 함정을 짚습니다.
TUN 모드와 기본 로컬 프록시의 차이
v2rayNG의 기본 연결 방식은 로컬에 인바운드 두 개만 엽니다. SOCKS는 127.0.0.1:10808, HTTP는 127.0.0.1:10809입니다. 프록시 설정을 읽는 앱(브라우저, 일부 다운로드 도구)만 요청을 이 두 포트로 보내고 나머지 앱은 그대로 직접 연결합니다. Android에도 모든 앱에 적용되는 전역 프록시 스위치는 없으며, Wi-Fi 고급 옵션의 프록시는 그 설정을 따르는 앱에만 적용됩니다.
TUN 모드는 경로가 다릅니다. v2rayNG가 Android VpnService로 가상 인터페이스를 요청하면 시스템이 기기에서 나가는 IP 패킷을 이 인터페이스에 기록하고, 앱 쪽에서는 프록시 주소를 입력할 필요가 없습니다. 인터페이스에 들어온 패킷은 내장 tun2socks 포워딩 컴포넌트로 넘어가 TCP 연결과 UDP 세션으로 복원된 뒤, SOCKS5로 Xray 코어에 전달되어 분기됩니다.
| 비교 항목 | 기본 로컬 프록시 | TUN 모드 |
|---|---|---|
| 적용 대상 | 프록시를 직접 설정하는 앱 | 기기의 모든 IP 트래픽, 앱별 필터링 가능 |
| 앱 설정 | 127.0.0.1:10808 입력 필요 | 불필요 |
| DNS 처리 | 앱이 직접 해석 | 트래픽과 함께 코어로 들어가 도메인 해석 전략에 따라 처리 |
| 권한 | 없음 | 시스템 VPN 권한 필요 |
| 전력 소모 | 낮음 | 약간 높음, 사용자 공간 포워딩 한 단계 추가 |
| 대표 시나리오 | 브라우저와 프록시 지원 도구 | 프록시 설정을 지원하지 않는 앱, 전역 적용이 필요한 경우 |
데이터 경로: 앱에서 아웃바운드까지
TUN 모드에서 요청 하나는 다섯 단계를 거치며, 각 단계를 따로 점검할 수 있습니다.
앞의 두 단계는 시스템과 포워딩 컴포넌트가 처리합니다. VpnService가 인터페이스를 만들면 기본 라우트 0.0.0.0/0이 이 인터페이스를 가리키고, 앱이 보낸 연결은 패킷 단위로 TUN에 기록됩니다. tun2socks는 인터페이스에서 원본 IP 패킷을 읽어 TCP 연결과 UDP 세션으로 복원한 뒤 SOCKS5(UDP ASSOCIATE 포함)로 127.0.0.1:10808에 넘깁니다.
뒤의 세 단계는 Xray 코어에서 처리합니다. 요청이 socks 인바운드로 들어오면 먼저 routing 규칙과 매칭되고, 그다음 outbound 프록시로 보낼지 freedom 직접 연결로 보낼지 결정합니다. 도메인을 언제 IP로 해석할지는 「설정」의 「도메인 해석 전략」이 정합니다. IPIfNonMatch를 고르면 도메인으로 먼저 규칙을 매칭하고 매칭되지 않을 때만 해석을 시작하므로 불필요한 DNS 조회를 한 번 줄일 수 있습니다. AsIs는 도메인 기준으로만 매칭하고, IPOnDemand는 IP 규칙을 만났을 때만 해석합니다.
{
"inbounds": [
{ "tag": "socks", "listen": "127.0.0.1", "port": 10808, "protocol": "socks", "settings": { "udp": true } },
{ "tag": "http", "listen": "127.0.0.1", "port": 10809, "protocol": "http" }
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{ "type": "field", "outboundTag": "direct", "ip": ["geoip:private"] },
{ "type": "field", "outboundTag": "direct", "domain": ["geosite:cn"] }
]
}
}
위에서 인용한 부분은 인바운드와 라우팅 두 구간이며, outbounds와 구체적인 노드는 가져온 구독에서 생성됩니다. TUN 모드에 새 프로토콜이 추가되는 것은 아닙니다. 인터페이스에서 나온 트래픽은 결국 10808 SOCKS 인바운드를 거치고, 핸드셰이크와 암호화 방식은 전적으로 노드가 결정합니다. VMess, VLESS, Trojan, SS 모두 마찬가지입니다.
TUN 모드 활성화 순서
아래 순서는 v2rayNG 1.9.x의 중국어 인터페이스 기준입니다. 일부 버전은 메뉴 문구가 한두 글자 다를 수 있지만 단계 자체는 같습니다.
- 먼저 구독을 가져오고 노드가 사용 가능한지 확인합니다. 노드 행 오른쪽 메뉴에서 「실제 연결 지연 테스트」를 실행하고, 지연이 -1로 표시되는 노드는 핸드셰이크 실패이므로 먼저 연결되는 노드로 바꿉니다. 노드 문제를 TUN 문제로 오판하지 않기 위해서입니다.
- 사이드바 → 「설정」을 열고 연결 방식이 VPN(TUN) 모드인지 확인합니다. v2rayNG는 VpnService로 가상 인터페이스를 만들며, 일부 버전은 여기가 「VPN 모드」 스위치이고 일부 버전은 별도 스위치 없이 연결을 누르면 바로 VpnService를 사용합니다. 이후 단계에는 영향이 없습니다.
- 사이드바 → 「라우팅 설정」 → 「사전 정의 규칙」에서 「LAN 및 중국 본토 우회」를 선택합니다. 내부 네트워크 기기와 중국 본토 사이트는 direct로 가고, 프록시가 필요한 트래픽만 노드로 들어갑니다.
- 「설정」 → 「도메인 해석 전략」에서 IPIfNonMatch를 선택합니다. 이 옵션은 도메인이 규칙 매칭의 어느 단계에서 해석되는지를 정하며, 뒤에서 DNS를 확인할 때 사용합니다.
- 앱별로 제어해야 한다면 「설정」 → 「앱별 프록시」로 들어가 스위치를 켜고 「선택한 앱만 프록시」 또는 「선택한 앱 우회」를 고른 뒤 앱 목록에서 대상 앱을 체크합니다.
- 메인 화면으로 돌아가 연결을 누릅니다. 처음에는 시스템의 「연결 요청」 대화상자가 뜨는데 「허용」을 누릅니다. 이후 상태 표시줄에 VPN 열쇠 아이콘이, 알림창에 v2rayNG 실행 알림이 나타나면 적용이 시작된 것입니다.
앱별 프록시와 TUN은 같은 계층의 메커니즘
앱별 프록시는 별도의 두 번째 통로가 아닙니다. TUN과 같은 VpnService를 사용하며, 허용 목록과 제외 목록은 시스템이 VPN 계층에서 걸러내므로 제외된 앱의 트래픽은 가상 인터페이스에 들어오지 않고 자연히 Xray에도 들어가지 않습니다. 따라서 TUN을 켠 상태에서 앱별 프록시를 켜도 이중 프록시가 되지 않고 적용 범위만 좁아집니다.
권한과 백그라운드 생존
권한은 시스템 계층에 있지만 생존은 제조사 백그라운드 정책에 달려 있습니다. 중국 제조사 ROM은 화면이 꺼진 뒤 몇 분이 지나면 VPN 서비스를 회수하는 경우가 많고, 상태 표시줄 열쇠 아이콘이 사라지거나 트래픽 통계가 더 이상 늘지 않거나 앱을 다시 열었을 때 연결 상태가 이미 끊김으로 돌아가 있는 식으로 나타납니다.
- 배터리: 시스템 「설정」 → 「앱」 → 「v2rayNG」 → 「배터리」에서 「제한 없음」을 고르거나 배터리 최적화를 끕니다.
- 자동 시작: 「자동 시작 관리」에서 v2rayNG의 자동 시작을 허용하고, 최근 작업 화면에서 앱을 잠가 일괄 정리할 때 종료되지 않게 합니다.
- 백그라운드 팝업: v2rayNG가 「연결 요청」을 띄울 때 시스템이 막지 않아야 하며, 이 권한을 허용하면 권한 승인 실패를 줄일 수 있습니다.
- 항상 켜진 VPN: Android 7.0부터 「설정」 → 「네트워크 및 인터넷」 → 「VPN」에 「항상 켜진 VPN」이 있어 v2rayNG를 상시 유지로 지정하면 연결이 끊긴 뒤 시스템이 다시 띄웁니다.
- VPN 없이 연결 차단: 같은 화면의 이 항목은 VPN이 끊기면 모든 트래픽을 차단하므로 디버깅 단계에서는 켜지 않는 편이 좋습니다. 그렇지 않으면 네트워크 단절 원인을 혼동하게 됩니다.
결론: 백그라운드 설정을 먼저, 규칙은 그다음
같은 설정이 기기마다 다르게 동작하는 이유는 대부분 코어가 아니라 백그라운드 생존 정책에 있습니다. 배터리 최적화 해제, 자동 시작, 백그라운드 잠금 세 가지를 설정하고 하루 정도 지켜본 뒤에 DNS와 라우팅 규칙을 점검하세요. 순서를 뒤집으면 많은 시간을 낭비하게 됩니다.
적용 범위 확인
연결 상태는 VpnService가 연결되었다는 것만 알려줄 뿐 트래픽이 실제로 코어에 들어갔는지는 알려주지 않습니다. 재현 가능한 세 가지 점검으로 적용 범위를 확인합니다.
- 출구 주소 비교: 먼저 브라우저로 출구 IP를 표시하는 페이지에 접속해 직접 연결 상태의 결과를 기록합니다. TUN에 연결한 뒤 같은 페이지에 접속하면 IP가 노드가 위치한 지역의 주소로 바뀌고 통신사 항목도 함께 바뀌어야 합니다.
- 앱별 프록시 반증: 「앱별 프록시」에서 특정 앱을 우회로 지정하고 그 앱을 다시 열면 로컬 IP가 표시되어야 합니다. 체크를 해제하고 다시 열면 노드 IP가 표시되어야 합니다. 두 결과가 다르면 TUN의 앱 단위 필터링이 동작하는 것입니다.
- 트래픽 통계: 「설정」 → 「트래픽 통계 사용」을 켜고 연결한 뒤 통계 화면에서 업로드와 다운로드가 브라우징에 따라 늘어나는지 봅니다. 숫자가 움직이지 않으면 트래픽이 코어에 들어가지 않은 것입니다.
자주 묻는 문제와 점검
v2rayNG 연결을 끊었는데 상태 표시줄 열쇠 아이콘이 남아 있나요?
열쇠 아이콘은 시스템 VPN 프레임워크가 그립니다. 먼저 v2rayNG 메인 화면에서 한 번 연결을 끊으면 아이콘은 VpnService와 함께 사라집니다. 그래도 남아 있다면 시스템 「설정」 → 「네트워크 및 인터넷」 → 「VPN」에서 다른 구성이 연결 상태인지 확인하고 하나씩 끊습니다.
TUN을 켰는데 특정 앱이 여전히 로컬 IP를 표시하나요?
먼저 「설정」 → 「앱별 프록시」를 봅니다. 모드가 「선택한 앱 우회」라면 목록에서 체크된 앱이 프록시를 타지 않는 앱이고, 「선택한 앱만 프록시」라면 체크되지 않은 앱이 프록시를 타지 않습니다. 두 모드를 각각 확인한 뒤 해당 앱을 다시 열어 재측정합니다.
브라우저 확장 프로그램에 127.0.0.1:10808이 그대로 입력되어 있는데 바꿔야 하나요?
지우는 편이 좋습니다. 남겨 두면 요청이 확장 프로그램을 통해 먼저 로컬 인바운드로 들어가 TUN의 앱 단위 필터링을 우회합니다. 앱별 프록시에서 브라우저를 제외했는데 확장 프로그램 계층은 여전히 프록시를 타면 점검할 때 서로 모순된 결론에 도달하게 됩니다.
연결할 때 시스템이 「연결 요청」을 띄우는데, 취소를 누르면 다시 뜨나요?
뜹니다. 다음에 연결을 누르면 권한을 다시 요청하며, 한 번 취소했다고 영구히 거부되지 않습니다. 팝업이 아예 나타나지 않는다면 시스템 VPN 목록에서 v2rayNG 항목을 삭제하고 다시 연결하면 권한 절차가 처음부터 다시 진행됩니다.
TUN 모드가 로컬 프록시보다 배터리를 더 많이 쓰나요?
조금 더 씁니다. 추가되는 비용은 tun2socks의 사용자 공간 포워딩과 메모리 복사 한 번이며, 오래 백그라운드에 둘수록 차이가 커집니다. 브라우저에서만 쓴다면 TUN을 끄거나, 앱별 프록시로 범위를 필요한 앱까지 좁히세요.
점검 순서는 고정해 두는 편이 좋습니다. 먼저 백그라운드에서 살아 있는지, 다음으로 라우팅 규칙이 대상 트래픽을 직접 연결로 보내는지, 마지막으로 DNS가 어디서 해석되는지 봅니다. 세 단계를 모두 통과했는데도 안 된다면 노드 자체로 돌아가 실제 연결 지연 테스트를 한 번 합니다.