먼저 세 가지 경로를 구분하세요: 가로채기, DNS 조회, 연결
“DNS를 활성화했다”고 해서 모든 앱이 해당 DNS 설정을 사용하는 것은 아닙니다. mihomo DNS 문제를 해결하려면 앱의 DNS 요청이 코어에 전달되는지, 코어가 어떤 업스트림 서버에 질의하는지, 조회 후 연결에 어떤 프록시 규칙이 적용되는지 세 단계로 나눠 살펴봐야 합니다. 어느 한 단계에서든 문제가 생기면 웹사이트가 열리지 않을 수 있지만, 같은 설정 하나를 바꿔서는 서로 다른 세 가지 문제를 해결할 수 없습니다.
- 가로채기 경로:
dns.listen은 DNS 요청을 받을 리스너를 설정합니다. TUN에서는dns-hijack이 조건에 맞는 DNS 트래픽을 내장 DNS 리졸버로 전달합니다. - 업스트림 선택:
nameserver,nameserver-policy,fallback등의 옵션이 DNS 조회 경로와 결과 선택을 결정합니다. - 연결 라우팅:
rules에 따라 웹사이트 연결이 직접 연결되거나 프록시를 거칩니다.respect-rules를 활성화하면 DNS 업스트림 연결에도 라우팅 규칙이 적용됩니다.
이 문서는 mihomo 코어를 사용하는 클라이언트를 대상으로 합니다. 원본 Clash, Premium, 그리고 버전이 다른 Meta 코어는 지원하는 옵션이 서로 다를 수 있습니다. 먼저 클라이언트의 코어 정보나 시작 로그에서 실제 코어를 확인한 뒤 현재 적용 중인 설정을 수정하세요. GUI 클라이언트의 버전만으로 코어 버전을 판단할 수는 없습니다.
default-nameserver: DNS 서버의 호스트 이름을 먼저 조회
업스트림에 https://dns.alidns.com/dns-query를 지정하면, HTTPS 연결을 만들기 전에 dns.alidns.com의 IP 주소를 알아야 합니다. default-nameserver는 이 초기 조회를 담당하며, “모든 웹사이트에서 기본으로 사용할 DNS”를 뜻하지 않습니다. 이름은 비슷하지만 문제를 확인해야 할 방향은 완전히 다릅니다.
dns:
enable: true
default-nameserver:
- 223.5.5.5
- 119.29.29.29
nameserver:
- https://dns.alidns.com/dns-query
위의 두 IP 주소는 초기 조회에 사용됩니다. 일반 IP 주소 형식의 DNS는 보통 UDP 53번 포트를 사용하며, 뒤에 지정한 업스트림이 DoH라고 해서 초기 조회까지 자동으로 암호화되지는 않습니다. 초기 조회도 암호화해야 하는 네트워크라면 현재 코어가 지원하고 추가 도메인 조회 없이 연결할 수 있는 IP 기반 암호화 엔드포인트를 선택하세요. 서비스 인증서와 접속 방식도 호환되는지 확인해야 합니다.
nameserver와 fallback: 기본 서버가 시간 초과된 뒤에만 대체 서버를 쓰는 방식이 아닙니다
nameserver는 일반 DNS 조회 결과를 제공합니다
nameserver는 더 구체적인 DNS 정책이 적용되지 않을 때 사용하는 기본 업스트림 목록입니다. 여러 주소를 지정하면 장애 대응에 도움이 될 수 있지만, 목록 순서대로 첫 번째가 실패해야 두 번째를 조회한다고 생각하면 안 됩니다. 코어가 여러 서버에 동시에 질의할 수도 있고, DNS 캐시 때문에 이번 요청은 업스트림에 아예 전달되지 않을 수도 있습니다.
DoH의 HTTPS 연결은 보통 TCP 443번 포트를, DoT는 보통 TCP 853번 포트를 사용합니다. 암호화 프로토콜은 DNS 질의 구간을 보호하지만, 연결이 어떤 프록시 노드를 거칠지는 결정하지 않습니다. DoH 주소가 브라우저에서 열린다고 해서 현재 mihomo의 라우팅, 인증서, 프록시 설정에서도 접속 가능하다는 뜻은 아닙니다.
fallback은 결과 필터와 함께 동작합니다
fallback을 네트워크 시간 초과 때만 작동하는 일반적인 대체 서버로 이해하면 안 됩니다. 이 옵션을 설정하면 코어가 fallback-filter와 함께 결과를 선택하며, 관련 질의가 동시에 진행될 수 있습니다. 문제를 확인할 때 두 업스트림 모두 질의를 받은 것이 보여도 설정이 두 번 읽혔다는 뜻은 아닙니다.
| 옵션 | 주요 역할 | 잘못 이해하기 쉬운 점 |
|---|---|---|
default-nameserver | DNS 업스트림 호스트 이름의 초기 조회 | 모든 웹사이트의 기본 업스트림 |
nameserver | 일반 도메인 조회 | 반드시 순서대로 처리되는 목록 |
fallback | 필터링에 사용할 추가 결과 제공 | 시간 초과 때만 조회하는 대기 서버 |
fallback-filter | fallback 결과를 선택할 조건 제어 | 프록시 규칙 또는 방화벽 규칙 |
dns-hijack | TUN 경로에서 조건에 맞는 DNS 트래픽 가로채기 | 앱 자체 DoH를 복호화하는 설정 |
fallback-filter: 지역, IP 주소, 도메인별 필터링
아래에서는 중국 본토 업스트림과 별도의 공용 DoH를 조합해 필터링 동작을 설명합니다. 옵션을 이해하기 위한 예시일 뿐, 모든 네트워크에서 모든 엔드포인트에 직접 연결할 수 있다는 뜻은 아닙니다. 대체 업스트림에 연결할 수 없다면 먼저 연결 상태나 라우팅을 확인한 뒤 반환 결과의 신뢰성을 살펴보세요.
dns:
enable: true
default-nameserver:
- 223.5.5.5
- 119.29.29.29
nameserver:
- https://dns.alidns.com/dns-query
- https://doh.pub/dns-query
fallback:
- https://1.1.1.1/dns-query
- https://dns.google/dns-query
fallback-filter:
geoip: true
geoip-code: CN
ipcidr:
- 240.0.0.0/4
domain:
- '+.google.com'
geoip: true와geoip-code: CN: 일반적으로 기본 업스트림이 지정된 지역에 속하지 않는 IP를 반환하면 fallback 결과를 우선 선택하는 방식으로 이해할 수 있습니다. 이 판단은 코어에서 사용하는 GeoIP 데이터에 따라 달라집니다.ipcidr: 기본 업스트림이 반환한 IP가 지정된 대역에 포함되면 fallback 결과를 선택합니다. 예시의240.0.0.0/4는 예약된 주소 대역이며, 모든 비정상 주소를 나열한 목록은 아닙니다.domain: 조건에 맞는 도메인은 fallback 경로를 사용합니다. 예시의+.google.com은 해당 도메인과 하위 도메인을 포함합니다. YAML 파싱 시 모호함을 줄이려면 따옴표로 감싼 문자열로 작성하세요.
지역 필터링은 정책이지, DNS 오염 여부를 수학적으로 증명하는 방법은 아닙니다. 해외 도메인이 중국 본토 CDN을 사용할 수도 있고, 중국 본토 서비스가 해외 IP를 반환할 수도 있습니다. GeoIP 데이터가 오래되면 잘못 판단할 가능성도 있습니다. 몇몇 도메인에 사용할 리졸버를 지정하려는 목적이라면 복잡한 지역 조건을 늘어놓기보다 nameserver-policy를 쓰는 편이 간단한 경우가 많습니다. 이 정책에 일치한 요청이 이곳의 일반 fallback 절차를 반드시 거친다고 가정하지 마세요.
지역 판별이 필요하지 않다면 geoip: false를 명시하고, 근거가 있는 도메인 및 IP 조건만 남길 수 있습니다. 시간 초과 로그를 없애려고 사설 IP 필터를 무작정 추가하지 마세요. 사내 사이트가 사설 IP를 반환하는 것은 정상입니다.
respect-rules: DNS 업스트림 연결에도 규칙 적용
respect-rules: true는 “코어가 DNS 업스트림에 연결할 때 어떤 경로를 선택하는가”를 제어합니다. “도메인 규칙을 사용할지 여부”를 설정하는 옵션이 아닙니다. 활성화하기 전에 프록시 노드 자체의 도메인을 조회할 proxy-server-nameserver를 준비하세요. 노드 조회에는 프록시가 필요하고 프록시 연결에는 노드 조회가 필요한 순환 의존성을 막을 수 있습니다.
dns:
respect-rules: true
proxy-server-nameserver:
- https://dns.alidns.com/dns-query
이 내용은 기존 설정에 추가하는 조각이므로 DNS 설정 전체를 대체하는 데 사용하지 마세요. 초기 조회에 사용하는 default-nameserver, 일반 업스트림 및 다른 옵션은 유지하고, 노드 도메인 조회용 업스트림이 시작 단계부터 연결 가능한지 확인하세요. 노드용 리졸버를 설정해도 모든 서비스 도메인의 리졸버가 설정되는 것은 아닙니다.
- 먼저 프록시 노드에 연결할 수 있는지, 규칙에서 참조하는 정책 그룹 이름이 실제로 있는지 확인하세요.
- DNS 서비스의 도메인이나 대상 IP에 어떤 규칙이 적용되는지 확인하세요. 해당 업스트림이 연결할 수 없는 경로로 보내진다면 이 옵션을 활성화해도 실패가 더 확실해질 뿐입니다.
- 로그에서 업스트림 연결에 선택된 아웃바운드를 확인한 다음 웹사이트 연결을 테스트하세요. 노드 지연 시간 아이콘만 보고 DNS가 정상이라고 판단하지 마세요.
TUN의 dns-hijack: 가상 인터페이스로 들어오는 53번 포트 트래픽 가로채기
dns.enable: true만 설정해도 운영체제의 모든 DNS 경로가 자동으로 바뀌지는 않습니다. TUN 모드에서는 dns-hijack을 사용해 TUN으로 들어오고 조건에 맞는 DNS 트래픽을 코어로 전달할 수 있습니다. 아래는 기존 mihomo 설정에 병합할 수 있는 기본 예시입니다. 기존 노드, 정책 그룹, 규칙은 그대로 유지해야 합니다.
dns:
enable: true
listen: 127.0.0.1:1053
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
default-nameserver:
- 223.5.5.5
- 119.29.29.29
nameserver:
- https://dns.alidns.com/dns-query
- https://doh.pub/dns-query
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
- tcp://any:53
any:53은 UDP DNS에 사용하고, tcp://any:53을 추가하면 TCP DNS도 처리할 수 있습니다. 대상 포트를 먼저 로컬 1053으로 바꿀 필요는 없습니다. 조건에 맞는 트래픽은 가로채기 동작을 통해 내장 DNS로 전달됩니다. listen은 명시적인 DNS 질의에 사용할 별도의 리스너입니다. 루프백 주소를 유지하면 실수로 LAN에 DNS 서비스를 공개하는 일을 막을 수 있습니다.
여기서 198.18.0.1/16은 fake-ip 매핑에 사용됩니다. 조회 결과로 해당 대역의 가상 주소가 반환되는 것은 정상이며, 업스트림이 실제로 그 주소를 반환했다는 뜻은 아닙니다. 코어는 매핑으로 도메인을 복원한 뒤 연결을 처리합니다. 앱에 실제 IP가 필요한 경우에는 사용 사례에 따라 fake-ip-filter를 검토하세요. 예약된 주소 대역 전체를 DNS 오류로 취급해서는 안 됩니다.
- 데스크톱: TUN을 사용하려면 관리자 권한, 서비스 모드 또는 관련 네트워크 권한이 필요할 수 있습니다. 필요한 조건은 클라이언트와 운영체제에 따라 다릅니다.
- Android: VPN 권한이 다른 VPN 앱과 충돌할 수 있으며, 시스템의 ‘비공개 DNS’ 설정이 DNS 경로를 바꿀 수도 있습니다.
- 브라우저: 브라우저에 내장된 보안 DNS는 HTTPS를 통해 443번 포트로 요청을 보내므로, 53번 포트 가로채기만으로 자동 처리된다고 기대해서는 안 됩니다.
- LAN 및 IPv6: TUN으로 들어오지 않는 트래픽, 라우팅에서 제외된 주소, 다른 인터페이스를 이용하는 경로는 각각 별도로 확인해야 합니다.
예시의 dns.ipv6: false는 DNS가 AAAA 질의를 처리하는 방식을 제어합니다. 운영체제의 IPv6를 끄는 설정도 아니고, IPv6를 통한 우회를 완전히 막는 방법도 아닙니다. Linux의 로컬 DNS 서비스, macOS의 LAN DNS 경로, Android의 VPN 구현에도 각각 제약이 있을 수 있습니다. 가로채기가 적용되는지 확인하려면 실제 요청을 관찰해야 합니다.
명령어로 단계별 확인: 먼저 리스너, 다음 가로채기, 마지막으로 업스트림
1단계: 설정과 로컬 리스너 확인
수정하기 전에 기존 설정을 백업하세요. 코어를 독립 실행하는 경우 아래 명령으로 설정을 먼저 검사할 수 있습니다. GUI 클라이언트에서는 실제로 사용하는 코어와 작업 디렉터리를 지정해 같은 이름의 다른 파일을 검사하지 않도록 하세요.
mihomo -t -f config.yaml
dig @127.0.0.1 -p 1053 example.com A
dig @127.0.0.1 -p 1053 example.com A +tcp
앞의 두 질의는 1053 리스너의 UDP 및 TCP 경로를 각각 확인합니다. dig가 없는 Windows 환경에서는 nslookup -port=1053 example.com 127.0.0.1을 실행할 수 있습니다. fake-ip가 반환되면 요청이 리졸버에 도달해 매핑을 받았다는 뜻일 뿐, 지정한 DoH가 실제 IP를 성공적으로 반환했다는 증거는 아닙니다.
2단계: TUN이 53번 포트를 가로채는지 확인
dig @8.8.8.8 example.com A
dig @8.8.8.8 example.com A +tcp
여기서 명시한 8.8.8.8은 테스트 대상입니다. 요청이 TUN에 가로채이면 실제로 질의를 받은 업스트림은 이 주소가 아닐 수 있습니다. 코어 로그와 fake-ip 반환 결과를 함께 확인하세요. dig 출력의 SERVER 행만 보아서는 안 됩니다. 프로그램이 원래 지정한 대상이 계속 표시될 수 있습니다.
3단계: 실제 DNS 응답과 웹사이트 연결 확인
- 로그 수준을 일시적으로
debug로 높이고, 문제가 발생한 요청의 도메인, 오류 메시지, 업스트림 주소를 기록하세요. 로그를 공유하기 전에는 구독 주소와 노드 인증 정보를 가리세요. - 클라이언트의 DNS 캐시를 지우거나 코어를 재시작한 뒤 아직 조회하지 않은 도메인으로 테스트하세요. Windows 시스템 캐시는
ipconfig /flushdns로 지울 수 있지만, 브라우저와 코어의 캐시까지 함께 지워지는 것은 아닙니다. - 실제 응답을 확인해야 한다면 통제된 테스트에서
enhanced-mode: redir-host를 임시로 설정한 뒤 재시작해 다시 질의할 수 있습니다. 테스트가 끝나면 원래 설정으로 되돌리세요. 앱에 남아 있는 이전 fake-ip 매핑이 판단에 영향을 줄 수 있습니다. - 마지막으로 웹사이트에 접속해 연결 규칙을 확인하세요. DNS 조회는 성공했지만 HTTPS가 시간 초과된다면 프록시 출구, 연결 라우팅, TLS, MTU를 계속 점검해야 합니다. 리졸버만 반복해서 바꾸지 마세요.
이 문서의 명령은 문제 재현과 원인 파악을 위한 절차이며, 특정 네트워크에서 측정한 지연 시간은 포함하지 않습니다. 성능을 비교할 때는 같은 네트워크에서 캐시가 비어 있는 상태와 채워진 상태를 각각 기록하세요. 두 번째 조회 시간만 비교하면 리졸버보다 캐시가 얼마나 잘 동작하는지 측정하게 됩니다.
자주 발생하는 문제와 설정 되돌리기 순서
| 증상 | 우선 확인할 항목 | 해결 방향 |
|---|---|---|
| 로컬 1053 질의 시간 초과 | 설정 로드, 포트 사용 여부, 코어 로그 | 먼저 리스너를 복구한 다음 업스트림 확인 |
| 1053은 정상인데 앱이 시스템 DNS를 계속 사용 | TUN 권한, 라우팅, 브라우저 보안 DNS | 요청이 가로채기 범위에 들어오는지 확인 |
| respect-rules를 켠 뒤 모든 요청이 시간 초과 | 노드 도메인 조회 및 DNS 업스트림의 아웃바운드 규칙 | 노드 전용 DNS 조회 경로 구성 |
| 일부 도메인에서만 문제 발생 | 정책 적용 여부, fallback 조건, 캐시 | 도메인을 하나씩 확인하고 설정 전체를 한꺼번에 바꾸지 않기 |
| 구독 업데이트 후 문제가 다시 발생 | 최종 적용 설정과 오버라이드 병합 결과 | 업데이트 후에도 유지되는 오버라이드 기능에 변경 사항 저장 |
설정을 되돌릴 때는 먼저 “연결 가능한 업스트림 하나, 복잡한 필터는 끔” 상태로 복구해 일반 DNS 조회가 되는지 확인하세요. 그다음 TUN 가로채기를 켜고, 마지막으로 fallback과 규칙 기반 라우팅을 추가합니다. 각 단계의 설정과 질의 결과를 기록해 두세요. 옵션이 많다고 DNS가 더 안정적인 것은 아닙니다. 각 요청이 왜 특정 업스트림을 사용했는지 설명할 수 있어야 설정을 유지보수할 수 있습니다.