수동으로 트래픽 분기를 조정하려는 사용자를 위한 안내입니다. 도메인, IP, 데이터셋의 매칭 문법을 구분하고 routing 예제로 규칙 순서, 필드 조합, DNS 조회 시점을 살펴봅니다. 문제를 진단할 때는 클라이언트 화면의 ‘직접 연결’, ‘프록시’라는 이름을 outboundTag로 간주하지 말고, 커널에 실제 전달된 설정을 기준으로 확인하세요.
1. 라우팅 대상과 규칙 적용 순서
V2Ray의 routing은 연결의 대상 주소, 대상 포트, 네트워크 유형, 인바운드 태그 등을 기준으로 아웃바운드를 선택합니다. 웹페이지 콘텐츠를 필터링하거나 URL 경로에 따라 트래픽을 분기하는 기능은 아닙니다. 같은 도메인의 서로 다른 페이지에 접속해도 보통 도메인 규칙은 동일하게 적용됩니다.
routing.rules는 배열에 적힌 순서대로 위에서 아래로 확인합니다. 조건을 만족하는 규칙을 찾으면 지정된 아웃바운드를 사용하며, 뒤에 있는 규칙과 ‘어느 쪽이 더 정확한지’를 비교하지 않습니다. 따라서 특정 도메인 예외는 도메인 접미사 규칙보다 앞에, 구체적인 규칙은 기본 처리 규칙보다 앞에 배치하세요.
- 규칙 간 순서: 먼저 일치하는 규칙이 결과를 결정합니다. 도메인 길이, 접두어 유형, 네트워크 크기에 따라 자동으로 정렬되지 않습니다.
- 같은 필드 안의 조건: 예를 들어
domain배열에 항목이 여러 개 있으면 하나만 일치해도 됩니다. - 서로 다른 조건 필드: 예를 들어
domain과port를 함께 지정하면 둘 다 만족해야 합니다. 한 규칙에domain과ip를 넣어도 ‘도메인 또는 IP’ 조건이 되지는 않습니다. - 어떤 규칙에도 일치하지 않는 경우: 다른 라우팅 메커니즘을 설정하지 않은 일반적인 구성에서는
outbounds배열의 첫 번째 아웃바운드를 사용합니다. 이 아웃바운드가 직접 연결이라는 보장은 없습니다.
2. domain, full, regexp, geosite 작성법
domain은 규칙 필드 이름이고, domain:은 해당 필드에서 사용하는 매칭 접두어입니다. 둘을 혼동하지 마세요. 아래 예시는 모두 문법 설명을 위한 예약 도메인 example.com을 사용하며, 실제 서비스의 트래픽 분기 권장안이 아닙니다.
| 항목 작성법 | 매칭 방식 | 주의 사항 |
|---|---|---|
full:example.com | 해당 도메인 전체와 일치 | www.example.com은 포함하지 않음 |
domain:example.com | 해당 도메인과 하위 도메인에 일치 | api.example.com은 포함하지만 notexample.com은 포함하지 않음 |
example.com | 접두어가 없으면 부분 문자열로 매칭 | 도메인에 이 문자열이 포함된 다른 이름도 일치할 수 있음 |
regexp:^api[0-9]+\.example\.com$ | 정규식으로 매칭 | JSON에 입력할 때 백슬래시를 한 번 더 이스케이프해야 함 |
geosite:cn | 도메인 데이터 파일의 cn 분류 참조 | 분류 내용은 실제로 불러온 데이터 파일에 따라 달라짐 |
사이트와 모든 하위 도메인을 포함하려면 원문자열에 의존하지 말고 domain:example.com을 사용하세요. 호스트 이름 하나만 대상으로 할 때는 full:을 쓰면 됩니다. 도메인 항목에는 https://, 포트, 경로, 쿼리 매개변수를 넣지 마세요. 이 필드는 해당 형식을 입력으로 받지 않습니다.
{
"type": "field",
"domain": [
"full:status.example.com",
"domain:example.net",
"regexp:^api[0-9]+\\.example\\.com$"
],
"outboundTag": "proxy"
}
이 JSON에서 도메인 항목 세 개는 OR 조건입니다. 정규식의 \\.은 JSON을 디코딩한 다음 정규식에 필요한 \.이 됩니다. 백슬래시를 하나만 입력하면 JSON 파싱 단계에서 설정이 실패할 수 있습니다. 정규식은 커널에서 사용하는 Go 정규식 문법을 따라야 하며, 역참조나 전후방 탐색은 사용할 수 없습니다.
판단 기준: 단일 사이트 규칙에는 full 또는 domain 사용
도메인 구조를 패턴으로 표현해야 할 때만 regexp를 사용하세요. 수정한 뒤에는 기본 도메인, 하위 도메인 하나, 비슷하지만 관련 없는 도메인을 각각 테스트해 부분 문자열이 잘못 매칭되지 않는지 확인하세요.
3. ip, geoip, 대상 포트 조합하기
ip 필드에는 단일 IP 주소, CIDR 대역, geoip: 데이터셋 참조를 지정할 수 있습니다. IPv4의 /32는 주소 하나를 뜻하며, 192.0.2.0/24는 문서용 예시 대역입니다. CIDR을 domain 배열에 넣거나 ip 배열에 https://를 추가하지 마세요.
{
"type": "field",
"ip": [
"192.0.2.0/24",
"2001:db8::/32"
],
"port": "443",
"network": "tcp",
"outboundTag": "direct"
}
이 규칙은 대상 주소가 예시 대역 둘 중 하나에 속하고, 대상 포트가 443이며, 네트워크가 TCP인 연결만 매칭합니다. 같은 주소의 TCP 80이나 UDP 443은 매칭하지 않습니다. 여기서 port는 대상 포트이며 클라이언트의 로컬 수신 대기 포트가 아닙니다. 인바운드를 태그로 구분하려면 inboundTag를 사용하세요.
geoip:private는 사설 및 로컬 주소 대역의 트래픽을 분기할 때 자주 사용합니다. 구체적인 포함 범위는 불러온 데이터 파일에 따라 달라집니다.geoip:cn은 IP 분류 참조이고,geosite:cn은 도메인 분류 참조입니다. 서로 바꿔 쓸 수 없습니다.- 도메인 분류와 IP 분류의 결과가 항상 일치하는 것은 아닙니다. 도메인이 여러 지역의 CDN 주소로 연결될 수도 있습니다.
- IPv4 대역만 지정하면 IPv6 연결은 포함되지 않습니다. 듀얼 스택 환경에서는 실제로 사용되는 주소 계열도 확인하세요.
4. domainStrategy에 따른 라우팅 도메인 조회 시점
routing.domainStrategy는 라우팅 단계에서 도메인 대상 주소를 어떻게 처리할지 제어합니다. 시스템 DNS 설정이나 아웃바운드 자체의 동명 또는 유사 설정과는 다릅니다. 라우팅 단계에서 도메인을 조회하지 않더라도, 서버에 연결하기 위해 이후 아웃바운드에서 주소를 조회할 수 있습니다.
| 값 | 라우팅 단계의 동작 | 일반적인 영향 |
|---|---|---|
AsIs | 원래 대상 정보로 매칭하며, 라우팅을 위해 별도로 도메인을 조회하지 않음 | 대상이 도메인뿐이라면 IP 규칙에서 사용할 조회 결과를 얻지 못함 |
IPIfNonMatch | 도메인 단계에서 일치하는 규칙이 없으면 조회한 뒤 다시 매칭 | 앞선 도메인 규칙이나 일반적인 기본 처리 규칙이 일치하면 조회 단계가 실행되지 않을 수 있음 |
IPOnDemand | 매칭 중 IP 판정이 필요한 규칙을 만나면 도메인 조회 시도 | 뒤에 있는 도메인 규칙보다 앞선 IP 규칙이 먼저 결과를 결정할 수 있음 |
놓치기 쉬운 사례는 IPIfNonMatch를 사용하면서 마지막에 모든 TCP·UDP 연결과 일치하는 규칙을 추가하는 경우입니다. 도메인 요청이 이 기본 처리 규칙에 바로 일치하면 ‘앞의 geoip 규칙이 일치하지 않은 뒤 자동으로 조회하여 다시 시도’하는 흐름이 이어지지 않습니다. 도메인 규칙을 먼저 적용한 뒤 조회된 IP로 분기하려면 조회 전략과 기본 처리 규칙을 함께 검토하세요.
도메인 먼저 매칭하고, 일치하지 않으면 조회
- domainStrategy
- IPIfNonMatch
- 규칙 시작
- 명시적인 도메인 예외
- 이후 조건
- 추가 판정이 필요한 IP 규칙
- 기본 처리 규칙 확인
- 일반 규칙이 먼저 일치하지 않도록 주의
모든 규칙이 일치하지 않을 때 첫 번째 아웃바운드가 의도한 기본 아웃바운드인지 확인하세요.
규칙 순서에 따라 필요한 경우 조회
- domainStrategy
- IPOnDemand
- 규칙 시작
- 우선 적용할 도메인 예외
- 이후 조건
- IP 또는 geoip 조건
- 기본 처리 규칙 확인
- IP 판정 후 명시적으로 기본 처리 규칙을 둘 수 있음
먼저 DNS 조회가 결과를 반환하는지 테스트한 다음, IP 분류 결과가 예상과 일치하는지 확인하세요.
애플리케이션이 커널에 전달하는 대상이 이미 IP라면, 이 설정으로 주소를 얻을 필요가 없습니다. 다만 이 경우 도메인 정보가 없을 수 있습니다. 일부 프로토콜에서는 인바운드 스니핑으로 도메인 정보를 보완할 수 있지만, 지원 여부는 트래픽 유형과 구체적인 설정에 따라 달라집니다. 스니핑을 켜면 모든 연결의 도메인 정보가 복원된다고 볼 수는 없습니다.
5. 순서를 확인하는 routing 예제
아래는 설정 일부이며 단독으로 실행할 수 있는 완전한 설정 파일이 아닙니다. proxy, direct, block 아웃바운드 태그가 이미 있고 각각 프록시, 직접 연결, 차단 아웃바운드를 가리킨다고 가정합니다. 태그는 설정 작성자가 정의하는 이름이지 커널이 자동으로 만드는 예약 이름이 아닙니다. 또한 이 예제에는 private 분류가 포함된 데이터 파일이 필요합니다.
{
"routing": {
"domainStrategy": "IPOnDemand",
"rules": [
{
"type": "field",
"domain": ["full:status.example.com"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["domain:example.com"],
"outboundTag": "proxy"
},
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"port": "6881-6889",
"outboundTag": "block"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
- 구체적인 예외를 먼저:
status.example.com은 1번 규칙에 일치해 직접 연결되며, 2번 규칙의 전체 도메인 접미사 규칙까지 진행하지 않습니다. - 사이트 규칙은 그다음:
www.example.com은 2번 규칙에 일치해proxy를 선택합니다. - 사설 주소 우선 처리: 앞의 두 규칙에 일치하지 않으면 사설 주소가 3번 규칙에 일치할 수 있습니다. 이때 도메인 대상은 필요에 따라 조회될 수 있습니다.
- 포트 규칙은 전체 연결에 적용되는 차단 규칙이 아닙니다: 4번 규칙은 앞에서 일치하지 않은 연결만 처리합니다. 이미 앞선 규칙에 일치한 사이트나 사설 주소는 이 규칙으로 넘어오지 않습니다.
- 명시적인 기본 처리 규칙은 마지막에: 나머지 TCP·UDP 연결은 5번 규칙에 일치합니다. 여기서는
IPOnDemand를 사용해 앞에 있는 IP 판정이 먼저 실행될 수 있도록 합니다.
조정 방법: 전체에 적용할 제한은 앞쪽으로 이동
포트 6881–6889를 우선 차단해야 한다면 포트 규칙을 도메인 및 사설 주소 규칙보다 앞에 배치하세요. 조정할 것은 배열의 위치이지, 존재하지 않는 ‘우선순위 숫자’가 아닙니다.
geosite:cn을 사용할 때는 필요에 따라 도메인 규칙을 추가할 수 있지만, 익숙한 분류 이름이라는 이유만으로 모든 예외를 덮어쓰지는 마세요. 먼저 데이터 파일을 불러올 수 있는지 확인한 다음, 이 규칙을 구체적인 도메인 예외 뒤에 둘지, IP 규칙 앞에 둘지 또는 다른 위치에 둘지 판단하세요. 데이터가 업데이트되면 분류 결과도 달라질 수 있습니다.
6. 클라이언트 화면에서 실제 적용 설정까지 확인하기
v2rayN, v2rayNG, v2flyNG의 화면에 표시되는 이름과 라우팅 규칙 가져오기 방식은 버전에 따라 달라집니다. 문제를 진단할 때는 먼저 클라이언트 버전, 커널 이름, 사용 중인 라우팅 모드를 기록한 다음 현재 활성화된 규칙 세트를 확인하세요. 구독 노드의 VMess, VLESS 연결 매개변수를 라우팅 규칙으로 혼동하지 마세요. 노드는 아웃바운드 연결을 정의하고 라우팅은 사용할 아웃바운드를 선택합니다.
- 현재 규칙 백업: 수정하기 전에 현재 라우팅 설정을 저장하세요. 구독 업데이트는 보통 노드 갱신에 사용하는 기능이지, 로컬 사용자 지정 라우팅 규칙을 배포하는 범용 기능이 아닙니다.
- 요청이 커널에 들어오는지 확인: 애플리케이션이 시스템 프록시 또는 지정된 로컬 프록시 입구를 사용하는지 확인하세요. 인바운드에 들어오지 않는 요청은 이 규칙의 적용을 받지 않습니다.
- 생성된 설정 확인: 현재
routing.rules의 실제 순서와outboundTag가outbounds[].tag와 정확히 일치하는지 살펴보세요. - 적용 후 다시 테스트: 규칙을 저장한 다음 클라이언트 안내에 따라 설정을 다시 불러오거나 커널을 재시작하고, 새 연결을 만드세요. 브라우저가 연결을 재사용하면 기존 아웃바운드로 연결이 계속 유지될 수 있습니다.
- 로그 확인: 필요한 경우 일시적으로 로그 수준을
info로 설정해 인바운드, 대상, 선택된 아웃바운드를 확인하세요. 커널마다 로그 형식이 달라 구체적인 규칙 번호가 표시되지 않을 수도 있습니다.
한 번에 조건 하나만 변경하는 것이 좋습니다. 먼저 full:로 특정 도메인의 분기가 되는지 확인하고, 다음으로 domain:을 적용해 범위를 넓힌 뒤 geosite 또는 geoip 분류를 추가하세요. 설정 항목의 맥락을 확인하려면 설정 레퍼런스에서 인바운드, 아웃바운드, DNS 필드를 함께 살펴보세요.
7. 라우팅 규칙 자주 묻는 질문
도메인 규칙을 추가했는데 왜 기존 노드로 연결되나요?
먼저 앞에 있는 더 포괄적인 규칙이 이미 일치하는지 확인하세요. 테스트용 full: 규칙을 잠시 맨 위에 배치하고 커널을 다시 불러온 뒤 새 연결을 만드세요. 그래도 적용되지 않으면 요청 대상이 도메인인지 IP인지, 트래픽이 실제로 현재 클라이언트를 통과하는지 확인하세요.
geosite 또는 geoip에서 분류를 찾을 수 없다고 나오면 무엇을 확인해야 하나요?
현재 커널이 실제로 사용하는 데이터 파일과 그 안의 분류 이름을 확인하세요. geosite:는 domain에, geoip:는 ip에 넣어야 합니다. 데이터 파일 누락을 처리하기 전에 도메인 하나 또는 명확한 네트워크 대역으로 규칙 구조부터 확인하세요. 노드 비밀번호를 반복해서 바꿔도 해결되지 않습니다.
한 규칙에 domain과 ip를 함께 지정하면 왜 매칭이 더 어려워지나요?
두 필드는 둘 다 충족해야 하며 둘 중 하나만 충족하면 되는 조건이 아닙니다. ‘이 도메인 또는 이 네트워크 대역을 모두 직접 연결’하려면 규칙을 두 개로 나누고, 각 규칙에 같은 outboundTag를 지정하세요. 분리한 뒤에는 도메인 조회 전략이 IP 조건을 판정에 반영할 수 있는지도 확인하세요.
IPIfNonMatch로 바꿨는데도 geoip가 적용되지 않나요?
마지막에 network: "tcp,udp"와 같은 일반 매칭 규칙이 있는지 확인하세요. 도메인 단계에서 이 규칙이 먼저 일치해 ‘일치하지 않으면 조회’ 흐름을 막을 수 있습니다. 필요에 따라 조회를 지연 실행하도록 조정하거나, 먼저 실행되는 기본 처리 규칙을 제거하고 기본 아웃바운드를 확인하세요. 어느 쪽이든 도메인 대상과 IP 대상을 다시 테스트해야 합니다.