사용자 지정 라우팅은 규칙 순서, 매칭 조건, DNS 정책 순으로 확인하세요. 노드 연결은 정상이며 특정 사이트에 예외 규칙을 추가하려는 사용자를 위해 V2Ray와 Xray의 일반적인 field 라우팅 문법, v2rayN 적용 방법과 검증 절차를 설명합니다. 예제에는 문서용 예약 도메인과 주소를 사용했으며, 실제 사이트 분류를 의미하지 않습니다.
1. 라우팅 규칙은 조건을 확인한 뒤 아웃바운드를 선택합니다
라우팅은 노드 연결 설정이 아닙니다. VMess, VLESS 등의 프로토콜은 서버에 연결하고, 라우팅은 코어에 전달된 요청을 어느 아웃바운드로 보낼지 결정합니다. v2rayN은 설정 인터페이스이며 규칙을 실제로 처리하는 것은 현재 실행 중인 코어입니다. 아래 예제는 V2Ray/Xray JSON 문법이므로 다른 형식의 설정 편집기에 그대로 붙여 넣을 수 없습니다.
일반적인 규칙은 type: "field", 매칭 필드, outboundTag로 구성됩니다. 태그는 기존 아웃바운드의 tag와 일치해야 합니다. 태그를 proxy로 지정한다고 프록시 노드가 자동으로 만들어지는 것은 아니며, direct라고 지정해도 직결 아웃바운드가 자동 생성되지 않습니다. 클라이언트가 생성한 태그는 다를 수 있으므로 수정하기 전에 실제 설정을 확인하세요.
이 포트는 요청의 대상 포트이며 클라이언트의 로컬 수신 포트가 아닙니다. 예를 들어 아래 규칙은 대상 포트가 443이고 도메인이 example.com인 요청만 프록시 아웃바운드로 보냅니다. 해당 도메인의 모든 연결에 적용되는 것은 아닙니다.
{
"type": "field",
"domain": ["domain:example.com"],
"port": "443",
"outboundTag": "proxy"
}
- 같은 필드 안에서는 보통 OR 조건입니다:
domain배열의 항목 중 하나라도 일치하면 도메인 조건을 충족합니다. - 서로 다른 필드 사이에서는 AND 조건입니다:
domain과port를 함께 지정하면 두 조건을 모두 충족해야 합니다. - 규칙은 순서대로 확인합니다: 모든 조건에 처음으로 일치하는 규칙을 찾으면 해당 아웃바운드를 선택하고, 더 구체적인 규칙을 계속 찾지 않습니다.
2. domain·full·regexp: 도메인 매칭 범위
기본 도메인과 모든 하위 도메인에 적용하려면 domain:을 사용하고, 특정 호스트 이름만 허용하려면 full:을 사용하세요. 둘 다 이름에 '도메인'이 들어간다고 같은 규칙으로 보면 안 됩니다. 도메인 필드에는 호스트 이름을 입력하며 웹 주소는 입력하지 않습니다. 프로토콜, 경로, 쿼리 매개변수도 포함하면 안 됩니다.
| 규칙 작성법 | 매칭 범위 | 혼동하기 쉬운 범위 |
|---|---|---|
domain:example.com | example.com 및 api.example.com 같은 하위 도메인 | notexample.com 및 example.com.test는 매칭되지 않음 |
full:example.com | example.com만 | www.example.com은 매칭되지 않음 |
example | 도메인에 해당 문자열이 포함된 경우 | unrelated-example.test가 매칭될 수 있어 특정 사이트 예외에는 부적합 |
regexp:^api[0-9]+\.example\.com$ | 예: api1.example.com, api25.example.com | 패턴의 시작과 끝을 지정해야 합니다. JSON에 입력할 때는 백슬래시도 이스케이프해야 합니다. |
정규식은 패턴 매칭이 꼭 필요한 경우에만 사용하세요. 아래 예제는 JSON 문자열에서 백슬래시를 두 번 써서, 코어가 리터럴 마침표를 매칭하는 \.를 받도록 합니다. 인터페이스의 입력란이 JSON 문자열이 아닌 원시 규칙 텍스트를 받는다면 JSON 이스케이프는 필요하지 않습니다.
{
"type": "field",
"domain": [
"full:login.example.com",
"regexp:^api[0-9]+\\.example\\.com$"
],
"outboundTag": "proxy"
}
결론: 단일 사이트 예외에는 먼저 full을 사용하세요
로그인 호스트 하나만 예외 처리하려면 먼저 해당 호스트 이름 전체를 지정한 규칙을 추가하고 확인하세요. 모든 하위 도메인에 같은 아웃바운드가 필요한지 확인한 뒤에 domain 규칙으로 범위를 넓히면 정적 리소스나 다른 서비스의 연결 경로까지 바뀌는 일을 피할 수 있습니다.
3. ip·geoip·geosite: IP 주소와 도메인 목록은 구분해서 작성
ip는 JSON 필드이고 geoip:는 해당 필드의 배열에 넣는 목록 참조입니다. geosite:는 domain 배열에 넣습니다. 두 목록은 코어가 해당 데이터 파일을 읽을 수 있어야 사용할 수 있습니다. 목록 이름과 내용은 데이터 파일에 정의되며, 코어가 이름만 보고 실시간으로 생성하는 결과가 아닙니다.
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
}
{
"type": "field",
"ip": [
"192.0.2.15/32",
"2001:db8::15/128",
"geoip:private",
"geoip:cn"
],
"outboundTag": "direct"
}
위의 192.0.2.15와 2001:db8::15는 문서용 예시 주소이므로 실제로 사용할 때는 대상 서비스의 주소로 바꾸세요. IPv4의 /32와 IPv6의 /128은 각각 단일 주소를 뜻합니다. 네트워크 접두사 길이가 짧을수록 일반적으로 더 넓은 범위를 포함합니다. 단일 주소의 접속 문제를 해결하려고 큰 네트워크 대역을 추가하지 마세요.
- geosite:cn: 데이터 세트의 도메인 분류를 기준으로 매칭하며, 해당 도메인의 모든 DNS 응답이 같은 지역에 속한다고 보장하지는 않습니다.
- geoip:cn: 대상 IP가 속한 주소 목록을 기준으로 매칭하며, 해당 주소에서 서비스되는 사이트가 특정 도메인 분류에 속한다고 보장하지는 않습니다.
- geoip:private: 데이터 세트에 정의된 사설 및 예약 주소 범위를 매칭합니다. 로컬 리소스를 직결로 연결하는 데 주로 사용합니다.
- 목록을 찾을 수 없는 경우: 시작 로그에 geosite 또는 geoip를 불러올 수 없다는 메시지가 표시되면 노드 문제로 처리하지 말고 데이터 파일과 항목 이름부터 확인하세요.
4. 매칭 우선순위: 예외 규칙을 넓은 규칙보다 앞에 배치
코어는 '전체 호스트 이름이 도메인 목록보다 더 구체적이다'라고 자동으로 판단하지 않습니다. 규칙은 rules 배열의 위에서 아래 순서로 실행됩니다. 첫 번째 domain:example.com 규칙이 직결로 처리하면 뒤에 있는 full:api.example.com 프록시 규칙은 적용될 기회가 없습니다. 예외 규칙을 먼저, 범위가 넓은 목록을 그다음, 최종 기본 규칙을 마지막에 배치하세요.
아래는 기존 설정에 병합할 수 있는 routing 조각이며, 클라이언트 전체 설정은 아닙니다. 기존 outbounds에 proxy와 direct 태그가 있고 참조하는 데이터 목록도 준비되어 있어야 합니다. 실제 태그가 다르면 먼저 태그를 맞추세요. 아웃바운드를 확인하지 않고 규칙만 복사하면 안 됩니다.
{
"routing": {
"domainStrategy": "IPOnDemand",
"rules": [
{
"type": "field",
"domain": ["full:api.example.com"],
"outboundTag": "proxy"
},
{
"type": "field",
"domain": ["domain:example.com", "geosite:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"ip": ["geoip:private", "geoip:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
| 테스트 대상 | 처음 일치하는 규칙 | 예상 아웃바운드 |
|---|---|---|
| api.example.com:443 | 1번째: 전체 호스트 이름 예외 | proxy |
| www.example.com:443 | 2번째: 기본 도메인 및 하위 도메인 규칙 | direct |
| 192.168.1.20:80 | 3번째: 사설 주소 목록 | direct |
| 위 목록에 해당하지 않는 공인 네트워크 대상 | 4번째: TCP/UDP 기본 규칙 | proxy |
이 표는 설정 동작을 따라가 본 예시이며 실제 인터넷 속도 측정 결과가 아닙니다. 예시 도메인에서 실제 서비스가 제공된다고 보장할 수 없으므로 웹페이지를 검증할 때는 정상 작동이 확인된 대상을 사용하세요. 마지막 기본 규칙을 삭제하면 일치하지 않은 요청은 일반적으로 설정에서 첫 번째 아웃바운드를 사용합니다. 따라서 전체 설정을 확인하지 않고 '일치하지 않으면 무조건 프록시' 또는 '일치하지 않으면 무조건 직결'이라고 단정할 수 없습니다.
5. domainStrategy: IP 규칙이 적용되지 않는 이유
요청이 코어에 들어올 때 대상은 도메인일 수도 있고 이미 IP 주소일 수도 있습니다. IP 주소만 있는 요청은 도메인 규칙을 추가해도 원래 도메인으로 자동 복원되지 않습니다. 반대로 도메인만 있는 요청이 ip 조건에 일치하려면 일반적으로 라우팅 DNS 정책에서 주소를 확인해야 합니다. 따라서 domainStrategy를 별도로 확인해야 합니다.
| 정책 | 라우팅 단계에서의 동작 | 설정 시 주의 사항 |
|---|---|---|
AsIs | 라우팅 매칭을 위해 대상 도메인을 IP로 확인하지 않음 | 대상이 이미 IP라면 IP 규칙에 매칭될 수 있습니다. 아웃바운드가 도메인을 절대 확인하지 않는다는 뜻은 아닙니다. |
IPIfNonMatch | 도메인으로 첫 번째 규칙 검색에 실패하면 주소를 조회한 뒤 다시 매칭을 시도합니다. | 첫 번째 검색에서 조건이 없는 기본 규칙에 이미 일치하면 추가 주소 조회는 실행되지 않습니다. |
IPOnDemand | 매칭 과정에서 IP 주소가 필요한 규칙을 만나면 대상 도메인 조회를 시도합니다. | DNS 조회가 늘어날 수 있으므로 조회 지연 시간과 DNS 트래픽의 아웃바운드도 고려해야 합니다. |
앞 절에서는 세 번째 주소 목록 규칙이 마지막 기본 규칙보다 먼저 검사되도록 IPOnDemand를 사용했습니다. 이를 IPIfNonMatch로 바꾸면 도메인 요청이 네 번째의 범위가 넓은 규칙에 먼저 일치해 의도한 주소 기반 분기가 실행되지 않을 수 있습니다. 이는 geoip 문법 오류가 아니라 주소 조회가 시작되는 시점의 차이입니다.
결론: 먼저 필요한 정보를 정하세요
사이트별로 분기하려면 요청에 도메인 정보가 포함되어 있는지 먼저 확인하세요. IP 주소 기준으로 분기하려면 그다음 DNS 조회 정책을 선택합니다. DNS 서버, DNS 요청의 아웃바운드, 스니핑의 대상 적용 여부는 각각 확인해야 합니다. domainStrategy 하나를 바꿔 모든 문제를 해결할 수는 없습니다.
- 앱이 HTTP 또는 SOCKS 프록시에 직접 연결해 호스트 이름을 전달하면 코어는 일반적으로 도메인 규칙으로 바로 판단할 수 있습니다.
- 앱이 먼저 DNS 조회를 한 뒤 IP를 전달하면 도메인 정보가 사라질 수 있습니다. 스니핑은 지원되는 트래픽에서만 식별을 시도하므로 모든 요청의 도메인을 복원할 수는 없습니다.
- 라우팅의
domainStrategy와 아웃바운드 연결 단계의 유사한 DNS 조회 옵션은 역할이 다릅니다. 수정할 때 설정 계층을 확인하세요.
6. v2rayN에서 규칙 적용 및 확인
일반 사용자는 라우팅 설정 화면에서 규칙을 관리하는 것이 좋습니다. v2rayN은 실행 설정을 생성하므로 임시로 생성된 JSON을 직접 수정하면 서비스를 재시작하거나 노드를 변경할 때 덮어쓸 수 있습니다. 아래는 '설정' → '라우팅 설정' 메뉴가 있는 데스크톱 화면을 기준으로 합니다. 버전에 따라 버튼 위치는 다를 수 있지만 규칙 순서와 아웃바운드 연결은 항목별로 확인해야 합니다.
-
기존 설정 보존
'설정' → '라우팅 설정'을 열고 현재 사용 중인 규칙 세트와 도메인 확인 정책을 기록하세요. 수정 전에 기존 설정을 백업하고 기본 규칙 세트를 모두 지우지 마세요.
-
규칙 하나 추가
대상 규칙 세트에
full:api.example.com처럼 호스트 이름 전체를 지정하는 조건을 추가하고 프록시 아웃바운드를 선택하세요. 화면의 도메인 입력란에는 규칙 항목만 입력하고 전체 routing 객체를 붙여 넣지 마세요. -
규칙 순서 조정
예외 규칙을 해당
domain:,geosite:또는 다른 범위가 넓은 규칙보다 앞에 배치하세요. 저장한 뒤 메인 화면에서 방금 수정한 규칙 세트가 선택되어 있는지 확인합니다. -
연결 다시 설정
서비스를 재시작하거나 설정을 다시 불러온 뒤 대상 웹페이지의 기존 연결을 닫고 다시 접속하세요. 규칙을 바꿔도 기존 연결은 일반적으로 다른 아웃바운드로 자동 전환되지 않습니다.
-
실행 로그 확인
코어 로그에서 대상 호스트, 대상 포트, 아웃바운드 태그를 확인하세요. 정상 작동이 확인된 사이트 하나로 먼저 테스트한 뒤 규칙 범위를 넓히세요. 로그 상세 수준이 부족하면 잠시 info 또는 debug로 높이고, 확인이 끝나면 원래대로 돌리세요.
검증할 때는 최소 세 가지 요청을 테스트하세요. 예외 호스트, 같은 기본 도메인 아래의 일반 호스트, 로컬 네트워크 리소스입니다. 앞의 두 가지로 도메인 규칙의 범위를 확인하고, 세 번째로 사설 주소 직결 규칙이 앞선 광범위한 프록시 규칙에 가려지지 않는지 확인합니다. 로그에 요청이 보이지 않으면 라우팅 표현식을 계속 수정하기 전에 앱이 현재 프록시 진입점을 통과하는지 확인하세요.
7. 자주 발생하는 규칙 충돌 빠른 해결
full 규칙을 추가했는데 왜 여전히 직결되나요?
먼저 해당 도메인을 포함하는 domain:, geosite: 또는 전체 트래픽 규칙이 앞에 있는지 확인하세요. 전체 호스트 이름 예외를 범위가 넓은 규칙보다 앞에 옮기고 저장한 뒤 새 연결로 테스트합니다. 해당 규칙에서 선택한 아웃바운드 태그도 확인하세요.
domain과 ip를 함께 넣었더니 왜 매칭되지 않나요?
하나의 field 규칙에 함께 넣으면 두 조건을 모두 충족해야 합니다. '도메인 또는 주소 중 하나만 일치하면 적용'하려면 같은 아웃바운드를 사용하는 규칙 두 개로 나누세요. 두 조건을 모두 적용해야 하는 경우에만 함께 작성합니다.
geosite:cn이 있는데도 일부 사이트가 왜 프록시로 연결되나요?
먼저 실제 요청에 사용된 호스트 이름을 확인하세요. 페이지에서 불러오는 리소스는 다른 도메인을 사용할 수 있습니다. 이어서 앞선 규칙, 데이터 파일 로드 여부, 해당 도메인이 목록에 포함되어 있는지 확인합니다. full: 규칙을 명시적으로 추가해 먼저 검증할 수 있습니다. 접속 로그에서 실제 아웃바운드를 확인하세요.
port를 443으로 설정하면 모든 웹페이지와 매칭되나요?
아닙니다. 대상 포트만 제한합니다. 일반 HTTP는 80을 사용할 수 있고 다른 서비스는 사용자 지정 포트를 사용할 수 있습니다. HTTPS도 TCP 또는 UDP로 연결될 수 있으며 network: "tcp"를 추가하면 UDP 요청에는 매칭되지 않습니다.
구독을 업데이트한 뒤에도 사용자 지정 규칙이 유지되나요?
노드 구독과 라우팅 규칙은 서로 다른 설정 항목입니다. 업데이트 후 현재 규칙 세트가 계속 선택되어 있는지, 프록시 아웃바운드가 유효한 노드를 가리키는지 확인하세요. 구독 주소를 라우팅 설정으로 사용하거나 라우팅 JSON을 구독 주소 입력란에 붙여 넣지 마세요.
문제 해결 순서는 일정하게 유지하세요. 요청이 코어에 들어오는지 확인하고, 도메인 또는 주소 정보를 사용할 수 있는지 확인한 뒤, 처음으로 일치한 규칙과 아웃바운드 연결 상태를 점검합니다. 한 번에 한 종류의 조건만 수정해야 규칙 범위, DNS 정책, 노드 네트워크 중 무엇이 결과를 바꿨는지 파악할 수 있습니다.