라우팅 규칙이 처리하는 대상부터 이해하기
V2Ray와 Xray의 라우팅 모듈은 인바운드와 아웃바운드 사이에 있습니다. 애플리케이션 트래픽이 코어로 들어오면 라우팅 모듈은 대상 도메인, 대상 IP, 포트, 네트워크 유형, 인바운드 태그 등의 정보를 읽은 뒤 해당 연결을 특정 아웃바운드로 전달합니다. 대표적인 아웃바운드 태그로는 프록시 연결에 사용하는 proxy, 로컬 직접 연결에 사용하는 direct, 연결 거부에 사용하는 block이 있습니다. 이 이름들은 고정 키워드가 아니라 설정의 outbounds 항목에 지정된 tag 값이며, 규칙의 outboundTag는 실제 태그와 정확히 일치해야 합니다.
VMess, VLESS 등의 프로토콜은 클라이언트와 원격 서버 사이에서 데이터를 전송하는 방식을 담당하고, 라우팅 규칙은 어떤 아웃바운드를 선택할지 결정합니다. 두 기능은 서로 다른 계층에 있습니다. VMess를 VLESS로 바꿔도 분기 결과가 자동으로 달라지지는 않으며, 새 구독을 가져왔다고 해서 기존 사용자 지정 규칙이 반드시 계속 적용되는 것도 아닙니다. v2rayN, v2rayNG 또는 v2flyNG를 사용할 때는 현재 설정, 라우팅 모드, 코어 유형을 각각 확인하고 규칙이 실제 실행 중인 설정에 반영되었는지 점검해야 합니다.
일반적인 필드 규칙은 type, 매칭 조건, 대상 아웃바운드로 구성됩니다. 현재 가장 널리 사용하는 유형은 field입니다. 하나의 규칙에는 도메인과 포트를 동시에 제한하는 것처럼 여러 조건 범주가 포함될 수 있으며, 서로 다른 범주는 보통 모두 충족해야 합니다. 같은 범주에 여러 값을 넣으면 후보 목록으로 처리되므로, 그중 하나만 일치해도 해당 규칙이 적용됩니다.
{
"type": "field",
"domain": [
"domain:example.com",
"full:api.example.net"
],
"port": "443",
"network": "tcp",
"outboundTag": "proxy"
}
이 예시는 TCP 443 포트만 처리하며, 대상 도메인이 두 항목 중 하나와 일치해야 합니다. 같은 도메인에 80 포트로 접속하면 매칭되지 않습니다. 실제 설정에서는 더 정확하게 만들겠다는 이유로 조건을 무작정 추가하지 마세요. 조건을 하나 더 넣을 때마다 원래 처리해야 했던 연결이 제외될 수 있습니다.
domain의 대표적인 매칭 문법 4가지
domain 배열은 완전한 도메인만 받는 것이 아닙니다. 접두사는 각 항목을 코어가 해석하는 방식을 결정합니다. 가장 많이 쓰는 형식은 full:, domain:, regexp:, 그리고 접두사가 없는 일반 문자열입니다. 접두사를 잘못 선택하면 매칭 범위가 지나치게 넓어지거나, 루트 도메인만 매칭되고 하위 도메인을 놓칠 수 있습니다.
| 문법 | 매칭 범위 | 적합한 상황 |
|---|---|---|
full:www.example.com |
정확히 일치하는 대상 도메인만 매칭 | 명확한 호스트 이름 하나만 별도 처리 |
domain:example.com |
루트 도메인과 하위 도메인 매칭 | 사이트 하나와 일반적인 하위 도메인 처리 |
regexp:^api\d+\.example\.com$ |
정규 표현식으로 매칭 | 도메인에 일정한 번호나 고정 형식이 있을 때 |
example |
도메인 키워드로 매칭 | 특정 문자열을 포함한 도메인을 폭넓게 처리 |
full:: 정확한 도메인 하나만 매칭
full:api.example.com은 API 호스트나 업데이트 서버처럼 경계가 명확한 대상에 적합합니다. www.example.com이나 cdn.api.example.com까지 함께 매칭하지는 않습니다. 특정 하위 도메인만 조정하고 같은 루트 도메인의 다른 서비스에는 영향을 주고 싶지 않다면 full:을 우선 사용하세요.
domain:: 루트 도메인과 하위 도메인 전체에 적용
domain:example.com은 example.com뿐 아니라 www.example.com, static.example.com 등의 하위 도메인도 처리합니다. 다만 이름이 비슷할 뿐 경계가 다른 도메인을 같은 사이트로 보지는 않습니다. 사이트 전체를 기준으로 트래픽을 분기할 때는 키워드 방식보다 일반적으로 더 안전합니다.
일반 문자열과 정규식: 범위가 넓으므로 신중하게 사용
접두사가 없는 값은 키워드처럼 매칭됩니다. example이라는 항목은 이름에 해당 문자열이 포함된 여러 도메인에 적용될 수 있습니다. 대상 도메인이 자주 바뀌지만 명명 규칙이 뚜렷할 때 유용한 반면, 관계없는 사이트까지 잘못 매칭할 가능성도 커집니다. 정규 표현식은 제어력이 더 강하지만 유지 관리와 문제 해결 비용이 늘어납니다. full:이나 domain:으로 표현할 수 있다면 복잡한 정규식을 먼저 작성할 필요는 없습니다.
{
"type": "field",
"domain": [
"full:status.example.com",
"domain:media.example.net",
"regexp:^edge-[0-9]+\\.example\\.org$"
],
"outboundTag": "proxy"
}
JSON 문자열의 백슬래시는 이스케이프해야 하므로 정규식의 \.은 JSON 파일에서 \\.으로 작성해야 합니다. 정규식만 따로 테스트할 때는 정상인데 설정에 넣으면 시작되지 않는 문제의 흔한 원인입니다. 저장 후 코어가 즉시 종료된다면 먼저 실행 로그에서 JSON 파싱 오류와 규칙 파싱 오류를 확인하세요.
ip, CIDR, geoip 작성법
ip 배열은 대상 IP를 매칭하는 데 사용하며, 단일 주소와 CIDR 네트워크를 넣거나 geoip 데이터셋을 참조할 수 있습니다. 단일 주소는 고정 서버에, CIDR은 연속된 네트워크에 적합합니다. IPv4의 192.0.2.0/24는 해당 네트워크 접두사가 포함하는 주소 범위를 뜻하며, IPv6도 2001:db8::/32처럼 접두사 길이 형식을 사용합니다.
{
"type": "field",
"ip": [
"192.0.2.25",
"198.51.100.0/24",
"2001:db8::/32"
],
"outboundTag": "direct"
}
CIDR에서 중요한 것은 시작·끝 주소를 글자로 줄여 쓰는 방식이 아니라 네트워크 접두사입니다. 접두사 길이가 클수록 범위는 작아집니다. IPv4에서 /32는 주소 하나만 가리키고, /24는 일반적으로 같은 접두사 아래의 256개 주소를 포함합니다. 서비스 제공업체가 현재 반환한 특정 주소를 지나치게 큰 네트워크로 확장하지 마세요. 같은 네트워크의 관계없는 서비스까지 우회될 수 있습니다.
geoip:private는 사설 네트워크와 로컬 용도의 주소를 매칭하는 데 자주 사용되며, 직접 연결 규칙의 일부로 적합합니다. 이를 통해 LAN 게이트웨이, 내부 패널, 로컬 기기에 접속할 때 원격 프록시로 전송되지 않게 할 수 있습니다. TUN처럼 더 넓은 범위의 트래픽을 가로채는 방식을 사용한다면 사설 주소 직접 연결 규칙을 일반 프록시 규칙보다 앞에 두는 것이 특히 중요합니다.
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "direct"
}
geoip:cn과 같은 항목은 현재 코어가 불러온 IP 데이터 파일에 의존합니다. 데이터셋은 네트워크 주소 묶음을 나타내며 도메인 모음과는 다르고, 특정 사이트의 모든 서버가 항상 같은 지역에 속한다고 보장하지도 않습니다. 대형 사이트는 콘텐츠 전송 네트워크를 자주 사용하므로 같은 도메인도 네트워크와 시간에 따라 다른 주소로 해석될 수 있습니다. 따라서 IP 지리 데이터만으로 사이트 단위 분기를 구성하면 항상 안정적이지는 않습니다.
geosite는 도메인 모음이지 프로토콜 이름이 아닙니다
geosite:는 domain 배열 안에 작성하며, 미리 정리된 도메인 모음을 참조할 때 사용합니다. 예를 들어 geosite:cn은 해당 범주에 속하는 도메인 묶음을, geosite:category-ads-all은 광고 관련 도메인 모음을 나타내는 데 흔히 사용됩니다. 사용할 수 있는 이름은 현재 데이터 파일에 따라 달라집니다. 이름이 없거나 파일이 로드되지 않았거나 데이터 버전이 맞지 않으면 규칙이 정상적으로 적용되지 않을 수 있습니다.
{
"type": "field",
"domain": [
"geosite:cn"
],
"outboundTag": "direct"
}
geosite의 장점은 대량의 도메인을 직접 관리하지 않아도 된다는 점입니다. 기본 분기 계층을 구성하는 데 적합하지만 실시간 온라인 조회 기능으로 이해해서는 안 됩니다. 데이터 파일이 업데이트되어야 모음의 내용도 바뀝니다. 새 도메인이 아직 포함되지 않았다면 geosite 규칙 앞에 명확한 full: 또는 domain: 규칙을 추가해 우선 현재 경로를 수정한 뒤 데이터 업데이트를 검토하세요.
광고 범주를 차단하려면 먼저 아웃바운드에 해당 거부 아웃바운드를 설정하고, 규칙이 올바른 태그를 참조하도록 해야 합니다. 전체 설정에 block 태그가 없는데 outboundTag: "block"만 작성하는 것으로는 유효한 연결 경로가 만들어지지 않습니다.
{
"type": "field",
"domain": [
"geosite:category-ads-all"
],
"outboundTag": "block"
}
범주별로 트래픽을 분기할 때는 예외 요구 사항도 살펴야 합니다. 어떤 도메인이 컬렉션 규칙에 의해 직접 연결로 분류되었지만 현재 네트워크에서는 프록시를 거쳐야 한다면, 해당 도메인의 명시적인 프록시 규칙을 컬렉션 규칙보다 앞에 배치하세요. 반대로 넓은 프록시 컬렉션에 포함된 도메인을 반드시 직접 연결해야 한다면 더 구체적인 직접 연결 규칙을 먼저 작성해야 합니다.
매칭 우선순위: 규칙은 위에서 아래로 검사하며 일치하면 중단
라우팅 규칙은 rules 배열에 있는 순서대로 검사됩니다. 조건을 처음으로 만족한 규칙이 아웃바운드를 결정하고 뒤의 규칙은 더 이상 참여하지 않습니다. 따라서 더 구체적인 규칙이 자동으로 높은 우선순위를 얻는 것이 아니라, 실제 우선순위는 배치 순서로 결정됩니다. 두 번째 규칙이 full:로 정확히 매칭하더라도 첫 번째의 광범위한 규칙이 이미 일치했다면 실행될 기회가 없습니다.
다음 순서에서는 앞의 domain:example.com이 full:special.example.com까지 포함하므로, 뒤에 있는 직접 연결 규칙이 적용되지 않습니다:
[
{
"type": "field",
"domain": [
"domain:example.com"
],
"outboundTag": "proxy"
},
{
"type": "field",
"domain": [
"full:special.example.com"
],
"outboundTag": "direct"
}
]
올바른 방법은 예외를 앞에 두고, 적용 범위가 넓은 규칙을 뒤에 배치하는 것입니다:
[
{
"type": "field",
"domain": [
"full:special.example.com"
],
"outboundTag": "direct"
},
{
"type": "field",
"domain": [
"domain:example.com"
],
"outboundTag": "proxy"
}
]
순서를 정리할 때는 ‘로컬 보호, 명시적 예외, 범주 컬렉션, 지역 규칙, 최종 기본값’의 흐름을 사용할 수 있습니다:
- 먼저 사설 네트워크, LAN, 계속 유지해야 하는 로컬 연결을 처리합니다.
- 그다음 개별 도메인이나 개별 IP처럼 명확한 예외를 배치합니다.
- 이후 geosite, geoip, 넓은 CIDR 컬렉션을 배치합니다.
- 마지막으로 TCP와 UDP를 모두 포괄하는 일반 규칙으로 남은 트래픽을 결정합니다.
일반 기본 규칙은 반드시 마지막에 두세요. network: "tcp,udp" 프록시 규칙을 맨 앞에 배치하면 대부분의 연결이 즉시 매칭되어 뒤의 직접 연결 및 차단 규칙이 사실상 작동하지 않습니다.
domainStrategy가 도메인 및 IP 규칙에 미치는 영향
routing.domainStrategy는 라우팅 단계에서 도메인 해석을 처리하는 방식을 결정합니다. 흔히 사용하는 값으로 AsIs, IPIfNonMatch, IPOnDemand가 있습니다. 코어 버전과 클라이언트의 설정 생성 방식에 따라 차이가 있을 수 있으므로, 수정하기 전에 화면의 옵션 이름만 보지 말고 실제 실행 설정을 확인해야 합니다.
| 전략 | 주요 처리 방식 | 사용 시 확인할 사항 |
|---|---|---|
AsIs |
원래 대상 정보를 기준으로 도메인 규칙을 실행하며, 라우팅 매칭을 위해 IP를 능동적으로 해석하지 않음 | IP 기반 분기에 의존하는 도메인 연결은 예상한 규칙과 일치하지 않을 수 있음 |
IPIfNonMatch |
도메인 규칙이 일치하지 않을 때 IP를 해석한 뒤 IP 규칙을 시도 | DNS 서버, 해석 결과, 최종 기본 규칙 순서 |
IPOnDemand |
라우팅 판단에 IP 조건이 필요하면 해석이 실행될 수 있음 | 규칙 수, DNS 경로, 추가 조회 동작 |
분기의 중심이 domain:과 geosite:라면 도메인 정보를 판단에 계속 사용하는 편이 직관적입니다. 도메인 연결도 geoip:나 CIDR 기준으로 분류하려면 domainStrategy와 DNS를 함께 확인해야 합니다. 어떤 IP로 해석되는지가 이후 IP 규칙의 결과에 직접 영향을 줍니다.
라우팅 DNS와 애플리케이션 자체의 해석 동작도 구분해야 합니다. 일부 연결은 IP를 직접 제출하므로 코어가 원래 도메인을 볼 수 없습니다. 이때 domain 규칙은 매칭되지 않고 IP와 포트 등의 조건만 사용할 수 있습니다. 반대로 도메인을 제출하는 애플리케이션은 먼저 domain 또는 geosite 판단에 참여할 수 있습니다. 문제를 해결할 때는 로그에 기록된 대상 형식을 확인하세요. 브라우저 주소창만 보고 코어가 반드시 도메인을 받았다고 추정해서는 안 됩니다.
자주 쓰는 규칙 조합 3가지
조합 1: LAN은 직접 연결, 나머지는 프록시
이 구조는 로컬 기기 접속은 유지하면서 나머지 TCP·UDP 트래픽을 프록시 아웃바운드로 보내야 할 때 적합합니다. 첫 번째 규칙이 사설 주소를 먼저 처리하고, 두 번째 규칙이 최종 기본값으로 작동합니다.
{
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
사용 전에 프록시 아웃바운드가 필요한 네트워크 유형을 처리할 수 있는지 확인하고, 로컬 DNS·LAN 도메인·사설 IP의 대응 관계도 점검하세요. 내부 서비스를 사용자 지정 도메인으로 접속한다면 내부 도메인 직접 연결 규칙을 추가해 최종 기본 규칙보다 앞에 배치할 수 있습니다.
조합 2: 대표 컬렉션은 직접 연결, 나머지는 프록시
이 구조는 먼저 사설 네트워크를 보호한 다음 geosite와 geoip 컬렉션을 직접 연결하고, 마지막으로 매칭되지 않은 연결을 프록시에 전달합니다. 지역 컬렉션 기반 분기에 적합하지만 실제 결과는 데이터 파일과 DNS 해석 결과에 좌우됩니다.
{
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"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"
}
]
}
어떤 도메인이 geosite 컬렉션에 포함되어 있지만 프록시가 필요하다면 geosite:cn 앞에 정확한 프록시 항목을 추가하세요. 예외를 컬렉션 뒤에 배치하면 앞의 직접 연결 규칙이 먼저 가로챕니다.
조합 3: 범주 차단, 예외 유지, 나머지는 컬렉션 기준 분기
더 완성도 높은 구조는 반드시 접속해야 하는 예외를 먼저 배치하고, 그다음 차단 범주를 처리한 뒤 직접 연결 컬렉션과 프록시 기본값을 적용하는 방식입니다. 예외를 차단 규칙보다 앞에 두면 더 높은 우선순위를 갖습니다.
{
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"domain": [
"full:required.example.com"
],
"outboundTag": "direct"
},
{
"type": "field",
"domain": [
"geosite:category-ads-all"
],
"outboundTag": "block"
},
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "direct"
},
{
"type": "field",
"domain": [
"geosite:cn"
],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
예시에 사용한 도메인은 구조 설명을 위한 것이므로 실제 사용 시 대상에 맞게 바꿔야 합니다. 전체 라우팅 설정은 완전한 설정의 routing 객체 안에 넣어야 하며, 일부 조각만 떼어 실행 가능한 설정으로 사용할 수는 없습니다. 클라이언트에 그래픽 규칙 편집기가 있다면 같은 순서로 항목을 하나씩 만들고 저장 후 생성된 결과를 확인하세요.
v2rayN, v2rayNG, v2flyNG에 적용하기
v2rayN 데스크톱 버전은 일반적으로 라우팅 설정, 규칙 세트 또는 사용자 지정 설정을 통해 트래픽 분기를 관리합니다. 버전에 따라 화면 이름은 달라질 수 있지만 확인 방법은 같습니다. 먼저 현재 선택된 라우팅 모드를 확인하고, 규칙이 사용 중인 설정에 연결되어 있는지 확인한 다음 관련 코어를 재시작하고 로그를 살펴보세요. 편집 창에서만 저장하고 해당 규칙 프로필로 전환하지 않았다면 실행 결과는 달라지지 않습니다.
v2rayNG에서 Xray 코어를 사용할 때는 클라이언트가 제공하는 라우팅 옵션으로 일반적인 규칙을 적용할 수 있습니다. v2flyNG에서 v2fly 코어를 사용할 때도 규칙의 의미는 도메인, IP, 포트, 아웃바운드 태그를 중심으로 구성되지만, 사용 가능한 필드는 현재 코어가 실제로 지원하는 내용을 기준으로 해야 합니다. 구독 가져오기는 일반적으로 서버 노드 정보를 업데이트할 뿐이므로, 모든 로컬 사용자 지정 분기를 자동으로 병합한다고 가정해서는 안 됩니다.
규칙을 조정하기 전에 현재 작동하는 설정을 복사해 두고, 이후에는 한 번에 변수 하나만 변경하는 것이 좋습니다. 예를 들어 먼저 full: 도메인 규칙 하나를 추가해 확인하고, 그다음 geosite 컬렉션을 추가한 뒤 마지막으로 domainStrategy를 조정하세요. 한 번에 수십 개의 규칙을 추가한 후 연결에 문제가 생기면 원인이 JSON 구조인지, 태그 이름인지, 데이터 파일인지, 매칭 순서인지 판단하기 어렵습니다.
규칙이 적용되지 않을 때 확인할 순서
- 설정이 실제로 활성화되었는지 확인하세요. 클라이언트가 방금 수정한 라우팅 프로필을 실행 중인지, 다른 노드 설정이나 기본 규칙을 사용 중인 것은 아닌지 확인합니다.
- JSON과 필드 위치를 확인하세요.
rules는routing객체 안에 있어야 하며, 문자열 이스케이프와 쉼표, 대괄호가 모두 올바르게 닫혀 있어야 합니다. - 아웃바운드 태그를 확인하세요.
outboundTag는 전체 설정의 태그와 철자까지 정확히 일치해야 하며, 대소문자를 혼용해서도 안 됩니다. - 앞선 규칙을 확인하세요. 대상이 더 앞에 있는 domain, IP, 포트 또는 일반 네트워크 규칙에 이미 매칭되었는지 살펴보세요.
- 대상이 도메인인지 IP인지 확인하세요. 애플리케이션이 IP에 직접 연결하면 해당 연결에서 원래 도메인을 복원할 수 없으므로 domain과 geosite 규칙은 매칭되지 않습니다.
- DNS와 domainStrategy를 확인하세요. IP를 이용한 2차 판단이 필요하다면 라우팅 단계에서 해석 결과를 얻을 수 있는지 확인합니다.
- 데이터 파일을 확인하세요. geosite와 geoip 항목은 현재 로드된 데이터 내용과 범주 이름에 의존합니다.
- 실행 로그를 확인하세요. 설정 파싱 오류, 아웃바운드 태그를 찾지 못한 오류, 데이터 로드 실패, 실제로 선택된 아웃바운드를 중점적으로 확인합니다.
테스트할 때는 반복해서 확인할 수 있는 대상을 선택하고 애플리케이션 자체의 연결 재사용 영향을 줄이세요. 이미 설정된 장시간 연결은 규칙을 방금 수정했다고 즉시 새 경로를 선택하지 않는 경우가 많습니다. 설정을 저장한 뒤 코어를 재시작하고 연결을 새로 만들면 결과를 더 쉽게 판단할 수 있습니다. 도메인 DNS 캐시가 이전 주소를 유지할 수도 있으므로 geoip나 CIDR을 사용하는 경우 특히 고려해야 합니다.
규칙을 작성할 때 명확한 판단 흐름을 유지하기
안정적인 라우팅 설정은 규칙 수가 아니라 각 계층의 경계가 명확한지에 달려 있습니다. 정확한 도메인은 예외를, domain:은 사이트 전체를, geosite는 대량의 도메인을, CIDR과 geoip는 네트워크 주소를, 최종 기본값은 나머지 연결을 담당합니다. 범위가 좁은 규칙을 앞에, 넓은 규칙을 뒤에 배치하면 대부분의 우선순위 오류를 줄일 수 있습니다.
설정이 끝나면 ‘대상은 무엇인가, 어떤 규칙이 먼저 일치하는가, 어느 아웃바운드로 전달되는가’라는 세 가지 질문으로 하나씩 확인하세요. 이 판단 흐름을 로그와 설정에서 연결할 수 있다면 이후 VMess·VLESS 노드를 추가하거나 구독을 업데이트할 때도 문제가 노드 연결에 있는지 로컬 분기에 있는지 빠르게 판단할 수 있습니다.