이 글은 정상적으로 작동하는 프록시 아웃바운드가 있고 DNS 정책을 조정하려는 사용자를 대상으로 합니다. 먼저 리졸버 선택과 DNS 쿼리의 전송 경로를 구분한 뒤, 중국 도메인 규칙과 원격 DoH, 직접 연결 아웃바운드 설정을 구성합니다. 마지막으로 별도 테스트 엔드포인트를 통해 DNS 조회 경로를 확인합니다. 예시는 V2Ray 형식의 JSON이며, 구독에 포함된 서버 설정을 대체하지 않습니다. 모든 클라이언트가 같은 코어를 사용한다고 가정하지도 않습니다.
1. DNS 분할은 리졸버 선택과 쿼리 라우팅으로 나뉩니다
DNS 분할은 서버 주소 두 개를 목록에 적는 것으로 끝나지 않습니다. 첫 번째 단계에서는 도메인별로 사용할 리졸버를 정하고, 두 번째 단계에서는 리졸버로 연결하는 트래픽을 직접 연결할지 프록시로 보낼지 결정합니다. 두 단계가 모두 명확해야 해외 도메인 쿼리가 의도한 경로를 거치는지 확인할 수 있습니다. 암호화 DNS는 쿼리 전송을 보호하지만, DNS 서비스가 항상 올바른 결과를 반환한다고 보장하지는 않습니다.
코어 DNS와 운영체제 DNS는 서로 다릅니다. 앱이 SOCKS를 통해 도메인을 전달하면 프록시 프로토콜에 따라 서버 측에서 도메인을 조회할 수 있습니다. 반대로 앱이 시스템 리졸버를 먼저 호출해 IP를 얻으면 코어에는 IP만 전달될 수 있습니다. 설정의 dns 객체만 수정해도 PC나 휴대폰의 모든 프로그램이 보내는 쿼리를 자동으로 가로채지는 않습니다.
- 코어에서 조회: 라우팅에 IP가 필요하거나, 직접 연결 아웃바운드에서 주소를 조회하거나, DNS 인바운드가 DNS 아웃바운드로 전달될 때 내장 DNS 모듈이 사용됩니다.
- 원격에서 조회: 프록시 요청에 대상 도메인이 포함되어 서버로 전달되면 실제 리졸버는 서버 환경에 따라 결정됩니다.
- 앱 자체 조회: 브라우저의 보안 DNS가 별도로 DoH 요청을 보낼 수 있으며, 이 경우 여기 설정한 서버 목록을 사용하지 않을 수 있습니다.
2. 설정 전 코어, 규칙 파일, 아웃바운드 태그 확인
v2rayN은 데스크톱 설정 관리 클라이언트이며, 실제 동작은 현재 선택한 코어에 따라 달라집니다. Android용 v2rayNG는 Xray 코어를, v2flyNG는 V2Fly 코어를 사용합니다. 여러 설정 항목이 비슷하더라도 모든 DNS 옵션과 FakeDNS 동작, 기본값이 완전히 같다고 볼 수는 없습니다. 먼저 코어 이름과 버전을 확인한 다음 해당 코어의 설정 문서에서 지원 항목을 살펴보세요.
- v2rayN의 ‘설정’ → ‘매개변수 설정’에서 현재 코어와 관련된 옵션을 확인하세요. DNS 편집 메뉴는 클라이언트 버전에 따라 다를 수 있으므로 실제 화면을 기준으로 확인해야 합니다.
- 현재 설정을 백업한 뒤 생성된 설정의
outbounds를 살펴보고 프록시와 직접 연결 아웃바운드의 실제tag값을 기록하세요. - 실행 디렉터리에서
geosite.dat를 읽을 수 있고cn분류가 포함되어 있는지 확인하세요. IP 분류를 사용할 때만 해당geoip.dat규칙이 필요합니다. - DNS를 조정하기 전에 프록시 연결이 정상인지 확인하세요. 프록시 아웃바운드에 연결할 수 없는 상황에서 원격 쿼리가 실패했다고 해서 곧바로 리졸버 문제라고 단정할 수는 없습니다.
이 숫자는 설정에 사용하는 포트 예시이며 성능 측정 결과가 아닙니다. 아래에서는 기존 프록시 아웃바운드를 proxy, 직접 연결 아웃바운드를 direct라고 부릅니다. 실제 태그가 다르면 참조하는 설정도 함께 바꿔야 하며, 규칙에 적힌 이름만 그대로 복사하면 안 됩니다.
3. 중국 도메인은 직접 연결 DNS, 나머지는 원격 DoH 사용
아래 조각을 기존 설정 최상위의 dns 항목에 병합하세요. 중국 도메인 분류에 해당하는 쿼리는 우선 223.5.5.5로 보내고, 분류에 해당하지 않는 쿼리는 https://1.1.1.1/dns-query를 사용합니다. 두 주소는 설정 예시일 뿐 모든 네트워크에서 접속할 수 있다는 뜻은 아니며, 이 공용 DNS 조합을 반드시 사용해야 하는 것도 아닙니다.
{
"dns": {
"queryStrategy": "UseIPv4",
"servers": [
{
"address": "223.5.5.5",
"port": 53,
"domains": [
"geosite:cn"
],
"skipFallback": true
},
{
"address": "https://1.1.1.1/dns-query"
}
]
}
}
domains는 리졸버를 우선 선택할 때 사용하는 조건입니다.geosite:cn은 규칙 파일의 분류에 의존하며, 도메인 접미사만으로 단순 판별하는 방식이 아닙니다. 중국 사이트가 모두 분류에 포함된다고 보장할 수도 없습니다.skipFallback: true는 해당 서버가 분류에 일치하지 않는 도메인의 일반 폴백 처리에 사용되지 않도록 합니다. 따라서 폴백 단계에서 해외 도메인이 이 직접 연결 리졸버로 전달되는 일을 막을 수 있습니다.- 이 설정에서는 중국 도메인의 우선 조회가 실패하면 원격 서버로 재시도할 수 있습니다. 따라서 중국 도메인 쿼리가 절대 해외로 나가지 않도록 격리하는 엄격한 정책은 아닙니다. 엄격한 격리가 필요하다면 코어의 폴백 제어 옵션을 별도로 확인하세요.
UseIPv4는 IPv6 관련 문제를 우선 제외하고 확인할 때 사용합니다. 시스템에서 IPv6를 비활성화하는 설정은 아닙니다. IPv4와 IPv6를 함께 사용해야 한다면 실제 IPv6 라우팅에 맞춰 쿼리 정책을 다시 검토하세요.
원격 주소를 IP 리터럴로 지정하면 DoH 서버에 연결하기 위해 먼저 해당 서버 도메인을 조회해야 하는 의존성을 줄일 수 있지만, TLS 인증서 검증은 여전히 필요합니다. 연결 오류를 해결하려고 인증서 검증을 끄지 마세요. DNS 서비스 주소를 도메인 형식으로 바꾼다면 해당 도메인을 조회할 초기 리졸버도 함께 설정해, 아직 연결되지 않은 DNS 경로에 다시 의존하지 않도록 해야 합니다.
4. DNS 쿼리의 아웃바운드를 지정해 기본 라우팅으로 경로가 바뀌지 않게 하기
아래 규칙은 AsIs를 사용합니다. 두 DNS 엔드포인트를 먼저 처리하고, 다음으로 중국 도메인을 처리한 뒤, 나머지 TCP와 UDP 연결은 프록시로 보냅니다. 일반 https:// DoH와 로컬 직접 연결 의미를 포함하는 https+local://은 같은 방식으로 해석하면 안 됩니다. 이 예시에서는 쿼리 연결이 코어 라우팅을 거쳐야 하므로 전자를 사용합니다.
{
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"ip": ["223.5.5.5"],
"port": "53",
"network": "udp",
"outboundTag": "direct"
},
{
"type": "field",
"ip": ["1.1.1.1"],
"port": "443",
"network": "tcp",
"outboundTag": "proxy"
},
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
이 설정은 경로를 확인하기 위한 기본 정책이며 LAN, 사내망, 광고 분류 등의 규칙은 포함하지 않습니다. 기존 설정에 병합할 때는 필요한 규칙을 유지하고 순서를 확인하세요. 규칙은 보통 위에서부터 차례로 적용되므로 마지막에 두는 기본 처리 규칙이 DNS 엔드포인트 규칙보다 먼저 매칭되면 안 됩니다. 위의 IP 및 포트 규칙은 같은 엔드포인트에 접속하는 다른 연결에도 적용되며, DNS 모듈이 만든 트래픽만 구분하지는 않습니다.
직접 연결 아웃바운드에서는 Freedom의 도메인 처리 정책도 확인해야 합니다. 아래는 기존 직접 연결 아웃바운드에 필요한 구조입니다. 같은 태그를 가진 항목을 하나 더 추가하지 말고 해당 항목을 수정하세요. UseIP를 지정하면 아웃바운드가 내장 DNS를 사용해 대상 IP를 조회합니다. 지정하지 않으면 기본 동작이 계속 시스템 DNS에 의존할 수 있습니다.
{
"tag": "direct",
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIP"
}
}
정리: DNS 조회 경로와 연결 경로를 따로 확인하세요
먼저 중국 도메인이 실제로 직접 연결 아웃바운드에서 내장 DNS를 사용하는지 확인하고, 다음으로 원격 DoH 연결이 프록시에 매칭되는지 확인하세요. 웹페이지가 열린다는 사실만으로 DNS 분할이 적용되었다고 볼 수는 없습니다. 프록시 요청에 도메인이 포함되면 대상 도메인 조회는 서버 측에서 이루어질 수 있습니다.
5. 별도 DNS 엔드포인트로 테스트하고 브라우저 캐시를 결과로 착각하지 않기
내장 DNS 모듈을 직접 테스트하려면 기존 inbounds와 outbounds 배열에 아래 객체를 각각 추가하세요. 인바운드는 127.0.0.1에만 바인딩하고 외부에서 접속할 수 있는 주소로 바꾸지 마세요. 이 엔드포인트는 로컬 문제 해결용이며 시스템 DNS를 자동으로 바꾸거나 브라우저 쿼리를 자동으로 가로채지 않습니다.
{
"tag": "dns-in",
"listen": "127.0.0.1",
"port": 1053,
"protocol": "dokodemo-door",
"settings": {
"address": "1.1.1.1",
"port": 53,
"network": "tcp,udp"
}
}
{
"tag": "dns-out",
"protocol": "dns",
"settings": {}
}
그다음 아래 규칙을 앞에서 다룬 routing.rules 맨 앞에 추가하세요. 테스트 요청이 마지막의 프록시 기본 규칙에 걸리지 않고 DNS 아웃바운드로 전달됩니다. DNS 아웃바운드는 A 및 AAAA 쿼리를 내장 DNS 모듈로 처리합니다. 다른 레코드 유형의 처리와 전달 동작은 별도로 확인하세요. TXT 쿼리 한 번으로 이 예시의 주소 레코드 테스트를 대신하면 안 됩니다.
{
"type": "field",
"inboundTag": ["dns-in"],
"outboundTag": "dns-out"
}
- 코어를 다시 시작하고 먼저 설정 로드 로그를 확인해 포트 충돌, 알 수 없는 필드, 규칙 파일 읽기 오류가 없는지 살펴보세요.
dig가 설치된 환경에서 아래 명령을 실행해 중국 도메인 분류와 원격 조회 경로를 각각 테스트하세요.- DNS 디버그 로그와 아웃바운드 접속 로그를 함께 살펴 두 DNS 엔드포인트가 실제로 어떤 태그를 사용하는지 확인하세요. 문제를 해결하는 동안 로그 수준을 잠시 높일 수 있으며, 작업이 끝나면 원래 수준으로 되돌리세요.
- 한 번에 설정 하나만 바꾸세요. 반복 쿼리는 캐시에 저장된 결과를 반환할 수 있습니다. 필요하면 코어를 재시작하고 앱 또는 시스템 캐시를 비운 뒤 결과를 다시 비교하세요.
dig @127.0.0.1 -p 1053 www.baidu.com A
dig @127.0.0.1 -p 1053 www.example.com A
테스트 도메인이 분류에 포함되는지는 현재 사용 중인 규칙 파일을 기준으로 판단해야 합니다. 조회 결과가 다르다고 반드시 DNS 오염인 것은 아닙니다. CDN 분산, 리졸버 위치, 캐시 상태에 따라 응답이 달라질 수 있습니다. 반환된 IP 두 개만 비교하지 말고 쿼리가 의도한 리졸버로 전달되는지, 시간 초과가 발생하는지, 최종 대상 연결이 성공하는지 확인하세요.
6. FakeDNS, 캐시, 라우팅 DNS 조회 정책의 적용 범위
FakeDNS가 반환하는 값은 코어에서 매핑에 사용하는 가상 주소이며 대상 사이트의 실제 주소가 아닙니다. 주된 목적은 트래픽이 프록시로 전달된 뒤에도 도메인 정보를 보존하거나 복원하는 것입니다. 실제 DNS 서비스를 대체하거나 연결할 수 없는 프록시 서버 문제를 해결하지는 않습니다. 사용 전에 현재 코어와 트래픽 가로채기 방식, 도메인 복원 경로가 해당 설정을 지원하는지 확인하세요.
| 설정 또는 기능 | 실제 역할 | 자주 하는 오해 |
|---|---|---|
| DNS queryStrategy | 내장 DNS 모듈이 조회하거나 사용하는 주소 계열을 제어합니다. | IPv4로 설정하면 모든 앱이 IPv6 트래픽을 보내지 않는다고 생각합니다. |
| routing.domainStrategy | 라우팅 규칙을 적용할 때 도메인의 IP를 조회할지 제어합니다. | AsIs를 코어 전체에서 도메인을 절대 조회하지 않는다는 의미로 해석합니다. |
| Freedom domainStrategy | 직접 연결 아웃바운드가 연결을 만들 때 도메인을 처리하는 방식을 제어합니다. | DNS 서버 목록만 바꾸고 직접 연결 아웃바운드는 계속 시스템 DNS를 사용하게 둡니다. |
| FakeDNS | 도메인과 가상 주소의 매핑을 유지합니다. 이후 트래픽도 매핑을 복원할 수 있는 코어를 거쳐야 합니다. | 가상 응답만 활성화하고 해당 연결도 코어에서 처리되는지는 확인하지 않습니다. |
| DNS 캐시 | 이전에 얻은 조회 결과를 재사용해 반복 쿼리를 줄입니다. | 설정을 바꾼 뒤에도 이전 결과가 보이면 새 설정이 로드되지 않았다고 단정합니다. |
IPIfNonMatch는 도메인 규칙이 일치하지 않으면 조회를 시도한 뒤 IP 규칙을 계속 적용합니다. IPOnDemand는 IP가 필요한 규칙을 적용할 때 조회를 시작합니다. 두 설정 모두 로컬 DNS 쿼리를 늘릴 수 있습니다. 설정에 반드시 매칭되는 기본 규칙이 있다면 모든 도메인이 IP 조회 단계까지 진행될 것이라고 단정하지 마세요.
- 먼저 일반 DNS와 명시적인 도메인 규칙으로 기본 경로를 확인한 뒤 FakeDNS를 추가하세요. 주소 매핑과 DNS 폴백이라는 두 변수를 한꺼번에 추가하지 않는 것이 좋습니다.
- 규칙 파일을 수정한 뒤에는 클라이언트 동작에 따라 코어를 재시작하거나 다시 불러오세요. 파일을 업데이트하는 것만으로 실행 중인 규칙이 바뀌지는 않습니다.
- 브라우저 보안 DNS, 시스템 DNS 캐시, 코어 DNS 캐시는 각각 따로 점검해야 합니다. 한 계층의 캐시를 비워도 다른 계층의 캐시까지 자동으로 삭제되지는 않습니다.
7. DNS 분할 관련 자주 묻는 질문과 문제 해결 순서
원격 DNS를 설정했는데 브라우저는 왜 로컬 리졸버에 계속 요청하나요?
먼저 쿼리가 코어에 전달되는지 확인하세요. 위에서 설정한 1053 포트 테스트 엔드포인트로 따로 검증한 다음 브라우저 보안 DNS와 시스템 프록시 동작을 확인합니다. 일반 시스템 프록시는 주로 앱 연결을 처리하며, 운영체제의 UDP 53 쿼리까지 자동으로 가로채지는 않습니다.
중국 사이트는 열리는데 해외 도메인 조회가 계속 시간 초과되면 어떻게 해야 하나요?
1.1.1.1:443이 proxy에 매칭되는지, 해당 태그가 실제로 존재하는지, 프록시 연결이 정상인지 확인하세요. 다음으로 TLS 오류와 시스템 시간을 확인합니다. 프록시 서버 주소가 도메인이라면 초기 조회가 원격 DoH에 의존해 순환 문제가 생기지 않는지도 점검하세요.
구독을 업데이트한 뒤 설정한 DNS 값이 사라지는 이유는 무엇인가요?
변경 사항이 클라이언트에서 임시로 생성한 실행 설정에만 저장되어 있는지 확인하세요. 노드를 바꾸거나 클라이언트를 다시 시작할 때 생성 파일이 덮어써질 수 있습니다. 현재 버전에서 제공하는 DNS 설정 또는 사용자 지정 설정 메뉴에 저장한 뒤, 생성된 설정을 다시 열어 해당 필드와 태그가 유지되는지 확인하세요.
FakeDNS를 켠 뒤 일부 프로그램이 전혀 연결되지 않으면 무엇부터 바꿔야 하나요?
먼저 일반 DNS로 되돌리고 코어를 다시 시작한 다음 관련 앱의 캐시를 비우세요. 정상 작동을 확인한 뒤 가상 주소를 사용하는 연결이 같은 코어로 돌아오는지, 인바운드의 도메인 복원 설정이 현재 코어 요구 사항에 맞는지 점검합니다. 가상 주소를 받은 프로그램이 트래픽 가로채기를 우회해 직접 연결하지 않도록 하세요.
최종 점검 기록으로 현재 코어와 설정 출처, 두 DNS 엔드포인트에 연결된 아웃바운드 태그, 별도 테스트 엔드포인트의 쿼리 로그를 남기세요. 그래야 공용 DNS 주소를 계속 바꾸는 대신 리졸버 선택, 쿼리 전송, 대상 연결 중 어느 단계에서 문제가 생겼는지 파악할 수 있습니다.