노드 연결은 되며 트래픽 분기를 조정하려는 사용자에게 적합합니다. V2Ray / Xray의 핵심 라우팅 구조를 바탕으로 도메인 접미사, 전체 도메인, IP 대역, 분류 데이터를 구분하고, 단계별로 결과를 확인할 수 있는 규칙 예시를 살펴봅니다. 이어서 v2rayN과 v2rayNG에서 실제 적용 결과를 확인하는 방법도 안내합니다. 규칙을 무작정 늘리는 대신 각 요청의 출구를 명확히 정하고 검증하는 것이 핵심입니다.
라우팅 시작점: 요청이 코어에 전달되는지 확인
시스템 프록시와 라우팅 규칙은 서로 다른 단계에서 작동합니다. 시스템 프록시는 프록시를 지원하는 앱의 요청을 로컬 포트로 전달하고, 코어 라우팅은 이미 코어에 들어온 요청이 어떤 아웃바운드를 사용할지 결정합니다. 브라우저가 시스템 프록시를 사용하지 않거나 프로그램이 직접 연결하면 아무리 정확한 geosite 규칙도 해당 연결에 적용되지 않습니다. TUN을 사용하면 더 많은 트래픽을 처리할 수 있지만, TUN 사용 여부와 관계없이 규칙은 위에서 아래 순서로 매칭됩니다.
v2rayN은 데스크톱 클라이언트로, 코어 설정을 생성하고 실행합니다. v2rayNG는 Xray 코어를, v2flyNG는 V2Fly 코어를 사용합니다. 클라이언트 화면의 라우팅 프리셋은 프로토콜 자체와 다릅니다. VMess와 VLESS는 프록시 연결에 사용하는 프로토콜이며, domain, ip, outboundTag는 로컬 트래픽 분기를 설정합니다. 노드 프로토콜을 바꿔도 잘못 작성한 도메인 규칙이 자동으로 수정되지는 않습니다.
domain 문법: 접미사 매칭은 문자열 접두사 매칭이 아닙니다
규칙의 domain은 문자열 배열이며, 배열 항목 중 하나라도 일치하면 해당 도메인 조건이 충족됩니다. 문자열 앞의 domain:, full:, regexp:는 매칭 방식을 지정합니다. 특히 domain:은 지정한 도메인과 하위 도메인을 매칭하며, 도메인이 해당 문자열로 시작하는지를 검사하는 방식이 아닙니다.
| 규칙 문자열 | 매칭 기준 | 테스트 대상 |
|---|---|---|
domain:example.test | 도메인 및 하위 도메인 | example.test, api.example.test와 일치하고 notexample.test와는 일치하지 않습니다 |
full:api.example.test | 전체 도메인 완전 일치 | api.example.test와 일치하고 img.api.example.test와는 일치하지 않습니다 |
example | 접두어 없는 부분 문자열 매칭 | another-example.test도 매칭될 수 있어 범위가 넓습니다 |
regexp:^api[.]example[.]test$ | 정규식 매칭 | 이 문법은 전체 도메인 하나만 지정합니다 |
geosite:cn | 데이터 파일의 cn 분류와 매칭 | 실제 범위는 사용 중인 geosite 데이터에 따라 달라집니다 |
서비스 하나와 모든 하위 도메인을 직접 연결하려면 domain:을 우선 사용하세요. 특정 API 하나만 예외로 두려면 full:을 사용하면 됩니다. 접두어 없는 문자열은 매칭 범위를 정확히 알고 있는 키워드 규칙에 적합하며, 짧은 단어를 정확한 도메인처럼 쓰기에는 적합하지 않습니다. 정규식 문법은 코어의 정규식 구현에 따라 제한될 수 있으므로 복잡한 표현식은 먼저 검증해야 합니다. 다른 도구에서 지원하는 기능을 모두 그대로 사용할 수 있는 것은 아닙니다.
{
"type": "field",
"domain": [
"full:api.example.test",
"domain:assets.example.test"
],
"outboundTag": "direct"
}
이 규칙은 지정된 API나 정적 리소스 도메인만 직접 연결하며 example.test 전체를 직접 연결하지는 않습니다. 정규식을 JSON에 넣을 때는 역슬래시 이스케이프에도 주의하세요. 점을 나타내는 \.을 사용한다면 JSON 문자열에는 \\.으로 작성해야 합니다. 위 표에서는 점을 [.]으로 표시해 이중 이스케이프로 인한 입력 실수를 줄였습니다.
ip와 geoip: 주소 범위, 분류, 조건 조합
ip 배열에는 단일 주소, CIDR 대역, geoip: 분류를 넣을 수 있습니다. CIDR에서 슬래시 뒤의 숫자는 네트워크 접두사 길이입니다. 192.168.0.0/16은 사설 주소 범위 전체를 의미하며 로컬 네트워크 주소 하나만 매칭하는 것이 아닙니다. IPv6도 fc00::/7처럼 쓸 수 있습니다. 분류 규칙을 사용하려면 코어가 GeoIP 데이터를 읽을 수 있어야 합니다.
주소 수는 대역에 포함된 전체 주소를 뜻하며, 호스트에 할당할 수 있는 주소 수와는 다릅니다. geoip:private는 사설 네트워크와 특수 로컬 주소를 분기할 때 자주 사용하고, geoip:cn은 데이터 파일에서 중국으로 분류된 IP 대역에 사용합니다. 후자는 중국어 웹사이트를 뜻하지 않으며 도메인 분류와 범위가 완전히 일치한다고 보장할 수도 없습니다. 한 도메인이 여러 지역의 CDN 주소를 사용할 수 있고, 주소 분류는 DNS 응답에 따라 달라질 수 있습니다.
{
"type": "field",
"ip": ["192.168.0.0/16"],
"port": "443",
"network": "tcp",
"outboundTag": "direct"
}
요점: 한 규칙의 필드들은 AND 조건입니다
위 규칙은 대상 IP가 지정된 대역에 속하고, 대상 포트가 443이며, 네트워크가 TCP인 조건을 모두 만족해야 직접 연결됩니다. 지정된 도메인 또는 IP를 직접 연결하려면 규칙을 두 개로 나누세요. domain과 ip를 한 규칙에 함께 넣어도 둘 중 하나만 일치하는 조건이 되지는 않습니다.
geosite와 domainStrategy: 도메인 분류와 DNS 조회 시점
geosite:cn은 데이터 파일에 정의된 분류 이름이지 온라인 검색 명령이 아닙니다. 코어가 해당 분류를 포함하는 geosite.dat를 읽을 수 있어야 합니다. 데이터 출처에 따라 포함된 태그가 다를 수 있으며, 노드 구독 정보를 갱신해도 분류 파일까지 업데이트되는 것은 아닙니다. 시작 로그에 “분류를 찾을 수 없음” 또는 “데이터 파일을 읽을 수 없음”이 표시되면 규칙 순서를 조정하기 전에 리소스 문제부터 해결하세요.
도메인을 먼저 매칭하고 추가 조회하지 않음
- 필드 위치
routing.domainStrategy- 값
AsIs- 도메인 요청
- 도메인 규칙을 바로 매칭합니다
- IP 조건
- 라우팅 매칭을 위해 도메인을 별도로 조회하지 않습니다
명시적인 도메인 규칙을 기준으로 아웃바운드를 결정하려는 설정에 적합합니다. 단, 아웃바운드 연결 자체에는 도메인 조회가 필요할 수 있습니다.
도메인 규칙이 일치하지 않으면 IP를 추가 확인
- 필드 위치
routing.domainStrategy- 값
IPIfNonMatch- 조회가 시작되는 조건
- 첫 번째 라우팅 매칭에서 규칙이 적용되지 않음
- 이후 처리
- 조회한 주소를 기준으로 다시 매칭합니다
도메인 분류에 더해 IP 분류로 트래픽 분기를 보완할 때 적합하지만, 첫 번째 매칭에서 규칙이 적용되지 않을 여지를 남겨야 합니다.
또 다른 자주 쓰이는 값은 IPOnDemand입니다. 매칭 과정에서 IP가 필요한 규칙을 만나면 조회가 시작될 수 있습니다. 따라서 앞쪽의 IP 규칙이 뒤쪽 도메인 예외보다 먼저 적용될 수 있습니다. IPIfNonMatch와의 핵심 차이는 어느 쪽이 “더 강한지”가 아니라 조회가 시작되는 시점입니다.
여기서 설명하는 설정은 routing 아래의 domainStrategy입니다. DNS 모듈의 조회 전략이나 직접 연결 아웃바운드의 도메인 전략과는 별개의 설정입니다. 라우팅을 위한 조회는 매칭에 필요한 정보만 제공하며 DNS 요청이 지정한 아웃바운드로 나간다고 보장하지 않습니다. DNS 서버 연결 여부, 조회 경로, 앱 자체의 도메인 조회 방식은 별도로 확인해야 합니다.
매칭 우선순위: 구체적인 예외를 먼저, 범위가 넓은 규칙은 나중에
코어는 rules 배열을 위에서 아래로 확인하고, 조건을 만족하는 첫 번째 규칙으로 라우팅을 결정합니다. 뒤쪽 규칙의 도메인이 더 길다고 해서 자동으로 우선 선택되지는 않습니다. 따라서 “더 구체적”이라는 것은 순서를 정하는 기준일 뿐, 코어가 자동 계산하는 우선순위가 아닙니다. 규칙의 태그는 정의된 아웃바운드를 가리켜야 합니다. 어떤 규칙도 적용되지 않으면 일반적으로 proxy라는 태그를 자동 선택하는 것이 아니라 outbounds 배열의 첫 번째 아웃바운드를 사용합니다.
- 서비스별 예외: 프록시 또는 직접 연결이 필요한 전체 도메인, 좁은 범위의 접미사, 특정 IP 대역을 먼저 배치합니다.
- 로컬 네트워크 보호: 사설 주소 규칙을 다음에 배치해 로컬 기기 요청이 기본적으로 프록시로 전달되지 않도록 합니다. 기업 내부망에 별도 출구가 필요하면 더 구체적인 예외를 먼저 작성하세요.
- 분류 규칙: 적용 범위가 넓은 geosite, geoip 등의 트래픽 분기 조건을 배치합니다.
- 기본 처리: 마지막에 나머지 연결의 경로를 명시하고, 이 규칙이 조회 전략의 실행 조건을 바꾸지는 않는지 확인합니다.
아래는 routing 설정 조각입니다. api.example.test는 프록시로 연결하고, 같은 상위 도메인의 나머지 요청은 직접 연결합니다. 사설 주소와 중국 분류는 직접 연결하고 나머지 TCP / UDP 요청은 프록시로 보냅니다. IPOnDemand를 사용하는 이유는 도메인 분류에 해당하지 않는 요청도 IP 규칙에서 조회 결과를 활용할 수 있게 하기 위해서입니다. 이 조각은 기존 코어 설정에 병합해야 하며, 완전한 설정 파일처럼 단독으로 실행할 수 없습니다.
{
"routing": {
"domainStrategy": "IPOnDemand",
"rules": [
{
"type": "field",
"domain": ["full:api.example.test"],
"outboundTag": "proxy"
},
{
"type": "field",
"domain": ["domain:example.test"],
"outboundTag": "direct"
},
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"ip": ["geoip:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
| 입력 조건 | 매칭 규칙 | 출구 |
|---|---|---|
| 도메인 api.example.test | 첫 번째 전체 도메인 규칙 | proxy |
| 도메인 img.example.test | 두 번째 도메인 접미사 규칙 | direct |
| 대상 IP 192.168.1.10 | 세 번째 사설 주소 규칙 | direct |
| 앞선 분류에 해당하지 않는 도메인, 조회된 IP는 geoip:cn에 해당 | 다섯 번째 IP 분류 규칙 | direct |
| 나머지 미매칭 TCP 요청 | 여섯 번째 기본 처리 규칙 | proxy |
두 번째 규칙을 첫 번째 규칙보다 앞에 옮기면 api.example.test가 상위 도메인 규칙에 먼저 매칭되어 직접 연결됩니다. 기본 처리 규칙을 배열 맨 위로 옮기면 뒤에 있는 규칙은 대부분 적용되지 않습니다. 충돌을 점검할 때는 원하는 규칙만 들여다보지 말고 실제 대상에 맞춰 첫 번째 규칙부터 차례로 확인하세요.
클라이언트에 적용하기: 생성된 설정을 확인하고 간단히 테스트
v2rayN의 「설정」→「라우팅 설정」에서 현재 라우팅 설정을 확인할 수 있습니다. 메뉴 이름은 버전에 따라 다를 수 있습니다. 선택되지 않은 다른 프리셋이 아니라 현재 활성화된 설정을 편집했는지 확인하세요. 「설정」→「매개변수 설정」에서 로컬 수신 포트도 확인합니다. 아래 테스트는 SOCKS가 127.0.0.1:10808에서 수신한다고 가정합니다. 실제 값이 다르면 바꿔 입력하세요. 예시 포트를 모든 버전의 고정 기본값으로 간주하면 안 됩니다.
- 현재 규칙을 백업합니다. 사용 중인 코어, 라우팅 프리셋, 도메인 전략, 아웃바운드 태그를 기록하고 확인하기 쉬운 도메인 예외 하나만 먼저 추가합니다.
- 저장한 뒤 다시 적용합니다. 클라이언트의 현재 절차에 따라 코어를 재시작하거나 다시 연결해 설정을 생성합니다. 편집 창에서 저장하는 것만으로 실행 중인 설정까지 전환되지는 않을 수 있습니다.
- 실행 로그를 확인합니다. 먼저 JSON 파싱 오류, 분류 누락, 존재하지 않는 아웃바운드 태그, 수신 포트 충돌이 없는지 확인하세요. 필요하면 로그 수준을 일시적으로 높이고 테스트가 끝난 뒤 원래대로 되돌립니다.
- 실제 접속 대상과 비교합니다. 연결 로그나 접속 로그에서 대상 도메인, 대상 IP, 아웃바운드 태그를 확인하세요. 로그 형식은 코어와 로그 수준에 따라 달라집니다.
- 그다음 적용 범위를 넓힙니다. 단일 예외의 동작을 확인한 뒤 geosite / geoip 분류와 기본 처리 규칙을 추가하세요. 여러 항목을 한 번에 바꾸면 원인을 찾기 어려워집니다.
curl --socks5-hostname 127.0.0.1:10808 \
--connect-timeout 10 \
--max-time 20 \
-I https://v2rayworld.com/
--socks5-hostname은 대상 도메인을 SOCKS 서버 측에 전달하므로 도메인 규칙 테스트에 유용합니다. --socks5는 보통 로컬에서 먼저 이름을 조회하기 때문에 코어에 IP 주소가 전달될 수 있습니다. 연결 시간 초과 10초와 전체 시간 초과 20초는 테스트 대기 시간을 제한하는 값이지 지연 시간이나 속도 측정 결과가 아닙니다. HTTP 요청이 성공해도 해당 요청을 사용할 수 있다는 뜻일 뿐, 지정한 규칙에 매칭됐는지는 아웃바운드 기록을 확인해야 합니다.
v2rayNG에서는 먼저 현재 라우팅 모드를 확인한 다음 「설정」에서 해당 라우팅 설정 메뉴로 이동하세요. 메뉴 위치는 버전에 따라 다를 수 있습니다. Android VPN의 트래픽 처리 여부는 앱별 프록시 범위에도 영향을 받을 수 있으므로 테스트할 브라우저가 적용 범위에 포함되어야 합니다. v2flyNG는 V2Fly의 실제 설정을 기준으로 코어 기능과 리소스 파일을 확인하세요. Xray 전용 필드를 그대로 옮겨 사용하면 안 됩니다. 여기서 설명하는 기본 field 규칙도 최종적으로는 현재 코어가 시작되는지 확인해야 합니다.
자주 묻는 질문: 도메인이 매칭되지 않거나 분류 오류가 발생하거나 규칙이 덮어써지는 경우
도메인 규칙을 제대로 작성했는데 왜 IP 규칙이 적용되나요?
먼저 인바운드에 도메인과 IP 중 무엇이 전달됐는지 확인하세요. 위의 --socks5-hostname 테스트와 비교해 보면 됩니다. 앱이 이미 도메인을 IP로 조회했다면 도메인 규칙을 매칭할 정보가 없을 수 있습니다. 스니핑은 일부 HTTP / TLS 트래픽에서 도메인을 추출할 수 있지만 모든 연결에서 가능한 것은 아니며, 모든 트래픽을 안정적으로 처리하는 해결책으로 볼 수 없습니다.
geosite:cn을 저장하자마자 실행되지 않습니다. 어떻게 해야 하나요?
코어 로그에서 geosite 파일을 찾을 수 없거나 cn 분류가 없다는 메시지가 표시되는지 확인하세요. 리소스 파일 위치와 읽기 권한, 클라이언트가 사용하는 데이터 출처도 점검합니다. 먼저 백업한 규칙을 복원해 코어를 시작한 다음 클라이언트의 리소스 업데이트 메뉴로 데이터를 처리하세요. 리소스 오류를 숨기려고 라우팅 규칙을 모두 삭제하지 마세요.
domain과 ip를 추가했더니 직접 연결 범위가 오히려 줄었어요.
두 조건을 한 field 규칙에 함께 넣었는지 확인하세요. 도메인 또는 주소 중 하나만 일치하면 되는 경우 규칙을 두 개로 나누고 같은 아웃바운드를 지정해야 합니다. 한 규칙에 필드가 두 개 있으면 둘 다 만족해야 하며, 도메인 요청이 IP 조건을 만족하려면 조회 전략도 영향을 줍니다.
코어 설정을 바꿨는데 다음 연결 때 원래대로 돌아가요.
클라이언트가 시작할 때 임시 코어 설정을 다시 생성할 수 있습니다. 실행 중 생성된 임시 파일만 편집하지 말고 현재 라우팅 프리셋이나 클라이언트가 지원하는 사용자 지정 설정 메뉴에서 수정하세요. 저장 후 다시 적용하고 생성된 rules의 순서를 확인해 프리셋 규칙이 변경 내용을 덮어쓰지 않았는지 점검합니다.
최종 점검은 요청이 코어에 전달되는지, 대상에 도메인이 포함되는지, 분류 리소스를 읽을 수 있는지, 규칙 순서가 예상대로인지, 아웃바운드 태그가 유효한지 순서대로 확인하면 됩니다. 브라우저가 기존 연결을 재사용할 수 있으므로 수정 후 새 요청을 보내거나 테스트 앱을 다시 시작하세요. 매칭 결과를 확인한 다음 일반 도메인, 로컬 네트워크 IP, 미분류 대상을 각각 테스트해야 합니다. 웹사이트 하나만 확인하고 전체 트래픽 분기가 정상이라고 판단하지 마세요.