노드 가져오기를 마쳤고 직접 연결, 프록시, 차단 트래픽을 세밀하게 제어하려는 사용자에게 적합합니다. 글을 읽고 나면 전체 도메인, 루트 도메인, 키워드, CIDR, geosite 분류를 구분하고, 위에서 아래로 내려가며 처음 일치한 규칙이 적용되는 원리를 이해할 수 있습니다. 폴백 항목을 포함한 설정으로 직접 검증하는 방법도 다룹니다.
라우팅 규칙은 무엇을 처리할까
V2Ray 또는 Xray의 라우팅 모듈은 노드 프로토콜을 바꾸거나 노드 자체의 대역폭을 높이지 않습니다. 연결의 목적지 정보를 받은 뒤 해당 연결을 어떤 아웃바운드로 보낼지 결정합니다. 일반적으로 사용하는 아웃바운드 태그는 proxy, direct, block이며, 각각 프록시 노드로 전달, 직접 연결, 연결 거부를 뜻합니다. 태그 이름은 자유롭게 정할 수 있지만 규칙의 outboundTag는 아웃바운드 설정의 tag와 대소문자까지 완전히 일치해야 합니다.
한 번의 요청에서 확인할 수 있는 매칭 정보는 도메인만이 아닙니다. 목적지 주소에는 IP, 포트, 네트워크 유형이 포함될 수 있고, 일부 클라이언트는 프로세스 이름이나 인바운드 태그도 제공합니다. 이 글에서는 가장 혼동하기 쉬운 세 가지 조건인 domain, ip, geosite를 집중적으로 다룹니다. geosite는 실제로 domain 배열 안에 작성하며, 독립적인 규칙 필드가 아니라 미리 정리된 도메인 분류를 참조하는 방식입니다.
라우팅 판단의 핵심은 ‘위에서 아래로, 처음 일치한 규칙’입니다. 코어는 규칙 목록을 순서대로 읽다가 어느 한 규칙의 모든 조건이 충족되면 해당 규칙이 지정한 아웃바운드를 사용하고 뒤의 규칙은 더 이상 확인하지 않습니다. 따라서 같은 도메인이 광고 분류와 지역 분류에 동시에 속한다면 앞에 배치한 차단 규칙이 뒤의 직접 연결 규칙보다 먼저 적용됩니다.
| 규칙 조건 | 확인하는 정보 | 일반적인 용도 | 주요 제한 사항 |
|---|---|---|---|
domain |
요청 대상 도메인 | 특정 사이트 직접 연결 또는 프록시 | 처음부터 IP만 있는 목적지는 매칭할 수 없음 |
geosite: |
도메인 분류 데이터 | 지역 또는 용도별 일괄 트래픽 분기 | 로컬 분류 데이터 파일에 의존 |
ip |
목적지 IP 또는 조회 결과 | 사설망, 지역 IP, 네트워크 대역별 트래픽 분기 | 도메인 요청을 조회할지는 정책에 따라 결정됨 |
port |
목적지 포트 | 53, 80, 443 등 특정 포트로 제한 | 같은 규칙의 다른 필드와 ‘AND’ 조건으로 계산됨 |
domain과 geosite 작성법의 차이
domain 배열은 여러 접두사를 지원합니다. 모든 주소를 일반 문자열로 작성하기보다 정확한 호스트명, 전체 루트 도메인, 또는 이름에 특정 문자열이 포함된 사이트 중 무엇을 매칭할지 먼저 정하는 것이 안전합니다. 범위를 너무 넓게 잡으면 관련 없는 도메인까지 같은 아웃바운드로 보내고, 너무 좁게 잡으면 정적 리소스, API, 로그인 서브도메인을 놓칠 수 있습니다.
전체 도메인 매칭
- 작성법
- full:api.example.com
- 일치
- api.example.com
- 불일치
- www.example.com
- 범위
- 단일 호스트명
하나의 API 도메인만 조정하고 같은 사이트의 다른 서브도메인에는 영향을 주지 않을 때 적합합니다.
루트 도메인 매칭
- 작성법
- domain:example.com
- 일치
- example.com
- 동시에 일치
- cdn.example.com
- 범위
- 루트 도메인 및 서브도메인
사이트 전체를 하나의 아웃바운드로 통일할 때 적합하며, 직접 작성하는 규칙에서 가장 많이 사용하는 형식입니다.
키워드 매칭
- 작성법
- example
- 방식
- 문자열 포함
- 범위
- 해당 문자열이 포함된 모든 도메인
- 위험 요소
- 일치 범위가 쉽게 넓어짐
모호한 매칭이 꼭 필요할 때만 사용하고, 짧은 단어는 오탐 여부를 먼저 확인하세요.
분류 목록 매칭
- 작성법
- geosite:cn
- 출처
- 로컬 도메인 분류 데이터
- 방식
- 항목 일괄 매칭
- 관리
- 데이터 파일 업데이트에 따라 변경
대규모 트래픽 분기에 적합하지만, 사용자 지정 도메인은 분류 규칙보다 앞에 배치해야 합니다.
regexp:에는 정규 표현식을 사용할 수 있습니다. 예를 들어 regexp:^([a-z0-9-]+\.)*example\.com$처럼 작성합니다. 복잡한 호스트명 구조를 표현할 수 있지만 domain:보다 유지 관리가 어렵습니다. 루트 도메인과 모든 서브도메인을 포함하려는 목적이라면 domain:example.com으로 직접 작성하는 편이 더 명확하고, 이스케이프 오류로 규칙이 무효화될 가능성도 낮습니다.
geosite:cn은 cn이라는 이름의 도메인 분류를 참조한다는 뜻이며, geosite:category-ads-all은 광고 관련 도메인을 매칭할 때 자주 사용합니다. 분류 내용은 클라이언트가 사용하는 데이터 파일에서 가져오고, 규칙에는 분류 이름만 저장됩니다. 코어를 업그레이드한 뒤 로그에 분류를 찾을 수 없다는 메시지가 나오면 geosite 데이터가 완전한지, 현재 데이터 버전이 해당 분류 이름을 지원하는지 함께 확인하세요.
{
"type": "field",
"domain": [
"full:api.example.com",
"domain:static.example.com",
"geosite:category-ads-all"
],
"outboundTag": "block"
}
ip, CIDR, domainStrategy 조합 방법
ip 필드에는 단일 주소, CIDR 네트워크 대역, geoip 분류를 작성할 수 있습니다. CIDR에서 슬래시 뒤의 숫자는 네트워크 프리픽스 길이를 뜻합니다. 예를 들어 192.168.0.0/16은 192.168.0.0부터 192.168.255.255까지를 포함하고, 10.0.0.0/8은 10으로 시작하는 전체 사설 네트워크 대역을 포함합니다. 가정용 라우터, 저장 장치, LAN 서비스를 처리할 때는 네트워크 대역을 하나씩 나열하는 것보다 geoip:private를 사용하는 편이 대체로 간편합니다.
도메인 요청이 IP 규칙까지 진입할 수 있는지는 라우팅의 domainStrategy에 따라 달라집니다. AsIs로 설정하면 라우팅 모듈이 원래 목적지를 기준으로 판단하므로 IP 매칭을 위해 도메인을 능동적으로 조회하지 않습니다. IPIfNonMatch에서는 도메인 규칙이 일치하지 않은 뒤 IP를 조회하고 IP 규칙도 계속 시도합니다. IPOnDemand에서는 매칭 과정에서 목적지 IP가 필요한 규칙을 만나는 순간 조회가 발생할 수 있습니다.
- 도메인만으로 트래픽 분기:
AsIs를 선택해 라우팅 단계의 추가 조회를 피합니다. - 도메인 우선, IP로 보완:
IPIfNonMatch를 선택하고, 먼저 직접 작성한 도메인과 geosite 분류가 경로를 결정하도록 합니다. - 앞선 규칙이 IP에 의존:
IPOnDemand를 고려하되, DNS 설정이 사용 가능한 결과를 반환하는지 확인합니다. - LAN은 반드시 직접 연결:
geoip:private규칙을 지역 IP 규칙과 최종 프록시 폴백보다 앞에 배치합니다.
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": [
"geoip:private",
"192.168.0.0/16",
"10.0.0.0/8"
],
"outboundTag": "direct"
},
{
"type": "field",
"ip": [
"geoip:cn"
],
"outboundTag": "direct"
}
]
}
}
흔한 오류는 같은 규칙에 domain:example.com과 geoip:cn을 함께 작성하는 것입니다. 의도는 ‘도메인 또는 지역 IP 중 하나가 일치하면 직접 연결’이지만, 실제로는 ‘도메인이 example.com에 속하고 조회 결과도 해당 IP 분류에 속할 때만 직접 연결’이 됩니다. ‘OR’를 표현하려면 두 규칙으로 나누고 동일한 outboundTag을 지정해야 합니다.
결론: 도메인 규칙을 앞에, IP 규칙은 보완용으로
먼저 full, domain, geosite로 명확한 의도를 표현하고 geoip와 CIDR은 뒤에 배치하세요. IPIfNonMatch를 사용하면 도메인 규칙에 일치하지 않은 요청만 IP 판단으로 넘어가므로 규칙 순서를 예측하기 쉬워집니다.
매칭 우선순위와 바로 적용할 수 있는 규칙 순서
규칙 우선순위는 domain, ip, geosite의 유형으로 결정되지 않으며, ‘정확한 규칙이 분류 규칙보다 자동으로 우선한다’는机制도 없습니다. 신뢰할 수 있는 유일한 우선순위는 배열 순서입니다. 사용자 지정 예외는 일괄 분류보다 앞에, 차단 규칙은 이를 덮어쓸 수 있는 직접 연결 또는 프록시 분류보다 앞에 배치하고, 마지막에는 TCP와 UDP를 모두 처리하는 폴백 규칙을 추가하세요.
아래 예시는 ‘사용자 지정 직접 연결, 광고 차단, 사설 주소 직접 연결, 지역 도메인 직접 연결, 지역 IP 직접 연결, 나머지 프록시’ 순서로 구성했습니다. 실제 사용 전 아웃바운드 태그가 정말 direct, block, proxy인지 확인하세요. 구독 템플릿에서 다른 태그를 사용한다면 태그 값만 바꾸고 조건 순서는 임의로 변경하지 마세요.
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"domain": [
"full:portal.example.com",
"domain:intranet.example"
],
"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",
"ip": [
"geoip:cn"
],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
| 순서 | 규칙 용도 | 이 위치에 두는 이유 |
|---|---|---|
| 1 | 직접 작성한 예외 | 뒤따르는 분류의 기본 결정을 덮어씀 |
| 2 | 명시적 차단 | 지역 직접 연결 분류가 먼저 가져가지 못하게 함 |
| 3 | 사설 주소 | 라우터와 LAN 장치에 직접 접근하도록 보장 |
| 4 | 지역 도메인 | 도메인 분류를 우선 적용해 조회 의존성을 줄임 |
| 5 | 지역 IP | 도메인이 없거나 분류되지 않은 목적지 처리 |
| 6 | 최종 폴백 | 일치하지 않은 연결에도 확실한 출구 제공 |
모든 코어 설정에서 폴백 규칙을 반드시 직접 작성해야 하는 것은 아닙니다. 일치하지 않은 연결은 기본 아웃바운드로 들어갈 수도 있기 때문입니다. 다만 명시적인 폴백을 두면 설정을 읽고 다른 구성으로 옮기기 쉽습니다. 다른 설정으로 이전할 때 마지막 규칙만 확인해도 분류되지 않은 트래픽의 경로를 알 수 있어, 아웃바운드 배열에서 어떤 항목이 첫 번째인지 추측할 필요가 없습니다.
결론: 예외는 반드시 분류보다 앞에
특정 사이트를 강제로 프록시로 보내야 한다면 해당 사이트의 full 또는 domain 규칙을 geosite:cn보다 앞에 배치하세요. 뒤에 두면 앞의 분류가 먼저 일치하는 순간 코어가 이 예외 규칙까지 읽지 않습니다.
v2rayN에서 규칙 입력 및 검증
v2rayN 7.12.x 데스크톱 인터페이스를 기준으로 먼저 ‘설정’ → ‘라우팅 설정’을 열고 현재 사용하는 규칙 세트를 복사한 다음 복사본을 편집합니다. 바로 덮어쓰지 않고 복사본을 사용하면 구문 오류가 발생했을 때 원래 규칙으로 즉시 되돌릴 수 있습니다. 세부 버전에 따라 버튼 위치는 달라질 수 있지만 확인해야 할 항목은 규칙 순서, 도메인 목록, IP 목록, 목적지 포트, 아웃바운드 태그입니다.
입력을 마친 뒤 새 규칙 세트를 선택하고 코어를 재시작합니다. 이어서 ‘설정’ → ‘매개변수 설정’을 열어 로컬 수신 포트를 확인하세요. 일반적으로 로컬 포트는 10808이지만 현재 화면에 표시된 값을 기준으로 해야 하며, 포트를 변경했다면 테스트 명령도 함께 수정해야 합니다. 시스템 프록시가 켜져 있다면 사용자 지정 직접 연결 도메인 하나, 프록시 도메인 하나, LAN 주소 하나에 각각 접속해 세 종류의 요청이 예상한 아웃바운드로 향하는지 확인하세요.
- 테스트 대상은 사용자 지정 예외, geosite 분류, IP 네트워크 대역, 미분류 도메인의 4가지로 준비합니다.
- 각 유형을 연속으로 3회씩 테스트해 총 12개의 요청을 기록하고, 캐시나 일시적인 조회 실패를 배제합니다.
- 실시간 로그에서 목적지 주소, 일치한 아웃바운드 태그, 실패 원인을 확인합니다.
- 규칙을 수정한 뒤에는 코어를 재시작하고, 기존 연결로 새 규칙의 적용 여부를 판단하지 마세요.
- LAN을 테스트할 때는
192.168.1.1처럼 장치 IP를 직접 입력해 private 직접 연결 규칙에 일치하는지 확인하세요.
curl --proxy socks5h://127.0.0.1:10808 https://example.com
curl --proxy socks5h://127.0.0.1:10808 https://www.example.org
socks5h의 h는 프록시 서버가 도메인 조회를 처리하도록 한다는 뜻입니다. 덕분에 코어가 원래 도메인을 확인하고 domain 또는 geosite 규칙을 실행할 수 있습니다. 로컬에서 먼저 조회한 뒤 IP를 프록시에 전달하는 방식으로 테스트하면 로그에 목적지 IP만 표시될 수 있으며, 이 경우 domain 규칙은 당연히 일치하지 않습니다.
자주 발생하는 문제와 확인 방법
규칙이 올바르게 보이는데 결과가 다르다면 대개 문법 자체가 아니라 현재 설정에서 규칙이 활성화되지 않았거나, 목적지 정보가 예상과 다르거나, 앞선 규칙이 이미 일치한 경우입니다. 문제를 확인할 때 모든 규칙을 계속 바꾸지 말고 먼저 하나의 대상 도메인으로 범위를 좁힌 뒤, 로그에서 코어가 실제로 도메인을 받았는지 IP를 받았는지 확인하세요.
domain 규칙을 작성했는데 왜 일치하지 않나요?
먼저 로그의 목적지가 이미 IP로 바뀌었는지 확인하세요. 테스트 도구가 로컬에서 조회를 완료했다면 도메인을 프록시에 전달하는 방식으로 바꾸고, 해당 규칙이 geosite 분류와 최종 폴백보다 앞에 있는지도 확인합니다.
geosite 분류를 찾을 수 없다고 나오면 어떻게 하나요?
현재 코어가 읽는 데이터 디렉터리와 geosite 데이터 파일을 확인한 뒤 분류 이름의 철자도 점검하세요. 코어를 업데이트했다면 해당 데이터도 함께 업데이트하고 코어를 재시작해 다시 로드합니다.
인트라넷 사이트가 프록시로 전송되면 어떻게 하나요?
프록시 폴백보다 앞에 geoip:private 직접 연결 규칙을 추가하세요. 사용자 지정 네트워크 대역을 사용한다면 172.16.0.0/12 같은 실제 CIDR도 추가하고, 앞에 더 넓은 강제 프록시 규칙이 있는지 확인합니다.
한 규칙에 domain과 ip를 함께 쓰면 더 정확한가요?
두 조건이 반드시 동시에 충족되어야 할 때만 이렇게 작성하세요. 도메인 또는 IP 중 하나만 일치해도 되게 하려면 인접한 두 규칙으로 나누고 두 규칙에 같은 아웃바운드 태그를 지정합니다.
규칙을 저장했는데도 웹 페이지가 계속 이전 출구를 사용하면 어떻게 하나요?
먼저 새 규칙 세트가 선택되었는지 확인한 다음 코어를 재시작하고 새 연결을 만드세요. 브라우저의 연결 재사용으로 이전 출구가 유지될 수 있으므로 관련 페이지를 닫았다가 다시 열고 로그를 확인합니다.
마지막으로 순서를 점검하세요. 사용자 지정 예외가 분류보다 앞에 있는지, 차단 규칙이 광범위한 직접 연결보다 앞에 있는지, private이 프록시 폴백보다 앞에 있는지, domainStrategy가 도메인 우선 설계와 맞는지 확인합니다. 이 네 가지가 설정에서 바로 읽히도록 구성하면 이후 규칙을 추가해도 기존 트래픽 분기를 망가뜨릴 가능성이 낮습니다.
- 먼저 단일 목적지에 대한
full:규칙을 작성하고 아웃바운드 태그가 유효한지 확인합니다. - 그다음
domain:으로 범위를 넓혀 루트 도메인과 두 개의 서브도메인을 검증합니다. - geosite 분류를 추가하되 사용자 지정 예외는 분류보다 앞에 유지합니다.
- 마지막으로 geoip, CIDR, TCP/UDP 폴백을 활성화하고 로그를 단계별로 확인합니다.