1. 로그 수집: 요청을 고정한 뒤 로그 수준 높이기

Clash 클라이언트의 UI 로그와 코어 실행 로그는 서로 다른 계층의 정보를 기록합니다. UI 로그에는 구독 다운로드, 서비스 시작, 설정 병합 등이 기록될 수 있고, 코어 로그에는 수신 대기 포트, DNS, 규칙 매칭, 아웃바운드 연결이 주로 기록됩니다. 웹페이지가 열리지 않으면 먼저 코어가 실행 중인지 확인한 다음 해당 요청이 코어에 들어왔는지 살펴보세요. 클라이언트 UI의 오류 화면만으로는 노드나 규칙 문제를 판단하기 어려운 경우가 많습니다.

최소 재현 정보 기록

  1. 클라이언트 이름과 버전, 코어 이름과 전체 버전을 기록하세요. Clash 원본과 mihomo는 지원하는 필드가 다르므로 ‘최신 버전’이라고만 적어서는 안 됩니다.
  2. 현재 설정 이름과 실행 모드, 시스템 프록시 또는 TUN 활성화 여부를 기록하세요. 규칙을 점검할 때는 규칙 모드를 사용해 전체 모드가 예상된 규칙을 우회하지 않도록 합니다.
  3. 현재 로그 화면을 비우고 시간을 기록한 뒤 문제가 있는 주소 하나만 방문하세요. 약 10초 기다린 다음 새로고침을 반복하지 말고 같은 시간대의 로그를 저장하세요.
  4. 연결 목록에서 대상, 매칭된 규칙, 정책 그룹, 최종 노드도 함께 확인하세요. 로그에 아웃바운드 정보가 없으면 연결 목록에서 보완할 수 있습니다.

더 자세한 정보가 필요하면 현재 클라이언트의 로그 페이지에서 로그 수준을 조정하세요. UI에 설정 항목이 없다면 클라이언트가 지원하는 설정 편집 또는 오버라이드 기능으로 아래 필드를 지정할 수 있습니다. 구독 클라이언트는 실행 설정을 다시 생성할 수 있으므로 최종 적용값을 확인하세요. 이후 덮어써질 구독 캐시 파일만 수정해서는 안 됩니다.

log-level: debug
수준주요 용도확인할 내용
debug짧은 시간 동안 문제 상황 재현DNS, 연결 및 코어에서 제공하는 디버깅 정보
info일상적인 실행 상태 확인시작 정보, 규칙 매칭, 연결 기록
warning이상 이벤트 확인연결 실패, 리소스 로드 이상
error심각한 오류 위주로 확인설정 로드 및 주요 구성 요소 오류
silent일반 로그 출력 끄기문제 재현 단계에는 적합하지 않음

개별 메시지의 수준은 코어가 결정하므로 warning이 프록시 서비스 전체의 중단을 뜻하지는 않습니다. 문제 재현이 끝나면 수준을 info로 되돌리세요. 로그를 공유하기 전에 구독 주소의 토큰, 노드 비밀번호, 제어 인터페이스 키, 개인 도메인은 가리세요. 포트, 오류 유형, 규칙 순서는 남겨 두세요.

2. dial tcp 시간 초과: 노드 연결과 대상 연결 구분하기

dial tcp는 프로그램이 TCP 연결을 시도한다는 뜻입니다. ‘DNS 오류’를 의미하지 않으며, 이 문구만으로 노드 장애를 단정할 수도 없습니다. 뒤에 나오는 주소가 프록시 서버인지, 직접 연결 대상인지, 프록시 체인의 다음 홉인지 확인하는 것이 중요합니다. 아래 예시는 오류 형식만 보여 주며, 문서용 주소이므로 실제 노드로 사용할 수 없습니다.

dial tcp 192.0.2.10:443: i/o timeout
dial tcp 192.0.2.10:443: connect: connection refused
dial tcp [2001:db8::10]:443: connect: network is unreachable

오류 유형별 확인 방향

  • i/o timeout: 제한 시간 안에 연결 또는 읽기·쓰기가 완료되지 않았다는 뜻입니다. 해당 줄의 노드 주소, 포트, 아웃바운드 인터페이스와 네트워크 경로를 확인하세요. 시간 제한만 늘려 문제를 가리지는 마세요.
  • connection refused: 보통 연결이 명시적으로 거부됐다는 뜻입니다. 먼저 포트 설정, 원격 서비스의 수신 대기 여부, 로컬 또는 중간 장비의 거부 정책을 확인하세요.
  • network is unreachable: 현재 네트워크 스택에서 사용할 수 있는 경로가 없다는 뜻입니다. 대상이 IPv6 주소라면 노드 비밀번호를 의심하기 전에 시스템의 IPv6 라우팅을 확인하세요.

오류가 노드 서버를 가리키면 먼저 같은 정책 그룹의 다른 정상 노드로 바꾸고 동일한 대상을 다시 테스트하세요. 특정 노드만 실패한다면 해당 노드의 서버 도메인, 포트, 프로토콜 매개변수를 확인하세요. 여러 노드가 동시에 실패한다면 로컬 네트워크, 노드 도메인 조회, 프록시 루프백을 점검하세요. 노드 속도 테스트 성공은 테스트에 포함된 요청만 성공했다는 뜻이며, 모든 웹사이트나 UDP 트래픽이 정상이라는 보장은 아닙니다.

연결 목록에 DIRECT가 표시된다면 대상 웹사이트로 직접 연결하는 경로에서 실패했을 수 있습니다. 이때는 먼저 매칭된 규칙을 확인하세요. 근거 없이 클라이언트를 다시 설치할 필요는 없습니다. 규칙은 순서대로 매칭되므로 앞쪽의 DOMAIN-SUFFIX 또는 규칙 세트에서 아웃바운드가 이미 결정됐다면 뒤에 있는 MATCH는 결과를 바꾸지 않습니다.

3. DNS 조회 실패: 조회 경로를 단계별로 확인하기

no such host는 이름이 존재하지 않거나 조회 경로에서 부정 응답을 받은 경우에 흔합니다. lookup ... i/o timeout은 DNS 요청이 제때 응답을 받지 못한 상황에 가깝고, SERVFAIL은 DNS 서버가 조회를 완료하지 못했다는 뜻입니다. 서로 다른 신호이므로 모두 프록시 노드 교체로 해결하려 해서는 안 됩니다.

먼저 어떤 도메인을 조회하는지 확인하기

  1. 대상 웹사이트 도메인: 코어 DNS가 활성화되어 있는지, 앱이 시스템 DNS를 사용하는지, Fake-IP 요청이 실제로 코어에 전달되는지 확인하세요.
  2. 노드 서버 도메인: 노드 도메인의 조회 경로를 확인하세요. mihomo에서는 proxy-server-nameserver로 노드 도메인 조회용 DNS 서버를 지정할 수 있습니다. 구체적인 동작은 현재 코어 버전의 문서를 확인하세요.
  3. 암호화 DNS 서버 도메인: 조회 시작에 사용하는 default-nameserver를 확인하세요. 상위 DNS 서버의 도메인 자체를 조회할 수 없으면 조회 경로를 시작하지 못할 수 있습니다.

아래는 로컬 1053 포트를 수신 대기하는 최소 DNS 진단 설정입니다. 기존에 있는 dns 맵 하나에 병합하고, 현재 환경에 필요한 다른 필드는 유지하세요. 일반 DNS를 문제 진단에 사용하는 예시일 뿐 모든 네트워크 환경에 적용할 최종 설정은 아니며, 시스템 DNS를 자동으로 변경하지도 않습니다.

dns:
  enable: true
  listen: 127.0.0.1:1053
  enhanced-mode: redir-host
  nameserver:
    - 223.5.5.5

dig가 설치된 환경에서는 이 수신 대기 포트를 바로 테스트할 수 있습니다. 아래 두 명령은 각각 IPv4와 IPv6 레코드를 조회합니다. AAAA 레코드가 없다고 해서 A 레코드 조회까지 실패한 것은 아닙니다.

dig @127.0.0.1 -p 1053 example.com A
dig @127.0.0.1 -p 1053 example.com AAAA

로컬 수신 대기 포트 조회는 성공하는데 앱에서 계속 DNS 조회 실패가 발생한다면 앱 자체의 보안 DNS, 브라우저 DNS 캐시, 실제 트래픽 처리 경로를 확인하세요. 수신 대기 포트에서도 실패한다면 상위 DNS 서버에 연결할 수 있는지, respect-rules 같은 기능을 켠 뒤 조회 의존성 루프가 생기지 않았는지 살펴보세요. 상위 DNS, Fake-IP, 라우팅 규칙을 한꺼번에 바꾸면 어떤 변경이 효과가 있었는지 파악하기 어렵습니다.

4. 포트 충돌: 수신 대기 프로세스와 실제 프록시 포트 확인하기

시작할 때 bind: address already in use가 표시되면 보통 수신 대기 주소와 포트가 충돌한 것입니다. Windows에서는 ‘각 소켓 주소는 일반적으로 한 번만 사용할 수 있습니다’라는 메시지가 표시될 수도 있습니다. 반면 permission denied는 권한, 보안 정책, 포트 예약을 따로 확인해야 하는 오류이며, 모두 기존 프로세스의 포트 점유로 분류해서는 안 됩니다.

먼저 오류 줄에서 구체적인 포트를 확인한 뒤 해당 설정 필드를 찾으세요. 예를 들어 mixed-port: 7890은 HTTP 및 SOCKS 프록시 진입점을 제공하고, external-controller: 127.0.0.1:9090은 관리 인터페이스입니다. 두 포트의 용도는 서로 다릅니다. 아래 포트는 진단용 예시이며, 실제 클라이언트 포트는 실행 설정을 기준으로 확인하세요.

Windows: 7890 포트의 수신 대기 프로세스 확인

netstat -ano | findstr :7890
tasklist /FI "PID eq 1234"

첫 번째 명령은 원격 포트까지 찾을 수 있으므로 로컬 주소 열과 LISTENING 상태를 확인하세요. 두 번째 명령의 1234는 예시 PID입니다. 실행할 때 첫 번째 출력에서 확인한 실제 프로세스 번호로 바꾸세요. 먼저 클라이언트에서 중복 실행된 인스턴스를 정상 종료하세요. 정체를 알 수 없는 시스템 프로세스를 바로 종료하지 마세요.

macOS 및 Linux: TCP 수신 대기 프로세스만 확인

# macOS
lsof -nP -iTCP:7890 -sTCP:LISTEN

# Linux
ss -ltnp 'sport = :7890'

Linux에서 다른 사용자의 프로세스 정보를 확인하려면 관리자 권한이 필요할 수 있습니다. 7891로 포트를 변경한다면 시스템 프록시, 브라우저의 수동 프록시, 터미널 환경 변수도 함께 수정해야 합니다. 코어 포트만 바꾸면 앱이 계속 이전 포트에 연결합니다. allow-lan은 LAN 접근 범위를 제어하는 설정이지, 로컬 포트 충돌을 해결하는 스위치가 아닙니다.

5. 설정 파싱 오류: 문법, 필드, 참조를 따로 확인하기

설정을 불러올 수 없다면 먼저 시작 오류부터 해결한 뒤 네트워크를 점검하세요. yaml: line ...은 대개 YAML 파싱 문제를 가리킵니다. proxy ... not found와 같은 메시지는 참조 이름과 관련된 경우가 많습니다. 지원하지 않는 프로토콜 유형이나 인식할 수 없는 필드는 코어 호환성 문제일 수 있습니다. 오류가 표시된 줄부터 확인하되, 실제 들여쓰기 오류는 앞부분에 있을 수도 있습니다.

  • 들여쓰기: 탭 대신 공백을 사용하세요. 같은 수준의 키는 같은 만큼 들여쓰고, 목록 항목은 - 뒤의 공백을 유지하세요.
  • 중복 키: 같은 수준에 두 번째 dns, rules, proxy-groups를 추가하지 마세요. 파서에 따라 오류가 나거나 내용이 덮어써질 수 있어 결과를 신뢰하기 어렵습니다.
  • 이름 참조: 규칙에서 참조하는 정책 그룹, 정책 그룹에서 참조하는 노드, RULE-SET에서 참조하는 규칙 제공자의 이름은 정의된 이름과 일치해야 합니다.
  • 코어 기능: VLESS, Hysteria2 등의 설정을 Clash 원본에서 모두 읽을 수 있다고 가정해서는 안 됩니다. 클라이언트 이름만 볼 것이 아니라 실제 실행 중인 코어를 확인하세요.
  • 원격 리소스: 규칙 세트 다운로드 실패는 리소스 로드 문제일 수 있으며 YAML 문법 오류와는 다릅니다. 해당 제공자의 URL, 파일 형식, 캐시 경로, 다운로드 시 사용되는 네트워크 경로를 확인하세요.

mihomo 코어를 직접 실행한다면 먼저 설정을 테스트할 수 있습니다. 아래 명령을 사용하려면 현재 디렉터리에 해당 실행 파일과 설정 파일이 있어야 합니다. 테스트 설정은 클라이언트가 실제로 생성한 실행 설정과 최대한 일치해야 합니다.

# macOS / Linux
./mihomo -t -f ./config.yaml

# Windows PowerShell
.\mihomo.exe -t -f .\config.yaml

설정 테스트를 통과했다는 것은 해당 검사에서 로드를 막는 문제를 찾지 못했다는 뜻일 뿐, 노드 연결이나 모든 규칙 세트의 정상 작동을 보장하지는 않습니다. 구독 원문은 테스트를 통과하지만 클라이언트 시작에 실패한다면 오버라이드, 스크립트 병합, 클라이언트 생성 설정의 차이를 확인하세요. 수정 전에 사본을 저장하고 한 번에 한 종류의 오류만 고친 뒤 다시 테스트하세요.

6. 시스템 프록시와 TUN: 같은 요청으로 트래픽 처리 경로 비교하기

‘브라우저에서는 열리지만 터미널에서는 안 된다’면 앱이 시스템 프록시를 따르는지 확인해야 하는 경우가 많습니다. 시스템 프록시는 모든 프로그램의 트래픽을 자동으로 처리하지 않습니다. TUN은 가상 네트워크 인터페이스, 라우팅, DNS 처리까지 관련되므로 점검 범위가 더 넓습니다. 비교 결과 없이 여러 프록시 도구와 TUN 인스턴스를 동시에 켜지 마세요.

명시적 프록시 진입점부터 확인하기

실행 설정의 혼합 포트가 실제로 7890이라고 가정하면, 아래 요청으로 앱이 시스템 프록시를 읽는지 여부와 관계없이 테스트할 수 있습니다. Windows PowerShell에서는 이전 버전 환경의 명령 별칭이 결과에 영향을 주지 않도록 curl.exe를 사용하세요. macOS와 Linux에서는 명령 이름을 curl로 바꾸면 됩니다.

curl.exe -v --connect-timeout 10 --max-time 20 --noproxy "" --proxy http://127.0.0.1:7890 https://example.com/

이 명령은 연결 단계 제한 시간을 10초, 전체 제한 시간을 20초로 설정해 로그 시간과 대조하기 쉽게 합니다. 실측 지연 시간은 아닙니다. 127.0.0.1:7890에 즉시 연결되지 않으면 먼저 수신 대기를 확인하세요. 프록시 터널은 연결됐지만 TLS가 실패하면 이후 핸드셰이크를 확인하세요. HTTP 응답을 받았다면 상태 코드를 살펴보세요. 403 같은 응답을 프록시 진입점 장애와 동일시해서는 안 됩니다.

이어서 TUN 처리 경로 비교하기

명시적 프록시 요청은 성공하지만 일반 앱 요청이 실패한다면 시스템 프록시 설정, 앱 자체의 프록시 설정, TUN 라우팅을 중점적으로 확인하세요. TUN을 켠 뒤 문제가 생겼다면 설정 사본을 보관한 상태에서 TUN을 잠시 끄고 명시적 프록시 결과와 비교할 수 있습니다. 확인할 필드로는 tun.enable, auto-route, dns-hijack가 있지만, 실제 지원 여부와 권한 요건은 코어, 클라이언트, 운영체제에 따라 다릅니다.

dns-hijack가 모든 암호화 DNS를 가로챈다고 생각해서는 안 됩니다. 일반적인 DNS 가로채기 설정은 조건에 맞는 DNS 트래픽을 주로 처리하며, 앱 자체의 HTTPS DNS 요청은 별도 경로를 사용할 수 있습니다. 로그에 해당 연결이 전혀 없다면 요청이 코어에 들어왔는지 먼저 확인하세요. 이미 들어왔다면 규칙, 아웃바운드, DNS 조회, 핸드셰이크 순서로 살펴보세요.

7. 수정 확인: 재현 가능한 근거 남기기

문제 해결을 마치기 전에 처음 실패했던 주소로 다시 테스트하고, 로그의 매칭 규칙과 아웃바운드 노드가 예상과 일치하는지 확인하세요. 홈페이지가 한 번 열렸다는 것만으로 구독 업데이트, DNS, 백그라운드 앱까지 복구됐다고 볼 수는 없습니다.

  1. 시작 확인: 코어 로드가 완료되고 프록시 진입점이 정상적으로 수신 대기하며, 포트 바인딩 오류가 반복되지 않습니다.
  2. 요청 확인: 원래 요청이 성공하고 로그에 해당 요청의 반복적인 시간 초과나 DNS 조회 오류가 더 이상 나타나지 않습니다.
  3. 경로 확인: 직접 연결과 프록시 규칙이 각각 예상한 정책과 매칭되고, TUN 상태가 사용 목적에 맞습니다.
  4. 설정 유지 확인: 클라이언트를 다시 시작하거나 구독을 업데이트한 뒤에도 변경 사항이 적용되어 있고 설정 생성 과정에서 덮어써지지 않습니다.

문제가 계속되어 문의해야 한다면 클라이언트 및 코어 버전, 운영체제 버전, 재현 시간, 대상 유형, 관련 설정 일부, 앞뒤 맥락이 포함된 연속 로그, 항목별 테스트 결과를 정리하세요. 마지막 줄의 timeout만 따로 캡처하는 것보다 원인을 찾기 쉽습니다. 필드의 의미는 프로토콜 참고서에서, 규칙·DNS·TUN의 개념 차이는 개념 빠른 참조에서 확인하세요.