01 / JSON STRUCTURE
설정 파일 구조 개요
먼저 트래픽 방향으로 최상위 객체 이해하기
V2Ray와 Xray 설정 파일은 보통 하나의 JSON 객체로 구성됩니다. 먼저 기억해야 할 것은 필드 수가 아니라 트래픽의 흐름입니다. 애플리케이션이 로컬 인바운드 리스너에 연결하면 커널이 라우팅 규칙을 읽고 아웃바운드를 선택한 뒤, 해당 아웃바운드를 통해 대상과 연결합니다. DNS는 도메인을 주소로 변환하고, policy는 세션 타임아웃과 통계 같은 실행 정책을 관리하며, log는 로그의 저장 위치와 기록 수준을 결정합니다.
inbounds와 outbounds가 배열인 이유는 하나의 인스턴스가 여러 로컬 포트를 동시에 리슨하고 여러 출구를 준비할 수 있기 때문입니다. 배열의 각 객체는 보통 tag로 이름을 붙이고, 라우팅 규칙에서 이 태그를 참조합니다. 태그는 인스턴스 내부 식별자일 뿐 원격으로 전송되지 않습니다. 이름은 직접 정할 수 있지만 짧고 일관되며 용도를 알 수 있게 작성하세요. 예를 들면 socks-in, proxy, direct, block 등이 있습니다.
읽기 편한 설정 순서는 로그, DNS, 인바운드, 아웃바운드, 라우팅, 정책 순입니다. JSON 자체는 이 순서를 요구하지 않지만, 배열 순서를 고정하면 문제 해결 시간이 줄어듭니다. 시작에 실패했을 때 파일 처음부터 아래로 확인하기 쉽고, 두 설정을 비교할 때 변경 사항도 빠르게 찾을 수 있습니다. 그래픽 클라이언트가 다른 순서로 생성하더라도 계층과 필드가 유효하다면 객체 키의 순서 때문에 실행 결과가 달라지지는 않습니다.
{
"log": {
"loglevel": "warning"
},
"dns": {},
"inbounds": [],
"outbounds": [],
"routing": {},
"policy": {}
}
JSON 문법과 설정 의미는 별도로 점검해야 합니다
설정이 JSON으로 파싱된다는 것은 괄호, 따옴표, 쉼표와 데이터 형식이 문법에 맞다는 뜻일 뿐, 현재 커널이 모든 필드를 받아들인다는 의미는 아닙니다. 예를 들어 포트를 문자열로 작성하면 유효한 JSON일 수 있지만 해당 필드가 요구하는 정수 형식에는 맞지 않을 수 있습니다. 아웃바운드 태그의 철자가 다르면 라우팅 매칭 시점에야 문제가 드러나기도 합니다. 문제를 해결할 때는 먼저 JSON 파싱 여부를 확인한 다음, 커널 로그에서 알 수 없는 필드, 형식 오류, 태그 누락 또는 프로토콜 설정 불완전 관련 메시지를 확인하세요.
표준 JSON에서는 주석을 사용할 수 없고, 객체나 배열의 마지막 항목 뒤에 불필요한 쉼표를 둘 수도 없습니다. 예제를 복사할 때 특히 주의하세요. 문서의 조각은 설명을 위한 것이므로 올바른 상위 객체에 넣어야만 작동합니다. 예를 들어 routing 객체만 따로 복사했다면 최상위 "routing" 값으로 넣어야 하며 파일 끝에 그대로 붙여 넣으면 안 됩니다. 문자열은 큰따옴표를 사용하고 불리언 값은 true 또는 false로 작성해야 하며 따옴표로 감싸면 안 됩니다.
| 필드 | 데이터 형식 | 주요 역할 | 주요 점검 항목 |
|---|---|---|---|
log |
객체 | 액세스 로그, 오류 로그와 기록 수준 제어 | 경로 권한, 로그 수준이 너무 낮지 않은지 |
inbounds |
배열 | 브라우저, 시스템 또는 로컬 네트워크 기기에서 들어오는 연결 수신 | 리스닝 주소, 포트 사용 여부, 프로토콜 유형 |
outbounds |
배열 | 프록시, 직접 연결, 차단 등의 출구 정의 | 서버 매개변수, 태그, 전송 설정 |
routing |
객체 | 도메인, IP, 포트 또는 인바운드 태그에 따라 출구 선택 | 규칙 순서, 태그 참조, 확인 전략 |
dns |
객체 | 해석 서버, 정적 매핑과 조회 조건 정의 | 조회 경로, 도메인 매칭, 폴백 동작 |
policy |
객체 | 세션 타임아웃, 트래픽 통계 등의 실행 정책 제어 | 정책 단계, 통계 스위치와 통계 모듈의 연동 |
수정 전 되돌릴 수 있는 기준점 만들기
조정을 시작하기 전에 현재 설정을 수정하지 않은 상태로 한 번 성공적으로 실행하고, 사용 중인 로컬 포트, 시스템 프록시 모드와 커널 이름을 기록하세요. 그런 다음 설정 파일을 복사해 용도가 분명한 파일명을 붙입니다. 한 번에 하나의 논리 단위만 수정하세요. 예를 들어 직접 연결 아웃바운드를 추가하고 확인한 뒤 라우팅 규칙을 넣는 식입니다. 여러 영역을 한꺼번에 바꾸면 빠를 수 있지만 시작 실패가 문법, 태그 또는 프로토콜 매개변수 중 무엇 때문인지 판단하기 어려워집니다.
그래픽 클라이언트는 구독을 업데이트하거나 노드를 전환하거나 커널을 다시 시작할 때 실행 설정을 다시 생성할 수 있습니다. 이때 임시 파일을 직접 편집하면 변경 사항이 오래 유지되지 않을 수 있습니다. v2rayN에서는 클라이언트가 제공하는 사용자 지정 설정, 라우팅 설정 또는 고급 옵션을 우선 사용하세요. Android 클라이언트에서는 현재 설정이 구독 노드에서 온 것인지 수동 설정인지 먼저 확인합니다. 용어의 범위를 더 정확히 이해하려면 용어집도 함께 확인해 ‘인바운드’, ‘시스템 프록시’, ‘라우팅 모드’를 같은 기능으로 오해하지 않도록 하세요.
02 / INBOUNDS
inbounds 인바운드 설정
리스닝 주소가 연결 가능한 범위를 결정합니다
인바운드는 로컬 애플리케이션이 트래픽을 커널에 넘기는 입구입니다. 가장 흔한 로컬 입구는 SOCKS와 HTTP 프록시입니다. listen은 어느 네트워크 주소에서 리슨할지, port는 포트를, protocol은 애플리케이션이 사용할 프록시 프로토콜을 결정합니다. 현재 기기에서만 사용할 때는 리스닝 주소를 127.0.0.1로 설정하는 것이 좋습니다. 이 주소는 로컬 연결만 허용하므로 브라우저, 시스템 프록시와 같은 기기의 다른 프로그램은 사용할 수 있지만 로컬 네트워크의 다른 기기는 직접 접속할 수 없습니다.
같은 로컬 네트워크의 휴대폰, TV 또는 다른 컴퓨터에서 데스크톱 클라이언트를 사용하게 하려면 인바운드는 보통 0.0.0.0 또는 구체적인 로컬 네트워크 주소에서 리슨합니다. 이 경우 시스템 방화벽, 네트워크 유형과 접근 제어도 함께 설정해야 하며 리스닝 주소만 바꾸어서는 안 됩니다. 공유 기기에는 127.0.0.1이 아니라 커널이 실행 중인 컴퓨터의 로컬 네트워크 주소와 인바운드 포트를 입력해야 합니다. 자세한 내용은 v2rayN 로컬 네트워크 연결 허용 설정 가이드를 참고하세요.
{
"inbounds": [
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
},
{
"tag": "http-in",
"listen": "127.0.0.1",
"port": 10809,
"protocol": "http",
"settings": {}
}
]
}
SOCKS, HTTP와 투명 프록시의 차이
SOCKS 인바운드는 SOCKS 프록시를 명시적으로 지원하는 애플리케이션에 적합하며 TCP를 전달하고 설정에 따라 UDP도 처리할 수 있습니다. HTTP 인바운드는 HTTP CONNECT 또는 일반 HTTP 프록시로 연결하는 프로그램에 주로 사용됩니다. 두 방식 모두 애플리케이션이나 시스템 프록시가 해당 포트를 정확히 가리켜야 합니다. 프로그램이 HTTP 프록시로 설정되어 있다면 SOCKS 포트를 가리킬 수 없습니다. 포트는 맞지만 프로토콜 유형이 틀리면 연결이 즉시 끊기거나 브라우저에 프록시 응답 오류가 표시되고, 로그에 인식할 수 없는 핸드셰이크 데이터가 남는 경우가 많습니다.
TUN 모드는 일반 로컬 프록시와 다릅니다. 가상 네트워크 인터페이스로 더 넓은 범위의 시스템 트래픽을 수신하며, 클라이언트에서 라우팅 테이블, DNS 가로채기와 권한도 설정해야 합니다. TUN 설정을 SOCKS 인바운드를 하나 더 추가하는 것으로 이해해서는 안 됩니다. v2rayN은 인터페이스의 TUN 옵션에 따라 실행 매개변수를 구성하므로, 보통 클라이언트 화면에서 먼저 활성화한 뒤 로그를 확인해야 합니다. 다른 환경의 완전한 TUN 조각을 현재 설정에 그대로 붙여 넣지 마세요. 일반 시스템 프록시만으로 브라우저와 일반 데스크톱 프로그램을 사용할 수 있다면 ‘더 많이 적용’하려고 여러 가로채기 방식을 동시에 켤 필요도 없습니다.
sniffing이 도메인 라우팅을 돕는 방식
sniffing은 연결에 포함된 프로토콜 특징에서 대상 도메인을 복원하는 기능입니다. 일부 애플리케이션은 먼저 직접 도메인을 조회한 뒤 IP 주소를 프록시에 전달합니다. 이때 routing에 도메인 규칙만 있다면 커널이 순수 IP만 보게 되어 도메인 매칭을 할 수 없습니다. 스니핑을 활성화하면 HTTP 요청의 호스트 정보나 TLS 핸드셰이크의 서버 이름이 라우팅 모듈의 도메인 식별을 도울 수 있습니다. 예제의 destOverride는 식별된 HTTP 또는 TLS 대상을 사용해 원래 목적지 주소를 덮어쓸 수 있게 하며, 이후 규칙에서 이를 판단할 수 있도록 합니다.
스니핑은 DNS를 대신하지 않으며 모든 연결에서 도메인을 복원할 수 있는 것도 아닙니다. 식별 가능한 호스트 정보가 없는 프로토콜은 여전히 IP로만 표시됩니다. 암호화 핸드셰이크 방식과 애플리케이션 동작도 결과에 영향을 줍니다. 라우팅이 매칭되지 않을 때는 먼저 액세스 로그에 도메인과 IP 중 무엇이 기록되는지 확인한 뒤 domainStrategy 조정, IP 규칙 추가 또는 스니핑 설정 점검 여부를 결정하세요. 로그를 확인하지 않은 채 같은 도메인과 IP 조건을 반복해서 쌓으면 규칙만 관리하기 어려워집니다.
포트, 인증과 태그 설정 원칙
같은 주소의 포트는 두 프로세스가 동시에 사용할 수 없으며, 두 인바운드가 같은 주소와 포트에서 리슨할 수도 없습니다. 클라이언트 시작 직후 주소가 이미 사용 중이라는 메시지가 나오면 중복 실행된 인스턴스를 종료한 뒤 다른 프록시 도구나 이전 커널 프로세스를 확인하세요. 포트만 임의로 바꾸는 것은 충돌의 절반만 해결합니다. 시스템 프록시, 브라우저 확장 프로그램과 로컬 네트워크 기기의 포트도 함께 바꿔야 합니다. 혼동을 줄이려면 SOCKS와 HTTP 포트를 서로 가까운 번호로 정할 수 있지만, 특정 숫자만 보고 프로토콜 유형을 판단해서는 안 됩니다.
auth: "noauth"는 루프백 주소에서만 리슨하는 로컬 SOCKS 인바운드에 적합합니다. 로컬 네트워크 주소에서 리슨할 때는 클라이언트 지원 여부를 고려해 인증과 방화벽 제한을 함께 검토하고 신뢰할 수 있는 네트워크만 접근하도록 하세요. 태그는 각 인바운드에 고유한 이름을 붙여야 이후 inboundTag로 입구마다 다른 라우팅을 설정할 수 있습니다. 예를 들어 로컬 트래픽은 일반 분기 처리를 하고, 로컬 네트워크 공유 입구는 일부 포트만 허용할 수 있습니다. 태그를 바꾼 뒤에는 routing의 참조를 전체 검색해 이전 이름이 남아 있지 않은지 확인하세요.
| 매개변수 | 권장 해석 | 자주 발생하는 오류 |
|---|---|---|
listen |
연결 출처의 범위 결정 | 공유할 때도 루프백 주소를 사용하거나, 로컬 전용인데 모든 네트워크 카드에 개방 |
port |
애플리케이션이 커널에 연결하는 로컬 포트 | 다른 프로그램과 충돌하거나 변경 후 시스템 프록시를 동기화하지 않음 |
protocol |
인바운드 핸드셰이크 방식 정의 | 애플리케이션은 HTTP를 선택했지만 실제로 SOCKS 포트에 연결 |
tag |
라우팅 규칙에서 참조하는 내부 이름 | 이름을 바꾼 뒤 routing은 이전 태그를 계속 사용 |
sniffing |
도메인 복원을 보조하고 트래픽 분기에 참여 | 활성화하면 모든 IP를 도메인으로 변환할 수 있다고 오해 |
03 / OUTBOUNDS
outbounds 아웃바운드 설정
프록시, 직접 연결과 차단으로 기본 출구 구성
아웃바운드는 커널이 트래픽을 어디로 보낼지 정의합니다. 일반적으로 최소한 프록시 출구와 직접 연결 출구가 필요하며, 특정 연결을 명시적으로 거부해야 할 때 차단 출구를 추가합니다. 프록시 출구에는 서버 주소, 포트, 사용자 식별자, 암호화 또는 전송 설정이 들어갑니다. 직접 연결 출구는 커널이 대상에 직접 접속하게 하고, 차단 출구는 규칙에 매칭된 연결을 능동적으로 종료합니다. routing은 연결을 수립하지 않고 현재 요청을 특정 아웃바운드 태그로 전달하는 역할만 합니다.
아웃바운드 배열의 순서도 확인해야 합니다. 어떤 연결이 라우팅 규칙에도 매칭되지 않으면 일반적인 구현에서는 첫 번째 아웃바운드를 기본 출구로 사용합니다. 따라서 프록시를 첫 항목에 둘지 직접 연결을 첫 항목에 둘지는 누락된 트래픽의 방향에 직접 영향을 줍니다. 중요한 정책을 기본 순서에만 의존하지 말고 명확한 규칙으로 작성하세요. 동시에 첫 항목도 전체 의도에 맞춰 두어 새 도메인이나 누락된 조건이 예상치 못한 결과를 만들지 않도록 합니다.
{
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "server.example.com",
"port": 443,
"users": [
{
"id": "11111111-2222-4333-8444-555555555555",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"serverName": "server.example.com"
}
}
},
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {
"response": {
"type": "none"
}
}
}
]
}
프로토콜 식별 매개변수와 전송 매개변수는 나누어 살펴보세요
프록시 아웃바운드를 점검할 때는 필드를 두 그룹으로 나누어 보세요. 첫 번째는 서버 주소, 포트, 사용자 ID와 프로토콜별 추가 설정 같은 프로토콜 식별 매개변수입니다. 두 번째는 streamSettings 안의 TCP, WebSocket, gRPC, TLS 또는 REALITY 같은 전송 매개변수입니다. 두 그룹이 각각 맞더라도 조합이 일치하지 않으면 연결되지 않습니다. 예를 들어 원격은 WebSocket인데 로컬은 TCP로 설정했거나, 서버 인증서의 이름과 serverName이 다르거나, 사용자 식별자는 맞지만 포트가 다른 서비스로 향하는 경우입니다.
구독 가져오기의 장점 중 하나는 서비스 제공자가 지정한 프로토콜, 전송, 보안 계층과 호스트 매개변수를 함께 클라이언트에 입력해 준다는 점입니다. 수동으로 옮길 때 주소와 포트만 복사하지 마세요. ‘노드 테스트는 되지만 웹페이지가 열리지 않는다’고 해서 곧바로 아웃바운드 식별 매개변수가 모두 맞다고 단정해서도 안 됩니다. 클라이언트 테스트는 일부 경로만 확인할 수 있고, 실제 애플리케이션에는 DNS, UDP, 라우팅과 시스템 프록시가 함께 관여합니다. 실행 로그를 통해 문제가 조회, 원격 연결, 핸드셰이크, 대상 접속 중 어느 단계에서 발생했는지 확인하세요.
직접 연결 출구도 DNS와 네트워크 환경의 영향을 받습니다
freedom은 현재 기기에서 대상 연결을 직접 수립한다는 뜻입니다. 설정 과정을 모두 우회하는 것이 아니라 인바운드와 routing을 거친 뒤 커널이 직접 연결을 실행합니다. 직접 연결이 실패하면 로컬 네트워크, 시스템 DNS, 대상 주소와 아웃바운드의 도메인 전략을 점검하세요. 규칙이 도메인에 따라 direct를 선택하더라도 연결 전에 조회가 필요할 수 있으며, 조회 결과와 주소 체계가 이후 동작에 영향을 줍니다. 일부 환경에서는 IPv6 레코드는 있지만 실제 연결 조건이 부족해 오래 기다린 뒤 타임아웃이 발생할 수 있습니다.
freedom 아웃바운드에 적절한 도메인 조회 전략을 설정할 수 있지만, 지원되는 값과 동작은 커널마다 다를 수 있습니다. 명확한 필요가 없다면 클라이언트가 생성한 기본값을 먼저 유지하세요. 분기 문제인지 확인하려면 범위가 작고 대상이 명확한 규칙 하나를 임시로 만들어 direct로 보내는 것이 좋습니다. 모든 규칙을 삭제하는 방식은 피하세요. 테스트가 끝나면 원래대로 돌려 다른 애플리케이션의 트래픽 경로가 바뀌지 않게 합니다.
프록시 체인과 여러 출구는 단순한 구조부터 시작하세요
하나의 설정에 여러 프록시 아웃바운드를 넣고 라우팅 태그로 선택할 수 있으며, 한 출구가 다른 출구를 통해 하위 연결을 만들도록 구성할 수도 있습니다. 이런 구조는 명확한 경로가 필요한 환경에 적합하지만 태그 의존성이 빠르게 늘어납니다. 설정하기 전에 ‘인바운드 → 라우팅 → 첫 번째 출구 → 하위 출구’ 순서를 그려 상호 참조가 없는지 확인하세요. proxy-a가 proxy-b에 의존하고 proxy-b가 다시 proxy-a로 돌아오면 커널은 유효한 경로를 만들 수 없습니다.
여러 노드 선택은 보통 v2rayN, v2rayNG 또는 v2flyNG의 설정 관리 기능으로 처리합니다. 클라이언트가 노드를 전환하면 현재 사용하는 아웃바운드를 조정하거나 실행 설정을 다시 생성합니다. 생성된 파일에 서버 객체를 많이 직접 넣는 방식은 클라이언트의 전환 로직과 맞지 않을 수 있습니다. 데스크톱에서는 v2rayN이 노드를 관리하도록 하고, 안정적인 사용자 지정 라우팅과 DNS 요구만 클라이언트가 지원하는 확장 위치에 추가하는 편이 전체 노드 목록을 장기간 수동 관리하는 것보다 되돌리기 쉽습니다.
| 태그 예시 | 프로토콜 | 역할 | 중점 점검 사항 |
|---|---|---|---|
proxy |
실제 노드의 프로토콜에 맞춤 | 원격 서버에 연결해 대상 트래픽 전달 | 주소, 포트, 식별 정보, 전송과 보안 계층이 모두 일치해야 함 |
direct |
freedom |
로컬 네트워크에서 대상에 직접 접속 | 로컬 네트워크, DNS, 주소 체계와 대상 도달 가능성 |
block |
blackhole |
매칭된 트래픽 종료 | 규칙 범위가 너무 넓거나 필요한 연결까지 차단하지 않는지 |
04 / ROUTING
routing 라우팅 규칙
규칙은 위에서 아래로 매칭되며 첫 번째 결과가 적용됩니다
라우팅 모듈은 연결의 대상 도메인, IP, 포트, 네트워크 유형, 프로토콜 특징 또는 인바운드 태그에 따라 아웃바운드를 선택합니다. 가장 중요한 점은 규칙 순서입니다. 규칙은 보통 위에서 아래로 검사되며 하나가 매칭되면 해당 규칙의 outboundTag를 사용하고 이후 규칙은 더 이상 적용하지 않습니다. 따라서 더 구체적인 규칙을 위에, 더 포괄적인 규칙을 아래에 배치해야 합니다. ‘모든 TCP 트래픽을 프록시로 보낸다’를 첫 규칙에 두면 뒤의 직접 연결 도메인 규칙은 적용될 기회가 없습니다.
규칙을 설계할 때는 먼저 기본 정책을 정한 다음 예외를 나열하세요. 기본 출구가 프록시라면 차단 조건과 명시적인 직접 연결 조건을 먼저 두고 나머지는 기본 프록시로 보내면 됩니다. 기본 출구가 직접 연결이라면 프록시가 필요한 대상을 먼저 나열하세요. 아웃바운드 배열 순서, 복잡한 도메인 목록과 여러 폴백 규칙에 같은 의미를 동시에 맡기지 마세요. 명확한 기본 동작 하나를 선택하고 규칙은 예외만 설명해야 이후 유지 관리가 쉽습니다.
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"protocol": [
"bittorrent"
],
"outboundTag": "direct"
},
{
"type": "field",
"domain": [
"domain:intranet.example.com",
"full:printer.example.net"
],
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
도메인 매칭 방식이 규칙의 범위를 결정합니다
도메인 조건에는 전체 일치, 도메인과 하위 도메인 일치, 키워드 일치, 사전 정의된 도메인 집합 등이 흔히 사용됩니다. full:printer.example.net은 정확한 호스트 이름만 매칭하므로 범위가 분명한 단일 서비스에 적합합니다. domain:example.com은 일반적으로 해당 도메인과 하위 도메인을 포함하므로 관련 호스트 그룹에 적합합니다. 접두사가 없는 문자열은 문맥에 따라 다르게 해석될 수 있으므로, 유지 관리 시에는 매칭 유형을 명시해 나중에 의도를 잊지 않도록 하세요.
키워드 매칭은 범위가 넓어 짧은 문자열 하나가 관계없는 도메인에 우연히 매칭될 수 있습니다. 이름의 일부를 기준으로 분류해야 하는 경우가 아니라면 full 또는 domain을 우선 사용하세요. 규칙이 매칭되지 않을 때는 먼저 커널이 본 대상이 도메인인지 확인합니다. 애플리케이션이 대상을 이미 IP로 변환했고 인바운드 스니핑이 도메인을 복원하지 못했다면 아무리 정확한 도메인 규칙도 적용되지 않습니다. 이때 액세스 로그 확인, 적절한 sniffing 활성화 또는 알려진 주소 범위에 IP 조건 추가를 검토하세요.
domainStrategy는 도메인 규칙과 IP 규칙을 연결합니다
domainStrategy는 IP 규칙과 매칭하기 위해 어떤 경우에 도메인을 조회할지 제어합니다. AsIs는 수신된 대상 형식 그대로 판단하는 데 중점을 두며, 라우팅 매칭만을 위해 도메인을 IP로 적극 변환하지 않습니다. IPIfNonMatch는 일반적으로 도메인 규칙이 매칭되지 않은 뒤 주소를 조회하고 IP 규칙을 시도한다는 뜻입니다. 다른 전략은 더 적극적으로 조회할 수 있습니다. 전략이 적극적일수록 도메인 트래픽이 IP 분류에 참여할 가능성이 커지지만 DNS 동작과 라우팅 결과의 결합도도 높아집니다.
전략을 선택할 때는 먼저 현재 규칙이 도메인 중심인지 IP 중심인지 확인하세요. 대부분의 규칙이 명확한 도메인이고 일부 네트워크 대역만 추가로 판단해야 한다면 IPIfNonMatch가 이해하기 쉽습니다. 모든 도메인을 먼저 주소 기준으로 분류하려면 DNS 설정과 예상 출구가 일치해야 합니다. 그렇지 않으면 조회 서버, 캐시 또는 주소 체계에 따라 같은 도메인도 다른 결과를 얻어 라우팅이 달라질 수 있습니다. domainStrategy를 바꾼 뒤에는 도메인 규칙, IP 규칙과 미매칭 대상 세 가지를 모두 테스트하세요.
IP, 포트, 네트워크와 인바운드 태그를 조합할 수 있습니다
IP 조건에는 단일 주소, CIDR 네트워크 대역 또는 커널이 지원하는 사전 정의 집합을 사용할 수 있습니다. 사설 주소는 보통 직접 연결해야 라우터, 프린터 또는 로컬 네트워크 서비스 접속이 원격으로 전달되지 않습니다. 포트 조건은 53 또는 80,443처럼 범위가 명확한 서비스에 적합하며 범위로 표현할 수도 있습니다. 네트워크 조건에는 tcp, udp 또는 두 유형의 조합을 흔히 사용합니다. 서로 다른 필드를 한 규칙에 넣으면 일반적으로 모두 충족해야 하며, 같은 필드의 배열에 여러 값을 넣으면 그중 하나만 매칭되어도 됩니다.
inboundTag는 출처를 구분할 때 유용합니다. 예를 들어 socks-in은 일반 분기 처리를 하고 lan-in은 지정된 출구만 사용하게 할 수 있습니다. 출처마다 커널 인스턴스를 여러 개 실행할 필요가 없습니다. 설정할 때는 인바운드 태그가 실제로 존재하는지 먼저 확인하고, 출처 제한을 규칙 앞부분에 배치해 더 넓은 대상 규칙에 먼저 매칭되지 않도록 하세요. 포트와 프로토콜 차단도 보수적으로 설정해야 합니다. 범위가 너무 넓으면 일부 애플리케이션은 첫 화면만 열리고 재생, 로그인 또는 동기화가 되지 않을 수 있습니다.
추측하지 말고 로그로 규칙을 검증하세요
라우팅을 검증하는 가장 효과적인 방법은 목적이 분명한 테스트 항목을 준비하는 것입니다. 직접 연결되어야 하는 내부 도메인 하나, 프록시로 가야 하는 대상 하나, 차단되어야 하는 조건 하나를 준비한 뒤 액세스 로그의 아웃바운드 태그를 확인하세요. 로그에 대상만 표시되고 예상 태그가 보이지 않는다면 일시적으로 로그 상세 수준을 높이고, 테스트가 끝난 뒤 낮춰 로그가 계속 증가하지 않게 합니다. 규칙을 수정한 후에는 커널을 다시 시작하거나 다시 로드하고, 클라이언트가 이전 실행 설정을 계속 사용하지 않는지도 확인하세요.
규칙이 많아지면 각 규칙 그룹에 대해 설정 외부에 유지 관리 메모를 작성하고 ‘왜 필요한가’를 기록하는 것이 도메인 목록만 남기는 것보다 유용합니다. 표준 JSON에는 주석을 쓸 수 있으므로 별도 문서에 설명을 보관하세요. 구독 업데이트는 일반적으로 노드와 프록시 아웃바운드에 영향을 주며 수동 라우팅까지 함께 덮어쓰면 안 됩니다. 업데이트할 때마다 규칙이 사라진다면 임시 생성 파일을 편집하고 있다는 뜻일 수 있으므로 클라이언트가 제공하는 라우팅 설정 경로를 사용하세요.
05 / DNS
dns DNS 설정
시스템 조회와 커널 조회를 먼저 구분하세요
DNS 설정이 자주 헷갈리는 이유는 한 기기에 여러 조회 경로가 동시에 존재할 수 있기 때문입니다. 애플리케이션이 먼저 시스템 DNS를 호출해 IP를 얻은 뒤 IP를 프록시에 넘길 수도 있고, 커널이 라우팅 판단을 위해 도메인을 직접 조회할 수도 있습니다. TUN 환경에서는 클라이언트가 시스템 조회를 가로챌 수도 있습니다. 설정 파일의 dns는 주로 커널 자체의 조회 방식을 정의하며 모든 애플리케이션의 조회가 자동으로 이 경로를 사용하도록 보장하지는 않습니다. 문제를 판단하기 전에 로그에서 커널에 들어온 대상이 도메인인지 이미 조회된 IP인지 확인하세요.
애플리케이션이 도메인을 SOCKS 또는 HTTP 프록시에 직접 넘기면 커널이 자체 DNS 설정으로 처리할 가능성이 있습니다. 반대로 애플리케이션이 로컬에서 먼저 조회하면 routing에는 주소만 보일 수 있어 해당 원래 조회에 DNS 설정이 적용되지 않을 수 있습니다. sniffing은 일부 연결에서 도메인을 복원할 수 있지만 전체 조회 가로채기를 대신하지는 못합니다. 따라서 ‘dns 객체를 작성했다’는 것과 ‘모든 프로그램이 해당 DNS를 사용한다’는 것은 같은 의미가 아닙니다.
{
"dns": {
"hosts": {
"router.home.arpa": "192.168.1.1"
},
"servers": [
{
"address": "1.1.1.1",
"domains": [
"domain:example.com"
],
"skipFallback": true
},
"localhost"
],
"queryStrategy": "UseIP"
}
}
servers 배열에는 순서가 있으며 조건도 추가할 수 있습니다
servers에는 단순 주소를 넣을 수도 있고, 객체를 사용해 특정 서버에 도메인 조건, 기대 주소 범위 또는 폴백 동작을 추가할 수도 있습니다. 단순한 설정은 안정적인 조회 소스 한두 개로 시작하면 충분합니다. 서버가 많다고 조회가 더 안정적인 것은 아닙니다. 각 서버의 사용 조건이 명확하지 않으면 실패 시 실제로 어느 서버에 조회했는지 판단하기 어렵습니다. 객체의 domains는 지정한 도메인을 해당 서버에 우선 전달하는 데 사용하며, 내부 도메인이나 조회 출처가 분명한 서비스에 적합합니다.
skipFallback은 현재 서버 조건에 매칭되는 조회가 이후 폴백에도 참여할지 제어합니다. 활성화하기 전에 해당 서버가 나열한 도메인을 실제로 조회할 수 있는지 확인하세요. 그렇지 않으면 조회에 실패해도 다른 출처를 시도하지 않을 수 있습니다. 로컬 네트워크 호스트 이름에는 로컬 조회 서버나 hosts 정적 매핑을 직접 사용하는 편이 명확합니다. 내부 이름을 공용 조회 서버에 맡기면 결과를 얻지 못할 뿐 아니라 문제 해결 방향이 로컬 네트워크에서 벗어날 수 있습니다.
hosts는 안정적인 매핑에 적합하며 동적 주소 관리에는 맞지 않습니다
hosts는 도메인을 고정 주소에 매핑하거나 소량의 별칭 관계를 정의할 수 있습니다. 새 서비스를 테스트하거나 로컬 네트워크 호스트 이름을 덮어쓰거나 잘못된 조회를 임시로 우회할 때 편리합니다. 일반 조회보다 우선 적용되므로 잘못 작성하면 계속 잘못된 대상으로 연결됩니다. hosts로 문제를 해결할 때는 추가한 항목을 기록하고 검증 후 유지할지 결정하세요. 몇 주 뒤 주소가 바뀌었는데도 설정이 이전 값에 고정되는 일을 막을 수 있습니다.
매핑 값의 데이터 형식은 커널 요구 사항에 맞아야 하며 도메인 키도 예상되는 완전한 이름으로 작성해야 합니다. 대상에 IPv4와 IPv6가 모두 있다면 하나의 고정 매핑이 정상적인 주소 선택을 바꿀 수 있습니다. 서비스 제공자가 동적으로 조정하는 도메인에는 hosts로 특정 결과를 장기간 고정하지 않는 것이 좋습니다. 한 번의 조회는 줄어들어도 장애 전환과 주소 업데이트 기능을 잃을 수 있습니다. 간헐적인 연결 문제가 발생하면 현재 IP를 바로 고정하기보다 조회 결과와 연결 로그를 먼저 비교하세요.
queryStrategy는 주소 체계 선택에 영향을 줍니다
queryStrategy는 IPv4, IPv6 또는 두 주소 유형을 조회하는 경향을 제어합니다. 구체적인 지원 값은 커널마다 다를 수 있으므로 현재 클라이언트가 사용하는 커널에서 유효한 설정을 기준으로 해야 합니다. 기기 네트워크가 안정적인 IPv4만 제공하는데 IPv6만 반환하도록 강제하면 대상에 연결할 수 없습니다. IPv6를 사용할 수 있다고 해서 모든 원격 경로가 IPv6 우선 사용에 적합한 것은 아닙니다. 로컬 네트워크, 프록시 서버 주소와 대상 아웃바운드의 능력을 함께 고려해 전략을 선택하세요.
도메인 조회는 빠르지만 특정 주소 체계에서 연결이 오래 대기하다가 폴백하거나 타임아웃되는 현상이 흔합니다. 이때 조회 결과의 A와 AAAA 레코드를 각각 확인하고 커널이 실제로 시도한 대상 주소도 관찰하세요. 모든 timeout을 노드 장애로 단정하지 마세요. 조회 전략을 바꾼 뒤 복구되었다면 로컬 IPv6 라우팅, 원격 서버 리슨 또는 대상 네트워크 경로 중 무엇이 문제였는지 추가로 확인해야 하며, 우연히 통했던 설정에 영구적으로 의존해서는 안 됩니다.
DNS와 routing은 순환 구조로 점검해야 합니다
domainStrategy가 IP 규칙 매칭을 위해 도메인 조회를 요구하면 routing이 DNS를 호출합니다. 조회 자체는 다시 특정 아웃바운드를 통해 전송될 수 있습니다. 설계가 잘못되면 순환 의존이 생깁니다. 도메인이 어느 출구로 갈지 결정하려고 조회를 시작했는데 조회 출구가 아직 끝나지 않은 도메인 분류에 의존하는 식입니다. 단순한 환경에서는 DNS에 지나치게 복잡한 라우팅 체인을 만들지 마세요. 먼저 기본 조회가 작동하는지 확인한 뒤 명확한 조회 서버 주소에 직접 연결 또는 프록시 규칙을 추가하세요.
순환 구조는 네 단계로 점검할 수 있습니다. 첫째, 애플리케이션이 인바운드에 도메인과 IP 중 무엇을 넘기는지 확인합니다. 둘째, 라우팅 전략에 조회가 필요한지 봅니다. 셋째, 어느 서버가 조회를 처리하는지 확인합니다. 넷째, 조회 연결 자체가 어느 아웃바운드를 통과하는지 확인합니다. 어느 한 단계라도 예상과 다르면 웹페이지가 열리지 않거나 분기가 잘못될 수 있습니다. v2rayN 로그로 조회와 연결 단계를 찾을 수 있으며, 읽는 방법은 V2Ray 실행 로그 읽는 법을 참고하세요.
| 증상 | 우선 확인할 항목 | 먼저 하지 말아야 할 일 |
|---|---|---|
| 도메인은 실패하지만 IP 직접 접속은 응답함 | 조회 서버, DNS 아웃바운드 경로, 애플리케이션의 시스템 조회 사용 여부 | 조회 서버를 한꺼번에 많이 추가하기 |
| 도메인 규칙이 매칭되지 않음 | 인바운드가 도메인과 IP 중 무엇을 보는지, sniffing, domainStrategy | 같은 도메인 키워드를 반복해서 추가하기 |
| 로컬 네트워크 호스트 이름을 조회할 수 없음 | 로컬 DNS, hosts 매핑, 검색 도메인 | 로컬 네트워크와 무관한 조회 소스에 맡기기 |
| 조회는 성공하지만 연결이 오래 대기함 | 주소 체계, 대상 라우팅, 아웃바운드가 실제로 시도한 주소 | 조회 속도만으로 노드 상태 판단하기 |
06 / POLICY
policy 정책과 통계
policy는 실행 동작을 제어하며 분기 방향을 결정하지 않습니다
policy를 routing의 보완 기능으로 오해하기 쉽지만, 실제로는 연결 세션의 타임아웃, 유휴 판정과 통계 스위치를 주로 제어합니다. 트래픽이 프록시로 갈지 직접 연결될지는 여전히 routing과 아웃바운드가 결정합니다. 정책은 보통 사용자 레벨별로 구성하며, 아웃바운드 사용자 객체의 level로 해당 레벨을 연결할 수 있습니다. 별도 설정이 없으면 대부분 기본 레벨을 사용합니다. 세션 동작을 다르게 해야 할 때만 여러 레벨을 추가하세요.
타임아웃 매개변수는 짧을수록 좋은 것이 아닙니다. 짧은 시간 동안 데이터가 전송되지 않았다고 연결이 끊긴 것은 아닙니다. 롱 폴링, 간헐적인 파일 전송, 원격 터미널과 연결을 유지하는 애플리케이션은 유휴 구간이 발생할 수 있습니다. 유휴 시간을 너무 짧게 설정하면 애플리케이션이 자주 재연결하고, 너무 길게 설정하면 끊어진 연결이 늦게 정리됩니다. 클라이언트나 커널의 기본 동작에서 시작해 로그와 애플리케이션 증상으로 필요성이 확인될 때만 조정하세요.
{
"policy": {
"levels": {
"0": {
"handshake": 4,
"connIdle": 300,
"uplinkOnly": 2,
"downlinkOnly": 5,
"statsUserUplink": false,
"statsUserDownlink": false
}
},
"system": {
"statsInboundUplink": false,
"statsInboundDownlink": false,
"statsOutboundUplink": false,
"statsOutboundDownlink": false
}
}
}
handshake와 connIdle은 서로 다른 단계를 처리합니다
handshake는 연결 수립 단계에서 기다릴 수 있는 시간을 제한합니다. 아직 핸드셰이크가 완료되지 않은 연결에 적용되며 웹페이지 전체 로딩 시간 제한과는 다릅니다. 너무 짧으면 네트워크가 불안정하거나 원격 응답이 조금 느릴 때 조기에 실패하고, 너무 길면 수립할 수 없는 연결이 더 오래 리소스를 점유합니다. 핸드셰이크 타임아웃이 발생하면 먼저 서버 주소, 포트, 전송 계층과 로컬 네트워크를 점검하세요.
connIdle은 데이터 활동이 없을 때 연결을 얼마나 유지할지 결정합니다. 유휴 연결이 닫히면 애플리케이션은 보통 다시 연결하지만 일부 프로그램은 이를 세션 중단으로 표시합니다. 문제 발생 간격이 일정한지 비교해 보세요. 매번 비슷한 유휴 시간 뒤 끊긴다면 정책을 점검할 가치가 있고, 시간이 무작위이며 로그에 원격 재설정이 보인다면 링크나 서버 동작일 가능성이 높습니다.
uplinkOnly와 downlinkOnly는 한 방향으로만 데이터 활동이 있는 연결을 처리하는 데 사용됩니다. 업로드나 다운로드 속도 제한이 아니며 특정 애플리케이션에 대역폭을 할당하지도 않습니다. 기존 연결 동작을 모르는 상태에서 ‘최적화’를 위해 임의로 시간을 줄이지 마세요. 그래픽 클라이언트가 생성한 기본 정책은 일반적인 사용에 적합한 경우가 많으며, 장시간 연결, 리소스 제약 또는 명확한 서비스 환경에서만 별도로 평가하면 됩니다.
통계 스위치는 수집 허용 여부만 담당합니다
statsUserUplink, statsUserDownlink와 system 아래의 인바운드·아웃바운드 통계 필드는 해당 방향의 트래픽 정보를 커널이 기록하도록 허용합니다. 이 불리언 값을 켠다고 해서 눈에 보이는 차트나 화면 숫자가 자동으로 생기는 것은 아니며, 지원되는 통계 모듈과 조회 방식도 필요합니다. 클라이언트가 이 데이터를 사용하지 않는다면 모든 통계 항목을 켜는 것은 불필요한 상태 관리만 늘립니다.
통계 항목을 연결 성공 여부를 확인하는 지표로 사용하지 마세요. 한 방향의 바이트 수가 변했다는 것은 해당 카운터 범위에 데이터가 지나간 적이 있다는 뜻일 뿐, 대상 콘텐츠가 완전히 반환되었다거나 라우팅 선택이 예상과 맞다는 것을 단독으로 증명하지는 못합니다. 연결 품질은 접속 결과와 오류 로그를 함께 확인해야 합니다. 클라이언트 화면의 트래픽 통계는 시스템 인터페이스, 커널 인터페이스 또는 자체 카운터에서 가져올 수 있어 policy의 각 스위치와 집계 기준이 완전히 같지 않을 수 있습니다.
여러 사용자 레벨은 명확한 연결 관계가 필요합니다
설정에 여러 사용자 객체가 포함되어 있다면 사용자마다 다른 level을 지정하고 policy의 levels에서 해당 정책을 정의할 수 있습니다. JSON의 레벨 키는 "0", "1"처럼 문자열로 표시됩니다. 사용자가 설정되지 않은 레벨을 참조하면 구현에 따라 커널이 기본 동작을 사용하거나 관련 문제를 보고할 수 있습니다. 유지 관리 시 사용자 레벨과 정책 레벨을 함께 확인해 한쪽만 복사하지 않도록 하세요.
일반 클라이언트 아웃바운드에는 복잡한 레벨 체계가 보통 필요하지 않습니다. 노드 구독에서 제공하는 사용자 식별 정보는 원격 프로토콜 인증에 사용되는 것이며, 로컬에서 노드마다 policy 레벨을 만들어야 한다는 뜻은 아닙니다. 인바운드 서비스로 운영하면서 세션 정책을 구분해야 할 때 여러 레벨이 더 흔합니다. 이 페이지는 클라이언트 설정에 초점을 두므로 기본 레벨 하나를 유지하고 인바운드 보안, 아웃바운드 매개변수와 라우팅 가독성에 집중하는 편이 좋습니다.
로그 수준과 정책 점검을 함께 진행하세요
정책 문제는 ‘연결된 뒤 끊김’으로 나타나는 경우가 많아 로그의 시간 흐름이 필요합니다. 평소에는 warning처럼 절제된 수준을 사용하고, 문제를 재현할 때만 일시적으로 상세 수준을 높여 시작 시간과 재현 절차를 기록하세요. 로그 경로가 권한 없는 디렉터리라면 커널이 시작되지 않거나 진단 정보가 남지 않을 수 있습니다. 그래픽 클라이언트는 보통 로그 위치를 처리하므로 독립 커널을 수동 설정할 때 파일 경로를 특별히 점검하면 됩니다.
재현 후 연결 시작, 마지막 데이터 활동, 연결 종료라는 세 시점을 먼저 비교하세요. 종료 시점이 정책 임계값과 거의 일치한다면 한 항목만 조정해 다시 테스트합니다. 로그에 원격 종료나 하위 연결 실패가 명확히 표시된다면 policy가 주요 원인은 아닙니다. 디버깅이 끝나면 적절한 로그 수준으로 되돌리고 테스트를 위해 켠 통계 항목도 삭제해 실행 설정을 간결하게 유지하세요.
| 필드 | 제어 단계 | 담당하지 않는 것 |
|---|---|---|
handshake |
연결 핸드셰이크 대기 | 웹페이지 전체 로딩 시간 |
connIdle |
데이터 활동이 없는 연결 유지 | 네트워크 속도 제한 |
uplinkOnly |
업링크만 활동한 뒤의 연결 처리 | 업로드 대역폭 할당 |
downlinkOnly |
다운링크만 활동한 뒤의 연결 처리 | 다운로드 대역폭 할당 |
statsInboundUplink |
인바운드 업링크 통계 기록 허용 | 시각화 보고서 자동 생성 |
07 / ASSEMBLY
전체 설정 조합과 시작 전 점검
최소한의 순환 구조부터 만들고 기능을 단계적으로 추가하세요
설정을 조합할 때 가장 안정적인 순서는 최소한의 순환 구조를 먼저 만드는 것입니다. 로컬에서만 리슨하는 SOCKS 인바운드 하나, 유효한 프록시 아웃바운드 하나, 직접 연결 아웃바운드 하나와 방향이 분명한 소수의 라우팅 규칙으로 시작하세요. 최소 설정으로 시작해 연결까지 확인한 뒤 HTTP 인바운드, DNS 조건, 차단 규칙과 policy를 추가합니다. 이렇게 하면 한 번에 추가되는 범위가 제한되어 문제가 생겼을 때 바로 이전의 정상 설정으로 되돌릴 수 있습니다.
완성된 파일의 모든 태그는 참조 관계가 맞아야 합니다. routing에서 사용하는 outboundTag는 outbounds에서 찾을 수 있어야 하고, inboundTag는 inbounds의 태그와 일치해야 합니다. 사용자 level이 policy와 연결된다면 해당 정책도 존재해야 합니다. 태그가 대소문자를 구분할 때 Proxy와 proxy는 서로 다른 이름입니다. 입력 오류를 줄이려면 소문자, 숫자와 하이픈만 사용하는 것이 좋습니다.
{
"log": {
"loglevel": "warning"
},
"dns": {
"servers": [
"localhost"
],
"queryStrategy": "UseIP"
},
"inbounds": [
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
}
],
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "server.example.com",
"port": 443,
"users": [
{
"id": "11111111-2222-4333-8444-555555555555",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"serverName": "server.example.com"
}
}
},
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {}
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
},
"policy": {
"levels": {
"0": {
"handshake": 4,
"connIdle": 300
}
}
}
}
예제가 완전하다고 노드 매개변수를 그대로 사용할 수 있는 것은 아닙니다
위 JSON은 계층 구조가 완전해 각 부분의 조합 방식을 이해하는 데 사용할 수 있지만, 서버 도메인과 사용자 ID는 문서용 예제입니다. 실제 설정에서는 자신의 구독 또는 서비스 정보에 있는 전체 매개변수로 바꾸고 streamSettings도 원격과 일치시켜야 합니다. 실제 노드가 예제와 다른 프로토콜이나 전송 방식을 사용한다면 프로토콜 이름만 바꾸지 말고 프록시 아웃바운드 객체 전체를 교체하세요. 프로토콜 객체 내부 구조가 다르므로 문자열 하나만 수정하면 호환되지 않는 필드가 남습니다.
v2rayN, v2rayNG 또는 v2flyNG를 사용할 때는 먼저 노드를 가져온 뒤 클라이언트가 생성한 아웃바운드 구조를 확인하고, 필요한 라우팅 방식을 클라이언트가 지원하는 위치에 적용하세요. 이 글의 예제를 사용하기 위해 클라이언트가 이미 올바르게 생성한 노드 매개변수를 버리지 마세요. 설정 참고 문서의 목적은 구조를 설명하고 문제 해결을 돕는 것이지, 모든 사용자가 빈 파일에서 연결 정보를 전부 수동 작성하게 하는 것이 아닙니다.
문법 검사와 커널 설정 검사를 실행하세요
첫 번째 단계에서는 JSON을 지원하는 편집기로 괄호, 따옴표와 쉼표를 확인할 수 있습니다. 두 번째 단계에서는 실제 커널이 설정을 읽게 해야 합니다. Xray를 독립 실행할 때 흔히 xray run -test -config config.json을 사용하며, V2Ray를 독립 실행할 때는 실행 파일이 지원하는 명령에 따라 v2ray test -c config.json을 사용할 수 있습니다. 명령 이름과 매개변수는 클라이언트의 래퍼 방식과 실행 파일 위치가 다를 수 있으므로 로컬 커널의 도움말 출력을 기준으로 하세요.
그래픽 클라이언트 사용자는 보통 터미널을 열어 임시 설정을 수동 테스트할 필요가 없습니다. 커널을 다시 시작한 뒤 클라이언트 로그를 확인하세요. 클라이언트가 시작 전에 파일을 다시 생성한다면 제공되는 편집 경로에서 변경 사항을 저장해야 합니다. 테스트 결과에 알 수 없는 필드가 표시되면 현재 V2Fly와 Xray 중 어떤 커널을 사용하는지 확인한 뒤 해당 필드가 최상위, 인바운드, 프로토콜 또는 streamSettings 중 어느 계층에 속하는지 점검하세요. 올바른 필드라도 잘못된 계층에 넣으면 유효하지 않은 것으로 처리됩니다.
데이터 흐름에 따른 시작 후 네 단계 검증
설정을 읽는 데 성공한 뒤에도 실행 경로를 검증해야 합니다. 첫 번째는 인바운드입니다. 포트가 리슨 중인지, 애플리케이션의 프록시 유형과 포트가 일치하는지 확인하세요. 두 번째는 라우팅입니다. 대상을 하나 열어 로그에서 proxy와 direct 중 무엇이 선택되었는지 확인합니다. 세 번째는 아웃바운드입니다. 원격 연결과 핸드셰이크가 완료되는지 관찰하세요. 네 번째는 대상 응답입니다. 단순히 로컬 프록시 연결만 수립된 것이 아니라 애플리케이션이 실제 콘텐츠를 받았는지 확인합니다.
첫 번째 단계에서 실패하면 포트 사용 여부와 리스닝 주소를 중점적으로 확인하세요. 두 번째 단계가 잘못되면 규칙 순서, 대상 형식과 태그를 점검합니다. 세 번째 단계가 실패하면 노드, 네트워크와 전송 매개변수를 확인하세요. 앞의 세 단계가 정상인데 네 번째만 이상하면 DNS, 대상 서비스와 애플리케이션 자체 동작을 살펴봅니다. 이렇게 나누어 점검하면 노드를 계속 바꾸는 것보다 효과적이며 로컬 포트 문제를 원격 장애로 오해하는 일도 줄어듭니다.
클라이언트가 설정을 덮어쓸 때 변경 사항을 보존하는 방법
v2rayN은 서버를 전환하거나 구독을 업데이트하거나 프록시 모드를 변경할 때 커널 실행 설정을 다시 구성할 수 있습니다. 장기간 유지해야 하는 내용은 실행 디렉터리의 임시 JSON만 편집하지 말고 클라이언트가 지원하는 사용자 지정 라우팅, DNS 또는 사용자 지정 설정 기능에 넣으세요. 수정하기 전에 현재 설정을 내보내거나 기록하고, 업데이트 후 사용자 지정 규칙이 계속 병합되는지 확인합니다. 최초 설치와 설정 파일 위치에 관한 주의 사항은 v2rayN 최초 설치와 초기 설정 전체 과정을 참고하세요.
Android 클라이언트도 단일 노드 설정, 구독 항목과 실행 설정을 서로 나누어 저장할 수 있습니다. 특정 노드를 편집하면 해당 노드의 프로토콜 매개변수만 바뀌며 전역 라우팅까지 바뀌는 것은 아닙니다. 현재 화면에서 수정하는 대상이 노드인지, 라우팅인지, 애플리케이션 설정인지 먼저 확인한 뒤 결과를 테스트하세요. v2rayNG는 Xray 커널 경로를 우선 사용하고 v2flyNG는 v2fly 커널의 대안으로 사용합니다. 두 커널은 확장 필드가 다를 수 있으므로 전체 JSON을 그대로 서로 복사해서는 안 됩니다.
08 / TROUBLESHOOTING
설정 오류와 연결 장애 문제 해결
시작 즉시 실패할 때: 첫 번째 명확한 오류부터 확인하세요
커널 시작에 실패하면 로그 뒤에 여러 연쇄 메시지가 이어질 수 있지만 실제 원인은 보통 가장 먼저 나온 명확한 오류 부근에 있습니다. JSON 파싱 실패, 알 수 없는 필드, 데이터 형식 불일치, 포트 사용 중, 접근할 수 없는 파일 경로, routing에서 참조한 태그 없음 등이 흔한 유형입니다. 첫 번째 오류를 먼저 처리한 뒤 다시 시작하세요. 후속 메시지만 보고 여러 영역을 한꺼번에 수정하면 안 됩니다. 뒤의 오류는 앞선 실패의 결과일 수 있습니다.
JSON 파싱 오류에는 보통 행 번호나 문자 위치가 표시됩니다. 해당 줄 앞뒤에 쉼표가 빠졌거나 불필요한 쉼표가 들어갔는지, 따옴표가 닫히지 않았는지, 복사 과정에서 전각 문장 부호가 섞이지 않았는지 확인하세요. 오류 위치는 파서가 문제를 발견한 지점일 뿐 실제 누락은 이전 줄에 있을 수도 있습니다. 파일이 길다면 최근 추가한 객체 전체를 잠시 제거해 기본 설정이 복구되는지 확인한 뒤 조각을 단계적으로 다시 넣으세요.
커널은 실행되지만 애플리케이션이 로컬 프록시에 연결되지 않음
이 경우 먼저 원격 노드를 확인하지 마세요. 애플리케이션의 프록시 주소가 127.0.0.1인지, 포트가 인바운드와 일치하는지, 프록시 유형이 맞는지 확인하세요. 시스템 프록시를 사용한다면 클라이언트에서 해당 모드를 활성화했는지 점검합니다. 커널만 시작한다고 시스템 설정이 자동으로 바뀌는 것은 아닙니다. 브라우저 확장 프로그램, 애플리케이션 내 프록시와 시스템 프록시가 동시에 있으면 중복 프록시가 되거나 이전 포트를 가리킬 수 있으므로 테스트할 때는 경로 하나만 명확하게 유지하세요.
Windows, macOS 또는 Linux 데스크톱에서는 이전 프로세스가 포트를 점유하는 일이 흔합니다. 클라이언트를 종료한 뒤 커널 프로세스도 함께 끝났는지 확인하고 다시 실행하세요. 인바운드 포트를 바꿨다면 시스템 프록시도 함께 업데이트해야 합니다. Android 클라이언트는 시스템 네트워크 인터페이스를 통해 애플리케이션 트래픽을 가로채므로 데스크톱 로컬 SOCKS 포트와 점검 방식이 다릅니다. 먼저 클라이언트가 연결 상태인지, 실행 로그에 커널이 정상 시작되었다고 표시되는지 확인하세요.
로컬 프록시에는 연결되지만 원격 핸드셰이크가 실패함
로그에 연결 거부, 핸드셰이크 실패 또는 원격의 조기 종료가 나타나면 ‘주소와 포트 → 사용자 식별 정보 → 프로토콜 → 전송 → 보안 계층’ 순서로 확인하세요. 도메인이 조회된다고 해서 해당 포트가 올바른 서비스로 연결된다는 뜻은 아니며, TCP 연결이 된다고 TLS 이름과 애플리케이션 계층 전송이 일치한다는 의미도 아닙니다. 구독 노드는 먼저 정상 업데이트를 한 번 실행해 현재 항목에 이전 매개변수가 남아 있지 않은지 확인하세요. 수동 노드는 원본 설정과 항목별로 비교합니다.
시스템 시간이 크게 틀리면 시간에 의존하는 보안 연결에 영향을 줄 수 있으므로 먼저 기기 시간을 정상화하세요. 네트워크를 전환한 뒤 문제가 사라졌다면 프로토콜만 수정하지 말고 현재 네트워크, DNS 또는 주소 체계도 점검해야 합니다. 노드 타임아웃은 노드 타임아웃 점검 순서에 따라 단계적으로 확인하고, 로컬 네트워크와 시스템 시간을 건너뛴 채 아웃바운드 객체만 반복해서 바꾸지 마세요.
일부 웹사이트나 애플리케이션만 실패함
일부 대상만 실패한다면 기본 인바운드와 최소 하나의 아웃바운드는 작동한다는 뜻일 가능성이 높습니다. 다음으로 라우팅, DNS, UDP와 대상의 특징을 확인하세요. 성공한 대상과 실패한 대상이 각각 어떤 아웃바운드를 사용하는지 비교한 뒤, 실패 항목이 커널에 들어올 때 도메인인지 IP인지 확인합니다. 잘못된 규칙이 특정 도메인을 direct로 보내면 노드가 정상이어도 해당 연결에는 사용되지 않습니다. domainStrategy가 다른 주소를 조회하도록 만들면 예상한 도메인 규칙과 결과가 달라질 수도 있습니다.
애플리케이션의 로그인, 음성, 동영상 또는 동기화 기능은 서로 다른 도메인, 포트와 네트워크 유형을 사용할 수 있습니다. 첫 화면이 열린다는 것은 일부 요청만 성공했다는 뜻입니다. 메인 페이지 결과만 보고 애플리케이션 전체 도메인을 너무 넓은 규칙 하나에 넣지 마세요. 재현할 때 실패한 기능의 로그 대상을 기록하고 필요한 조건을 하나씩 추가합니다. UDP가 관련되면 SOCKS 인바운드가 UDP를 허용하는지, 프록시 프로토콜과 서버가 현재 경로를 지원하는지, routing이 UDP를 올바른 출구로 보내는지 확인하세요.
규칙은 올바르게 보이지만 계속 매칭되지 않음
먼저 규칙 위치를 확인하세요. 앞에 더 넓은 domain, IP, network 또는 port 조건이 있지는 않나요? 다음으로 대상 형식을 확인합니다. 로그에 완전한 도메인, 하위 도메인, IP 또는 sniffing으로 복원된 이름 중 무엇이 보이나요? 이어서 매칭 접두사가 요구 사항에 맞는지 점검하세요. full은 모든 하위 도메인을 자동으로 포함하지 않으며 키워드는 지나치게 넓을 수 있습니다. 마지막으로 outboundTag 철자와 현재 실행 파일을 확인해 백업 파일을 수정하고 실제로는 다른 설정을 로드하는 일이 없도록 하세요.
특정 규칙을 검증하려면 임시로 앞부분으로 옮기고 대상을 명확한 도메인 하나로 제한하세요. 테스트 후 로그의 아웃바운드 태그를 확인합니다. 여전히 매칭되지 않으면 대상 형식이 잘못되었거나 설정이 로드되지 않은 것입니다. 앞부분으로 옮겼을 때 매칭된다면 원래 위치 앞의 규칙이 먼저 가로챈 것입니다. 원인을 확인한 뒤 순서를 다시 정리하세요. 새 규칙을 모두 맨 위에 쌓는 방식을 장기간 사용하면 구체적인 규칙끼리도 점점 서로 덮어쓰게 됩니다.
연결이 일정 시간 뒤 끊김
먼저 끊김이 일정한 시간 간격으로 발생하는지 확인하세요. 매번 connIdle 또는 단방향 연결 정책의 시간과 비슷하다면 policy를 점검하고, 시간이 무작위라면 원격 재설정, 네트워크 전환, 기기 절전과 주소 변경을 확인합니다. 노트북이 한 네트워크에서 다른 네트워크로 전환되면 기존 연결이 무효화되는 것은 정상이며 클라이언트가 경로를 다시 수립해야 할 수 있습니다. 절전 모드에서 깨어난 뒤 한 번 발생한 중단을 곧바로 노드 매개변수 문제로 단정하지 마세요.
로그의 timeout, context canceled와 connection reset은 서로 다른 단계와 원인을 나타내므로 단순히 ‘오류’라는 이유만으로 같은 방식으로 처리하면 안 됩니다. timeout은 앞선 로그를 함께 보고 DNS, 다이얼링 또는 핸드셰이크 중 어디서 발생했는지 판단해야 합니다. context canceled는 상위 요청이 능동적으로 종료했을 수 있고, reset은 어느 한쪽이 연결을 재설정했다는 뜻입니다. 시간 흐름에서 가장 이른 이상을 먼저 찾고 뒤의 오류가 취소 및 정리 과정에 불과한지 확인하세요.
재현 가능한 문제 해결 기록을 만드세요
복잡한 설정은 클라이언트 이름, 현재 커널 계열, 인바운드 포트, 기본 아웃바운드, 최근 수정 영역과 재현 절차를 포함한 짧은 기록을 남기는 것이 좋습니다. 노드의 민감한 정보는 기록할 필요 없이 구조만 설명하면 됩니다. 매 테스트마다 ‘무엇을 바꿨는지, 무엇을 예상했는지, 실제 로그가 무엇이었는지’를 적으면 두세 차례만으로도 대부분의 추측을 배제할 수 있습니다. 여러 옵션을 반복해서 전환하면서 기록하지 않으면 문제가 우연히 사라진 뒤에도 원인을 확인할 수 없습니다.
복구가 필요하면 먼저 최소한의 사용 가능한 설정으로 돌아간 뒤 DNS, 분기와 정책을 하나씩 추가하세요. 최소 설정에서도 실패한다면 클라이언트 설치, 로컬 네트워크 또는 노드 자체의 문제일 가능성이 높으므로 빠른 시작 경로로 돌아가 가져오기와 연결 단계를 다시 확인할 수 있습니다. 사용자 지정 규칙만 실패한다면 검증된 노드 아웃바운드는 유지하고 routing과 대상 로그에 집중하세요. 클라이언트를 다시 설치할 필요는 없습니다.
| 장애 단계 | 대표 증상 | 우선 조치 |
|---|---|---|
| JSON과 필드 | 커널이 시작되지 않음 | 첫 번째 파싱 또는 필드 오류를 처리하고 최근 변경 사항을 확인 |
| 인바운드 | 애플리케이션이 로컬 프록시에 연결되지 않음 | 주소, 포트, 프로토콜 유형과 포트 사용 여부 확인 |
| 라우팅 | 대상이 잘못된 출구로 가거나 규칙이 매칭되지 않음 | 대상 형식, 규칙 순서와 실제 아웃바운드 태그 확인 |
| DNS | 도메인 접속 실패 또는 조회 결과 이상 | 조회 경로, 서버 조건과 주소 체계 확인 |
| 아웃바운드 | 원격 거부, 핸드셰이크 실패 또는 타임아웃 | 주소, 식별 정보, 프로토콜, 전송과 보안 계층을 한 세트로 확인 |
| 정책과 세션 | 일정한 유휴 시간 후 연결 종료 | policy 임계값과 로그 시간 흐름 비교 |