Clash 시스템 프록시가 작동하지 않을 때: 브라우저는 접속되지만 터미널은 실패하는 단계별 문제 해결

브라우저 프록시, 시스템 프록시, 터미널 환경 변수를 구분하고 수신 포트·앱 재정의·DNS 경로를 차례로 점검해 모드만 반복해서 바꾸는 일을 피합니다.

먼저 문제가 발생한 계층을 확인하세요

브라우저에서는 웹 페이지가 열리지만 터미널의 curl·git·패키지 관리자 또는 개발 도구의 연결이 실패한다고 해서 Clash 코어가 중단된 것은 아닙니다. 더 흔한 원인은 두 프로그램이 서로 다른 프록시 경로를 사용하기 때문입니다. 브라우저는 운영체제 프록시를 읽거나 확장 프로그램이 별도로 제어할 수 있지만, 터미널 프로그램은 자체 설정, 프록시 환경 변수 또는 명령줄 인자만 읽는 경우가 많습니다.

문제를 점검할 때는 경로를 네 계층으로 나누세요. 클라이언트 UI가 코어를 정상적으로 관리하는지, 코어가 로컬 포트를 수신 중인지, 대상 프로그램이 해당 포트로 요청을 보내는지, DNS와 규칙이 코어에 전달된 뒤 올바르게 처리되는지를 각각 확인해야 합니다. 한 번에 한 계층만 검증해야 문제의 범위를 정확히 좁힐 수 있습니다.

증상 우선 확인할 항목 일반적인 원인
브라우저는 정상인데 curl 실패 터미널 프록시 환경 변수 curl이 시스템 프록시를 읽지 않거나 변수가 이전 포트를 가리킴
브라우저와 터미널 모두 실패 코어 상태 및 수신 포트 코어가 시작되지 않았거나 설정 로드에 실패했거나 포트가 사용 중임
도메인은 실패하지만 IP 요청은 정상 DNS 경로 로컬 DNS 조회 실패, 앱이 Clash DNS 우회 또는 fake-ip와 호환되지 않음
Git 또는 패키지 관리자만 실패 앱 전용 설정 앱이 환경 변수를 재정의했거나 이전 프록시 주소를 계속 사용함
TUN을 켜면 터미널이 정상으로 돌아옴 기존 시스템 프록시 경로 프로그램이 원래 시스템 프록시를 읽지 않았으며, TUN이 네트워크 계층에서 대신 처리함

1단계: 코어가 실행 중이며 올바른 포트를 수신하는지 확인

클라이언트 UI에서 실제 포트 확인

포트가 반드시 7890일 것이라고 가정하지 마세요. 많은 Clash 또는 mihomo 설정이 mixed-port: 7890을 사용하지만, port: 7890socks-port: 7891을 따로 지정할 수도 있고 포트 충돌로 클라이언트가 다른 번호를 사용할 수도 있습니다. 현재 클라이언트의 「설정」→「매개변수 설정」 또는 「설정」→「포트 설정」에서 HTTP, SOCKS5, Mixed Port의 실제 값을 확인하세요. 메뉴 이름은 클라이언트 버전에 따라 달라질 수 있으므로 화면에 표시되는 값을 기준으로 삼아야 합니다.

설정 파일의 일반적인 수신 설정은 다음과 같습니다. 여기서는 필드를 식별하기 위한 예시일 뿐이며, 실제 점검에서는 현재 로드된 설정과 실행 상태를 기준으로 해야 합니다.

mixed-port: 7890
allow-lan: false
mode: rule
log-level: info

mixed-port는 하나의 포트에서 HTTP와 SOCKS5 연결을 모두 받을 수 있습니다. 포트를 분리한 설정이라면 HTTP 클라이언트는 port에, SOCKS5 클라이언트는 socks-port에 연결해야 합니다. 프로토콜과 포트가 맞지 않으면 연결이 즉시 끊기거나 빈 응답이 반환되거나 프록시 핸드셰이크 실패가 표시되는 경우가 많습니다.

로컬에서 수신 상태 확인

Windows PowerShell에서는 지정한 포트가 수신 중인지 다음 명령으로 확인할 수 있습니다.

Get-NetTCPConnection -State Listen |
  Where-Object LocalPort -In 7890,7891 |
  Select-Object LocalAddress,LocalPort,OwningProcess

macOS와 Linux에서는 다음 명령을 사용합니다.

lsof -nP -iTCP:7890 -sTCP:LISTEN
lsof -nP -iTCP:7891 -sTCP:LISTEN

시스템에서 ss를 제공한다면 다음과 같이 실행할 수도 있습니다.

ss -lntp | grep -E ':(7890|7891)\b'

127.0.0.1:7890이 보인다는 것은 해당 포트가 로컬 연결만 받는다는 뜻이며, 터미널과 Clash가 같은 컴퓨터에 있다면 충분합니다. 명령을 WSL, 컨테이너, 가상 머신 또는 다른 LAN 장치에서 실행하는 경우 그 환경의 127.0.0.1은 호스트가 아니라 자기 자신을 가리킵니다. 이때는 호스트 주소, 가상 네트워크 경계와 allow-lan 설정을 명확히 확인해야 하며, 수신 주소를 곧바로 전체 네트워크에 공개한 뒤 점검을 중단해서는 안 됩니다.

2단계: 시스템 설정을 우회해 프록시 포트를 직접 테스트

포트가 수신 중인 것을 확인했다면 명시적 인자로 요청을 프록시에 직접 전달하세요. 이렇게 하면 “코어와 노드를 사용할 수 있는지”와 “운영체제가 프록시 설정을 올바르게 전달하는지”를 분리해 확인할 수 있습니다.

curl로 HTTP 프록시 확인

curl -v --connect-timeout 10 \
  -x http://127.0.0.1:7890 \
  https://example.com/

Windows PowerShell에서 curlInvoke-WebRequest의 별칭이라면 curl.exe를 명시적으로 호출하세요.

curl.exe -v --connect-timeout 10 ^
  -x http://127.0.0.1:7890 ^
  https://example.com/

명시적 프록시 요청은 성공하지만 -x 없는 요청이 실패한다면 코어, 수신 포트와 현재 정책은 대체로 정상이며 터미널 프로그램이 프록시를 사용하지 않는 것이 문제입니다. 명시적 요청도 실패한다면 Clash 로그를 함께 확인하세요. 로그에 연결 기록이 전혀 없다면 보통 요청이 해당 포트에 도달하지 않은 것입니다. 연결 기록은 있지만 정책이 REJECT로 처리되거나 노드 시간 초과 또는 TLS 오류가 발생한다면 규칙, 프록시 그룹과 상위 연결을 계속 점검해야 합니다.

SOCKS5를 확인하고 로컬 조회와 프록시 조회를 구분

curl -v --connect-timeout 10 \
  --proxy socks5h://127.0.0.1:7891 \
  https://example.com/

socks5hh는 도메인 조회를 프록시 측에서 처리한다는 뜻이며, socks5는 보통 로컬에서 먼저 도메인을 조회합니다. socks5h는 성공하고 socks5는 실패한다면 문제의 초점은 프록시 포트가 아니라 로컬 DNS로 옮겨갑니다. 이 비교 테스트는 노드를 바로 바꾸는 것보다 원인을 더 분명하게 보여 줍니다.

테스트 대상은 안정적이며 현재 규칙의 예상 동작에 맞는 주소를 선택해야 합니다. 규칙에서 특정 도메인을 DIRECT로 지정했다면 해당 요청은 선택한 프록시 노드를 거치지 않을 수 있고, REJECT라면 실패는 설정에 따른 결과입니다. 규칙 모드는 위에서부터 순서대로 평가하며 처음 일치한 규칙이 경로를 결정하므로, 로그에서 실제로 적용된 규칙과 정책도 확인해야 합니다.

3단계: 터미널에 올바른 프록시 변수 설정

macOS 및 Linux의 현재 셸

HTTP 또는 Mixed Port를 사용하는 로컬 Clash라면 현재 터미널 세션에서 다음과 같이 설정할 수 있습니다.

export HTTP_PROXY=http://127.0.0.1:7890
export HTTPS_PROXY=http://127.0.0.1:7890
export ALL_PROXY=socks5h://127.0.0.1:7891
export NO_PROXY=localhost,127.0.0.1,::1

많은 프로그램은 소문자 변수만 인식하고, 일부 프로그램은 대문자 변수를 우선 읽습니다. 호환성 차이를 배제하려면 두 변수 쌍을 모두 설정할 수 있지만 값은 반드시 같아야 합니다.

export http_proxy="$HTTP_PROXY"
export https_proxy="$HTTPS_PROXY"
export all_proxy="$ALL_PROXY"
export no_proxy="$NO_PROXY"

이 명령은 현재 셸과 그 이후에 실행되는 하위 프로세스에만 영향을 주며, 이미 열려 있는 편집기·터미널 탭·백그라운드 서비스의 설정을 자동으로 바꾸지 않습니다. 영구 적용이 필요하다면 사용하는 셸에 맞춰 ~/.zshrc, ~/.bashrc 또는 해당 시작 파일에 기록한 뒤 새 터미널을 열어 확인하세요. 여러 시작 파일에 서로 다른 포트를 동시에 남겨 두지 마세요.

Windows PowerShell의 현재 세션

$env:HTTP_PROXY = "http://127.0.0.1:7890"
$env:HTTPS_PROXY = "http://127.0.0.1:7890"
$env:ALL_PROXY = "socks5://127.0.0.1:7891"
$env:NO_PROXY = "localhost,127.0.0.1,::1"

$env:로 설정한 변수는 현재 PowerShell 프로세스와 그 하위 프로세스에서만 유효합니다. 시스템 설정에서 사용자 환경 변수로 저장해도 이미 실행 중인 터미널에는 자동으로 반영되지 않으므로 닫았다가 다시 열어야 합니다. 실제 값을 확인하려면 다음을 실행하세요.

Get-ChildItem Env: |
  Where-Object Name -Match '^(HTTP|HTTPS|ALL|NO)_PROXY$'

이전 포트와 잘못된 변수 정리

클라이언트에서 포트를 바꾼 뒤에도 터미널에는 이전 값이 남아 있을 수 있습니다. 예를 들어 Clash는 7897로 변경했지만 HTTPS_PROXY는 여전히 7890을 가리키는 경우입니다. macOS와 Linux에서는 다음 명령으로 임시 삭제할 수 있습니다.

unset HTTP_PROXY HTTPS_PROXY ALL_PROXY NO_PROXY
unset http_proxy https_proxy all_proxy no_proxy

PowerShell의 현재 세션에서는 다음을 사용할 수 있습니다.

Remove-Item Env:HTTP_PROXY -ErrorAction SilentlyContinue
Remove-Item Env:HTTPS_PROXY -ErrorAction SilentlyContinue
Remove-Item Env:ALL_PROXY -ErrorAction SilentlyContinue
Remove-Item Env:NO_PROXY -ErrorAction SilentlyContinue

삭제한 뒤 먼저 프록시 없이 요청을 한 번 실행하고, 실제 포트에 맞춰 다시 설정하세요. 이렇게 하면 여러 설정 출처가 서로 덮어쓰는 문제가 아님을 확인할 수 있습니다.

4단계: Git·패키지 관리자·개발 도구의 독립 설정 확인

환경 변수가 올바르다고 해서 모든 도구가 이를 사용하는 것은 아닙니다. Git, npm, Python 도구 체인, Java 빌드 도구, 편집기와 컨테이너 런타임은 자체 프록시 설정을 저장할 수 있습니다. 점검할 때는 모든 설정 계층에 동시에 값을 쓰기보다 먼저 설정 출처를 확인한 다음 삭제할지 수정할지 결정해야 합니다.

Git 전역 및 저장소 설정

git config --show-origin --get-regexp 'http\..*proxy|https\..*proxy'

--show-origin은 설정이 시스템·사용자·현재 저장소 중 어디에서 왔는지 보여 줍니다. 이전 포트가 발견되면 전역 설정을 업데이트할 수 있습니다.

git config --global http.proxy http://127.0.0.1:7890
git config --global https.proxy http://127.0.0.1:7890

Git이 환경 변수를 따르도록 하려면 자체 재정의 항목을 삭제하세요.

git config --global --unset http.proxy
git config --global --unset https.proxy

저장소 수준 설정도 확인해야 합니다. .git/config의 설정이 사용자 설정을 덮어쓸 수 있기 때문입니다. HTTPS 요청을 HTTP 프록시로 보낼 때 https.proxy 값이 보통 http://로 시작하는 것은 클라이언트가 먼저 HTTP 프록시에 연결한 다음 CONNECT로 TLS 터널을 만들기 때문입니다. 최종 웹사이트가 평문 HTTP를 사용한다는 뜻은 아닙니다.

npm·pnpm 및 Python 도구

npm config get proxy
npm config get https-proxy
pnpm config get proxy
pnpm config get https-proxy
python -m pip config list -v

출력에 이전 주소가 표시된다면 해당 도구의 사용자 설정에서 수정해야 합니다. npm은 다음 명령으로 재정의 항목을 삭제해 환경 변수를 다시 읽도록 할 수 있습니다.

npm config delete proxy
npm config delete https-proxy

Python의 pip는 환경 변수를 읽을 수도 있고 사용자 디렉터리 또는 가상 환경 내부의 설정을 읽을 수도 있습니다. pip만 단독으로 입력하지 말고 python -m pip를 사용하면 현재 Python 인터프리터에 연결된 도구의 설정을 확인할 수 있습니다.

편집기 내장 터미널 및 원격 개발

바탕화면 아이콘으로 실행한 편집기는 터미널 프록시 변수를 수정하기 전에 이미 실행되어 있었을 수 있습니다. 내장 터미널은 편집기 프로세스가 시작될 때의 환경을 상속하므로 편집기를 완전히 종료한 뒤 다시 열어야 합니다. 원격 SSH, 개발 컨테이너와 WSL은 각각 독립된 환경입니다. 호스트의 시스템 프록시가 원격 호스트의 프록시로 자동 전환되지 않으며, 호스트의 127.0.0.1:7890에도 원격 호스트가 접근할 수 없습니다.

5단계: DNS·규칙 모드·TUN의 차이 확인

도메인과 IP를 비교해 DNS 경로 확인

터미널 오류에 Could not resolve host, Name or service not known 또는 getaddrinfo failed가 포함되어 있다면 아직 대상 사이트에 연결조차 하지 못한 상태입니다. 먼저 시스템 DNS 조회를 테스트하세요.

nslookup example.com
curl -v https://example.com/

그다음 socks5h를 사용하는 요청과 비교하세요. 프록시 측 조회는 성공하지만 일반 요청이 실패한다면 운영체제 DNS, VPN 또는 네트워크 확장의 조회 경로와 앱이 DNS를 직접 지정하는지 확인해야 합니다. mihomo의 fake-ip 모드는 예약 주소를 반환하고 코어가 도메인을 매핑하므로 해당 트래픽이 실제로 코어로 돌아와야 합니다. 시스템 네트워크 스택을 우회하거나 사용자 지정 DNS를 고정해 사용하는 일부 프로그램은 다르게 동작할 수 있습니다.

no-resolve는 해당 매개변수가 붙은 IP 규칙에만 적용됩니다. 일치하는 IP 규칙에 대해 도메인을 적극적으로 조회하지 않는다는 뜻이지, Clash 또는 mihomo 전체의 DNS를 끈다는 뜻은 아닙니다. 설정에 IP-CIDR,...,no-resolve가 보인다고 해서 모든 도메인 조회 오류를 이 매개변수 탓으로 돌려서는 안 됩니다.

모드 전환보다 규칙 로그가 더 많은 정보를 제공합니다

Rule 모드에서 코어는 설정에 적힌 규칙 순서대로 요청을 매칭합니다. 로그에는 보통 대상 도메인 또는 IP, 적용된 규칙, 사용한 정책 그룹과 최종 출구가 표시됩니다. 브라우저와 터미널이 같은 도메인에 접속했는데 서로 다른 규칙이 적용된다면, 터미널이 먼저 도메인을 IP로 조회했거나 앱이 다른 하위 도메인에 연결했거나 IPv4와 IPv6 결과가 다르거나 두 요청이 같은 코어 포트로 들어가지 않은 경우가 흔합니다.

모드를 잠시 Global로 바꾸는 것은 범위를 좁힐 때만 사용하세요. Global은 성공하고 Rule은 실패한다면 규칙과 정책 그룹을 확인해야 하며, 두 모드 모두 실패한다면 포트·DNS·노드와 네트워크 경로를 계속 점검해야 합니다. 테스트가 끝나면 원래 모드로 되돌리고, Global을 장기 사용해 규칙 문제를 해결하려고 하지 마세요.

TUN으로 해결할 수 있는 문제와 해결할 수 없는 문제

시스템 프록시는 운영체제의 프록시 설정을 읽는 앱을 주로 대상으로 합니다. TUN 모드는 가상 네트워크 인터페이스를 통해 더 폭넓은 IP 트래픽을 처리하므로 HTTP 또는 SOCKS5 프록시를 지원하지 않는 일부 터미널 프로그램이 TUN을 켠 뒤 다시 연결될 수 있습니다. 이는 기존 앱 계층의 프록시 경로가 해당 프로그램을 포함하지 않았다는 뜻이지, 시스템 프록시 버튼 자체가 고장 났다는 뜻은 아닙니다.

TUN을 켜기 전에 클라이언트의 「설정」→「TUN 모드」 또는 해당 네트워크 설정에서 필요한 권한을 확인하세요. Windows에서는 서비스 모드 또는 관리자 권한이 필요할 수 있고, macOS에서는 VPN 구성 또는 네트워크 확장 승인이 필요할 수 있으며, Linux에서는 네트워크 관리 권한·라우팅·DNS 설정이 관련되는 경우가 많습니다. mihomo 기반 구현은 클라이언트마다 진입점이 다르므로 현재 클라이언트의 화면과 로그를 기준으로 확인해야 합니다.

스위치를 반복해서 바꾸지 말고 결과를 바탕으로 문제를 좁히세요

위 점검을 마친 뒤에는 다음 순서로 재현 가능한 결론을 만들 수 있습니다. 각 단계에서 명령, 포트와 로그의 시간대를 기록하면 클라이언트나 설정을 바꾼 뒤에도 빠르게 다시 확인할 수 있습니다.

  1. 클라이언트에서 현재 코어가 실행 중인지 확인하고 HTTP·SOCKS5 또는 Mixed Port의 실제 포트를 기록합니다.
  2. lsof·ss 또는 Get-NetTCPConnection으로 해당 포트를 예상한 프로세스가 실제로 수신 중인지 확인합니다.
  3. curl -x 또는 curl --proxy socks5h://로 프록시에 명시적으로 연결하고 Clash 로그에 해당 요청이 나타나는지 확인합니다.
  4. 명시적 프록시가 성공한 뒤 HTTP_PROXY·HTTPS_PROXY·ALL_PROXY와 대소문자 변수의 값을 확인합니다.
  5. 특정 도구만 실패한다면 Git·npm·pip·편집기 또는 빌드 도구 자체의 설정 출처를 확인합니다.
  6. 도메인은 실패하지만 프록시 측 조회가 성공한다면 시스템 DNS, fake-ip 트래픽의 코어 회귀와 앱 사용자 지정 DNS를 점검합니다.
  7. TUN에서만 성공한다면 대상 프로그램이 원래 시스템 프록시를 지원했는지 확인하고 터미널·컨테이너 또는 원격 환경의 네트워크 경계를 점검합니다.

대표적인 결과는 다음과 같습니다. Clash의 Mixed Port는 실제로 7897이고, 브라우저는 클라이언트가 방금 기록한 시스템 프록시를 읽어 정상적으로 접속합니다. 반면 터미널의 HTTPS_PROXY는 여전히 127.0.0.1:7890을 가리키고 Git 사용자 설정에도 같은 이전 포트가 저장되어 있습니다. 먼저 터미널 변수를 7897로 바꾸고, Git의 재정의 항목을 삭제하거나 업데이트한 다음, 명시적 프록시 요청과 일반 Git 요청을 각각 다시 테스트해야 합니다. 이 과정에서 Rule·Global·TUN을 반복해서 전환할 필요는 없습니다.

또 다른 흔한 결과는 HTTP 프록시 테스트는 실패하지만 socks5h://127.0.0.1:7891은 성공하는 경우입니다. 이때는 먼저 HTTP 포트가 실제로 존재하는지 확인하고 SOCKS5 포트를 HTTP 포트로 사용하지 마세요. 일반 SOCKS5는 실패하고 socks5h만 성공한다면 로컬 DNS 문제를 계속 처리해야 합니다. 이처럼 계층별로 비교하면 “Clash가 작동하지 않는다”는 문제를 포트·앱 설정·DNS 조회 또는 규칙 문제로 구체화할 수 있습니다.

Clash 다운로드플랫폼별 클라이언트 선택