노드 연결을 마치고 트래픽 분기 규칙을 조정하려는 사용자를 위한 안내입니다. 먼저 커널이 도메인과 IP 중 어떤 정보를 받는지 확인한 뒤, 매칭 문법과 규칙 순서를 정하고 로그에서 실제 연결 경로를 검증하세요. 여기에 나오는 JSON은 커널 설정 일부이며 구독 정보가 아닙니다. 차이를 이해하면 ‘규칙을 추가했는데 적용되지 않음’, ‘사설망 트래픽이 프록시로 연결됨’, ‘분류 규칙을 불러오지 못함’ 등의 문제를 파악할 수 있습니다.
1. 라우팅 규칙은 연결 경로를 어떻게 결정할까
v2rayN은 클라이언트 인터페이스이며, 실제 매칭과 전달은 V2Ray 또는 Xray 커널이 담당합니다. VMess와 VLESS는 노드 연결에 사용하는 프로토콜이지, 특정 사이트의 연결 경로를 정하는 기준이 아닙니다. 라우팅 과정에서는 대상 도메인, 대상 IP, 포트, 인바운드 태그 등의 정보를 바탕으로 기존 아웃바운드 중 하나를 선택합니다.
routing.rules는 위에서 아래로 검사합니다. 조건을 처음으로 만족한 규칙이 연결 경로를 결정하며, 이후 더 ‘정확한’ 규칙을 찾지 않습니다. 어떤 규칙에도 해당하지 않으면 일반적으로 outbounds 배열의 첫 항목이 사용됩니다. 따라서 규칙 끝부분뿐 아니라 기본 아웃바운드도 확인해야 합니다.
- 같은 필드에 여러 값을 지정하면 보통 OR 조건입니다:
domain배열의 항목 중 하나라도 일치하면 도메인 조건이 충족됩니다. - 한 규칙에서 서로 다른 조건을 지정하면 보통 AND 조건입니다:
domain과port를 함께 입력했다면 도메인과 포트가 모두 일치해야 합니다. - 규칙은 작성한 순서대로 적용됩니다: 구체적인 예외 규칙을 넓은 범위의 분류 규칙보다 앞에 두고, 최종 대체 규칙은 마지막에 배치하세요.
- 아웃바운드 이름은 실제로 존재해야 합니다:
outboundTag에는 아웃바운드의tag와 일치하는 값을 지정해야 합니다. 설명 문구를 임의로 입력할 수 있는 항목이 아닙니다.
2. domain, full, regexp의 매칭 범위
domain은 규칙의 필드 이름이기도 하고 필드 값의 접두사이기도 하지만, 두 용도는 서로 다릅니다. 필드는 도메인 조건을 담고, 접두사는 매칭 방식을 지정합니다. 기본 도메인과 모든 하위 도메인을 포함하려면 domain:을, 완전히 일치하는 호스트 이름 하나만 허용하려면 full:을 사용하세요.
| 작성 방법 | 매칭 방식 | 범위 예시 |
|---|---|---|
example.com | 접두사가 없으면 부분 문자열로 매칭 | notexample.com에도 매칭될 수 있음 |
domain:example.com | 기본 도메인과 하위 도메인 매칭 | img.example.com에는 매칭되고 notexample.com에는 매칭되지 않음 |
full:api.example.com | 도메인 전체가 일치할 때 매칭 | img.api.example.com에는 매칭되지 않음 |
regexp:^api[0-9]+\\.example\\.com$ | 정규식입니다. 여기서는 JSON 문자열 안에 작성하는 형태를 보여 줍니다. | api12.example.com에는 매칭되고 api.example.com에는 매칭되지 않음 |
도메인 규칙은 웹 URL의 경로와 매칭되지 않습니다. https://api.example.com/v1/status를 처리하려면 대상 도메인인 api.example.com만 지정하세요. 프로토콜, 경로, 쿼리 매개변수까지 도메인 필드에 넣으면 안 됩니다. HTTPS 경로는 일반 라우팅 규칙에서 직접 조건으로 사용할 수 없습니다.
{
"type": "field",
"domain": [
"full:api.example.com",
"domain:static.example.net",
"regexp:^edge[0-9]+\\.example\\.org$"
],
"port": "443",
"outboundTag": "proxy"
}
이 규칙은 세 도메인 조건 중 하나가 일치하고 대상 포트가 443일 때만 proxy로 연결합니다. 정규식의 마침표는 이스케이프해야 합니다. JSON 문자열에서는 역슬래시도 이스케이프해야 하므로 \\.로 작성합니다. 클라이언트의 일반 텍스트 도메인 입력란에는 보통 \.만 입력하면 됩니다. 두 입력 방식을 혼용하지 마세요.
3. ip, CIDR, geoip를 사용하는 경우
ip 필드는 대상 IP를 처리하며, 단일 주소, CIDR 대역 또는 geoip: 분류를 지정할 수 있습니다. 여기서 판단하는 것은 이번 요청의 대상 주소이지 컴퓨터의 네트워크 카드 주소나 노드 서버 주소가 아닙니다. 앱이 IP 주소로 직접 접속한다면 도메인 조회 없이도 IP 규칙에 매칭될 수 있습니다.
IP 대역 직접 지정
- 단일 주소
192.168.1.10- IPv4 대역
192.168.0.0/16- IPv6 대역
fc00::/7- 데이터 의존성
- 지역 분류 파일이 없어도 사용 가능
대역 범위가 명확한 사설 네트워크나 고정 서비스 대역에 적합합니다.
geoip 분류 규칙
- 사설 주소 분류
geoip:private- 지역별 주소 분류
geoip:cn- 일반적인 데이터 파일
geoip.dat- 확인할 사항
- 분류가 존재하고 데이터를 읽을 수 있어야 함
분류 범위는 사용하는 데이터셋에 따라 달라지며, 실시간 네트워크 위치와 일치하는 것은 아닙니다.
{
"type": "field",
"ip": [
"127.0.0.0/8",
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",
"::1/128",
"fc00::/7"
],
"outboundTag": "direct"
}
위 예시는 직접 지정하는 연결 대역의 일부일 뿐, 특수 용도 주소 전체 목록이 아닙니다. geoip:private를 사용한다면 현재 데이터셋에 포함된 범위를 기준으로 확인하세요. 회사 내부망은 ‘사설망 분류에 포함되어 있겠지’라고 추측하기보다 실제 사용하는 대역을 직접 지정하는 편이 좋습니다.
4. geosite 분류와 데이터 파일
geosite:는 도메인 집합을 참조하는 접두사로 domain 배열에 사용합니다. geoip:는 ip 배열에 사용하며, 서로 바꿔 쓸 수 없습니다. geosite:cn은 데이터셋에서 cn이라는 이름의 집합을 참조한다는 뜻이지, 단순히 .cn으로 끝나는 모든 도메인을 가리키는 것은 아닙니다.
{
"type": "field",
"domain": [
"geosite:cn"
],
"outboundTag": "direct"
}
- 먼저 해당 집합이 있는지 확인하세요: 같은 이름의 데이터 파일이라도 관리 주체에 따라 분류 이름, 내용, 속성이 다를 수 있습니다.
- 두 가지 로드 오류를 구분하세요:
geosite.dat를 찾지 못한다면 파일이나 리소스 경로 문제이고, 지정한 분류를 찾지 못한다면 집합 이름이나 데이터 버전 문제입니다. - 업데이트 후 다시 검증하세요: 집합 내용이 바뀌면 매칭 결과도 달라질 수 있습니다. 업데이트가 성공했다고 기존 트래픽 분기 방식까지 그대로 유지되는 것은 아닙니다.
- 필요한 경우에만 속성으로 필터링하세요: 예를 들어
geosite:google@cn은 사용하는 데이터셋의 해당 항목에 그 속성이 있을 때만 의도한 대로 동작합니다. 이름만 보고 결과를 추측하지 마세요.
설정을 불러오는 중 커널이 바로 종료된다면 노드를 반복해서 바꾸기보다 로그에서 리소스 로드 오류부터 확인하세요. 분류 규칙이 정상적으로 로드되지 않았다면 연결 속도 테스트로 라우팅 설정의 정확성을 판단할 수 없습니다. 문제가 있는 분류 참조를 잠시 제거하고 명시적인 도메인 규칙 하나만 남겨 두면 설정 오류와 네트워크 장애를 구분하기 쉽습니다.
5. domainStrategy가 IP 규칙에 미치는 영향
routing.domainStrategy는 라우팅 판단 시 도메인 대상의 IP를 조회할지 제어하며, 최종 아웃바운드의 DNS 정책과 같은 의미가 아닙니다. 이미 앱에서 사라진 도메인 정보가 이 설정으로 복구되는 것도 아닙니다. 앱이 IP만 전달한다면 도메인 규칙을 사용하기 위해 인바운드 스니핑 등의 조건을 검토해야 합니다. 스니핑이 모든 트래픽에 적용되는 것은 아닙니다.
| 정책 | 도메인 대상 처리 방식 | 주요 영향 |
|---|---|---|
AsIs | 라우팅 매칭을 위해 도메인을 IP로 조회하지 않음 | 도메인 대상은 IP 규칙만으로 분기하기 어려움. 원래 IP인 대상은 계속 매칭 가능 |
IPIfNonMatch | 현재 대상 정보로 먼저 매칭한 뒤, 일치하는 규칙이 없으면 도메인을 조회하여 다시 매칭 | 첫 번째 검사에서 대체 규칙이 매칭되면 이후 IP 조회 단계로 넘어가지 않음 |
IPOnDemand | 매칭 과정에서 대상 IP가 필요한 조건을 만나면 도메인을 조회 | 앞쪽의 IP 규칙이 먼저 매칭되어 뒤에 있는 도메인 예외에 영향을 줄 수 있음 |
자주 하는 실수는 IPIfNonMatch를 설정하면서 규칙 끝에 모든 TCP·UDP 트래픽을 대상으로 하는 프록시 규칙을 추가하는 것입니다. 이 대체 규칙은 첫 번째 검사에서 바로 매칭되므로, 도메인 대상은 ‘일치하는 규칙이 없을 때 IP 조회’ 단계까지 진행하지 않습니다. 따라서 앞에 있는 geoip:cn 규칙이 조회된 IP를 판단하지 못할 수 있습니다.
요점: 먼저 대체 규칙을 정한 다음 조회 정책을 선택하세요
일치하지 않은 도메인을 IP 분류로 처리하려면 IPIfNonMatch 사용 시 첫 번째 아웃바운드를 대체 경로로 두고, 첫 번째 검사에서 반드시 매칭되는 규칙을 마지막에 추가하지 마세요. IPOnDemand를 선택한다면 반드시 유지해야 할 도메인 예외를 범위가 넓은 IP 분류보다 앞에 배치하세요.
여기서 DNS 조회 결과는 IP 분류 판단에 직접 영향을 줍니다. 같은 도메인이 오늘은 직접 연결되고 내일은 프록시를 통한다면 규칙 순서가 무효라고 단정하지 말고 조회 결과와 분류 데이터를 함께 확인하세요. DNS와 라우팅 필드에 대한 자세한 설명은 설정 참고 자료를 확인하세요.
6. 우선순위에 따라 작성한 라우팅 예시
아래 예시는 IPOnDemand를 사용해 ‘지정 도메인 예외 → 사설망 직접 연결 → 도메인 분류 → IP 분류 → 최종 프록시’ 순서를 보여 줍니다. 기존 설정에 추가할 수 있는 routing 객체의 예시입니다. 설정에 proxy와 direct라는 두 아웃바운드 태그가 이미 있고, 관련 분류 데이터도 사용할 수 있어야 합니다.
{
"routing": {
"domainStrategy": "IPOnDemand",
"rules": [
{
"type": "field",
"domain": [
"full:api.example.com"
],
"outboundTag": "proxy"
},
{
"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.com은 규칙 설명을 위한 예약 예시 도메인이며 실제 서비스의 동작 여부를 확인하는 주소가 아닙니다. 첫 번째 규칙에 있으므로 이후의 IP 분류에 매칭될 가능성이 있더라도 우선 프록시를 선택합니다. 실제로 사용할 때는 이 항목을 연결 경로를 고정할 업무용 도메인으로 바꾸거나 삭제하세요.
- 기존 설정을 보관하세요: 클라이언트에서 현재 설정을 내보내고 활성화된 라우팅 구성을 기록해 두면 변경에 실패했을 때 복구할 수 있습니다.
- 실제 태그를 확인하세요: 생성된 설정의
outbounds에서tag를 확인하고 예시와 일치하는지 살펴보세요. 클라이언트에 따라 태그 이름이 다를 수 있습니다. - 라우팅 객체만 병합하세요: 이 내용으로 전체 설정을 덮어쓰면 인바운드, 노드 아웃바운드, DNS 등 필요한 항목이 사라집니다.
- 인터페이스에서 저장하고 활성화하세요: v2rayN의 메뉴 이름은 버전에 따라 달라질 수 있습니다. 일반적으로 ‘설정’ → ‘라우팅 설정’에서 규칙을 추가한 뒤, 해당 라우팅 구성이 활성화되어 있는지 확인해야 합니다.
- 테스트 연결을 새로 만드세요: 저장한 후 클라이언트 안내에 따라 커널을 다시 불러오거나 재시작하고, 기존 웹 연결을 닫은 뒤 테스트하세요. 이미 설정된 연결은 라우팅 규칙을 다시 적용하지 않을 수 있습니다.
7. 규칙이 실제로 적용됐는지 확인하는 방법
웹페이지가 열린다는 사실만으로 연결 성공 여부만 확인할 수 있을 뿐, 올바른 경로로 연결됐는지는 알 수 없습니다. 트래픽 분기를 검증할 때는 대상, 프로토콜, 매칭된 아웃바운드, 테스트 시각을 함께 기록하세요. 먼저 완전한 도메인 하나로 최소 테스트를 진행한 뒤 분류 규칙을 단계적으로 추가하면 규칙을 한 번에 여러 개 수정하는 것보다 문제를 찾기 쉽습니다.
- 트래픽이 커널에 전달되는지 확인하세요: 브라우저가 시스템 프록시를 사용하는지 확인합니다. 명령줄 테스트에는
curl --proxy socks5h://127.0.0.1:10808 https://example.com/ -I를 사용할 수 있습니다. 여기서10808은 클라이언트의 실제 SOCKS 인바운드 포트로 바꿔야 합니다. - 도메인 정보를 유지하세요: 위 명령은
socks5h를 사용해 도메인 조회를 프록시 측에서 처리합니다. 앱이 로컬에서 먼저 조회한 뒤 IP만 전달한다면 도메인 규칙을 테스트하기 위한 전제가 달라집니다. - 커널 로그를 확인하세요: 대상 주소와 아웃바운드 태그를 살펴보세요. 로그 형식은 커널 버전에 따라 다릅니다. 액세스 로그가 비활성화되어 있다면 사용 중인 버전에 맞게 임시로 활성화하세요. 기록이 없다고 트래픽도 없다고 단정하지 마세요.
- 세 가지 사례를 비교하세요: 명확한 도메인 예외 하나, 접속 가능한 내부망 주소 하나, 일반적인 공인 도메인 하나를 각각 테스트하고 예상 경로와 실제 경로를 기록하세요. 내부망 서비스 포트는 실제 환경에 맞게
80또는443을 사용할 수 있습니다. - 테스트 환경을 정리하세요: 기존 연결을 닫고 다시 시도하고, 필요하면 테스트 앱을 재시작하세요. 확인이 끝나면 상세 액세스 기록이 계속 쌓이지 않도록 평소 로그 수준으로 되돌리세요.
full 규칙을 추가했는데 하위 도메인은 왜 프록시를 통하지 않나요?
full:example.com은 이 호스트 이름과 정확히 일치할 때만 적용됩니다. www.example.com도 포함하려면 domain:example.com으로 바꾸고, 범위가 넓은 직접 연결 규칙보다 앞에 배치한 뒤 연결을 새로 만드세요.
domain과 ip를 모두 지정했는데 왜 매칭이 더 어려워졌나요?
한 규칙에 두 필드를 지정해도 둘 중 하나만 만족하면 되는 것은 아닙니다. ‘이 도메인 또는 이 IP는 모두 직접 연결’하려면 규칙을 두 개로 나누고, 두 규칙의 outboundTag에 같은 값을 지정하세요.
geosite 분류를 복사한 뒤 커널이 시작되지 않으면 어떻게 해야 하나요?
가장 먼저 기록된 로드 오류를 확인하고 geosite.dat의 리소스 경로와 분류 이름을 점검하세요. 우선 해당 분류를 제거하고 full: 규칙으로 커널이 정상 실행되는지 확인한 다음, 유효한 데이터 파일과 분류를 다시 적용하세요.
안드로이드 클라이언트에 데스크톱 설정 전체를 그대로 적용해도 되나요?
v2rayNG는 Xray 커널을, v2flyNG는 v2fly 커널을 사용합니다. 기본 매칭 문법은 비슷하지만 아웃바운드 태그, 리소스 파일 위치, 설정 가져오기 방식은 클라이언트에 따라 달라집니다. 먼저 선택한 커널이 지원하는 필드를 확인한 뒤 라우팅 설정 일부를 옮기세요. 실행 설정 전체를 그대로 덮어쓰지 마세요.
문제를 점검할 때는 ‘대상 정보 → 규칙 순서 → 조회 정책 → 데이터 파일 → 실제 연결 경로’ 순으로 확인하세요. 정밀한 규칙 하나가 작동하는지 먼저 검증한 뒤 도메인 집합과 IP 분류를 추가하는 편이 규칙 전체를 반복해서 바꾸는 것보다 효과적입니다.