증상: «윈도우 브라우저는 되는데 WSL만 안 된다»
Edge나 Chrome에서는 해외 사이트가 열리는데, 같은 PC의 Ubuntu·Debian 계열 WSL에서 curl https://example.com만 타임아웃에 가깝다면, 노드 품질 문제보다 먼저 «트래픽이 Clash를 안 지나간다»는 가설을 두는 편이 빠릅니다. 특히 git clone https://github.com/...처럼 HTTPS를 쓰는 도구는 OS의 «시스템 프록시」와 무관하게 동작하는 경우가 많아, 셸에 프록시 환경 변수가 비어 있으면 곧바로 직접 연결을 시도합니다.
apt도 마찬가지입니다. /etc/apt/apt.conf 계열에 Acquire::http::Proxy가 없고 환경 변수도 없으면, 저장소 미러로 나가는 HTTP(S) 요청이 프록시를 우회합니다. 회사망·지역 회선에서 특정 대역만 막히는 환경이라면 «브라우저만 Clash를 탄다»는 패턴이 반복됩니다.
1단계: Windows Clash에서 포트·Allow LAN 확인
WSL 가상 NIC에서 윈도우의 프록시 데몬에 붙으려면, Clash가 127.0.0.1에만 묶여 있어도 대부분의 설정에서 WSL 측 «호스트 IP»로 접근 가능합니다. 다만 일부 빌드에서는 Allow LAN(또는 동등한 «LAN 허용» 옵션)을 켜야 가상 스위치 대역에서 들어오는 연결이 받아들여집니다. 방화벽 팝업이 뜨면 «개인 네트워크»에서 허용했는지도 함께 확인하세요.
기본적으로 많은 프로필이 HTTP 프록시를 7890, SOCKS5를 7891처럼 나누거나, mixed-port 하나로 묶습니다. 아래 예시에서는 HTTP를 7890, SOCKS를 7891로 두었다고 가정합니다. 실제 숫자는 반드시 자신의 설정에 맞추어 바꾸십시오.
윈도우 PowerShell에서 netstat -ano | findstr 7890처럼 LISTEN 상태가 보이면, 최소한 로컬 바인딩은 살아 있는 것입니다. TUN 모드와 병행할 때의 동작 차이는 TUN·시스템 프록시 트러블슈팅에서 다룬 순서대로 점검하면 WSL과 겹치는 증상도 줄일 수 있습니다.
2단계: WSL2가 바라봐야 할 주소 — 미러형 네트워킹 vs 기본 NAT
미러형 네트워킹(mirrored networking)을 쓰는 경우
Windows 11 최신 채널과 WSL 2.0.x 계열에서는 .wslconfig에 networkingMode=mirrored를 주면, WSL 내부의 127.0.0.1이 Windows의 루프백과 의미상 맞물리는 동작을 기대할 수 있습니다. 이 모드가 켜져 있으면 프록시 주소를 http://127.0.0.1:7890처럼 짧게 잡는 방식이 가장 단순합니다. 설정 후 wsl --shutdown으로 완전히 내렸다가 다시 올리는 것을 잊지 마세요.
기본 NAT(미러 미사용)인 경우
전통적인 WSL2에서는 컨테이너와 Windows 호스트가 서로 다른 네트워크 네임스페이스에 있어, WSL 안의 127.0.0.1은 «그 Ubuntu 자기 자신»입니다. 이때는 Windows 쪽 Clash가 열어 둔 포트에 도달하려면 호스트의 브리지 IP를 써야 합니다. 과거에는 /etc/resolv.conf의 nameserver(예: 172.x.x.1)가 호스트를 가리키는 경우가 많았고, 지금도 배포판·WSL 버전에 따라 ip route show default의 게이트웨이, 또는 $(hostname).local 계열이 안내됩니다.
실무에서는 한 번 찾아 둔 IP를 셸 프로필에 변수로 박아 두되, VPN·하이퍼바이저 업데이트 뒤에 바뀔 수 있으므로, 스크립트로 게이트웨이를 읽어 export하는 패턴도 자주 씁니다. 핵심은 «지금 이 세션에서 실제로 열리는지 curl로 확인한다»는 점입니다.
# Replace PORT with your Clash mixed or HTTP port curl -x http://127.0.0.1:PORT -I https://www.google.com
미러 모드가 아닐 때는 위의 127.0.0.1을 호스트 IP로 바꿔 같은 명령을 실행해 보세요. 연결이 거절되면 포트·Allow LAN·방화벽 순으로 다시 올라갑니다.
3단계: http_proxy·HTTPS_PROXY·ALL_PROXY·no_proxy 정리
대부분의 CLI 도구는 소문자 http_proxy와 대문자 HTTP_PROXY를 모두 읽는 구현이 있지만, 혼용을 피하려면 둘 다 같은 값으로 맞추는 편이 안전합니다. HTTPS 트래픽은 환경 변수 이름이 https_proxy인데, 값은 여전히 http://호스트:포트 형태인 경우가 일반적입니다(프록시 자체가 HTTP CONNECT를 제공). SOCKS만 쓸 때는 socks5h://...처럼 DNS까지 프록시 쪽에서 하게 하려면 스킴을 socks5h로 두는 것이 흔합니다.
ALL_PROXY는 한 번에 기본 아웃바운드를 잡고 싶을 때 쓰지만, 도구마다 해석이 조금씩 다릅니다. Git은 http.proxy 설정이 더 예측 가능한 경우가 많습니다. no_proxy에는 사내망·레지스트리 미러·로컬 레포지토리 호스트를 넣어 불필요한 홉을 줄입니다.
export http_proxy=http://127.0.0.1:7890 export https_proxy=http://127.0.0.1:7890 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,10.0.0.0/8,192.168.0.0/16
위 블록은 예시이며, 미러 네트워크가 아닐 때는 127.0.0.1 대신 앞 단계에서 확인한 호스트 IP로 바꿉니다. ~/.bashrc나 ~/.zshrc에 넣기 전에, 우선 한 세션에서만 export 해서 apt와 git이 기대대로 동작하는지 검증하는 것을 권장합니다.
4단계: apt 전용 설정(Acquire::http::Proxy)
일부 환경에서는 sudo apt가 루트 셸을 열면서 사용자의 환경 변수를 비우기 때문에, /etc/apt/apt.conf.d/ 아래에 프록시를 박아 두는 방식이 더 안정적입니다. 파일 이름은 예를 들어 95proxies처럼 임의로 정해도 됩니다.
Acquire::http::Proxy "http://127.0.0.1:7890"; Acquire::https::Proxy "http://127.0.0.1:7890";
여기서도 미러 모드가 아니면 주소를 호스트 IP로 교체합니다. 설정 후 sudo apt update 로그에 미러 연결이 프록시를 경유하는지, 혹은 여전히 직접 대역으로 나가는지 확인하세요. 회사 프록시와 이중으로 걸리면 인증 오류가 날 수 있으므로, 그 경우에는 Acquire::http::Proxy를 비우고 상위 프록시만 쓰는 쪽이 맞는지 네트워크 정책과 맞춰야 합니다.
5단계: Git http.proxy·https.proxy
Git은 환경 변수만으로도 동작하지만, 저장소마다 다르게 두고 싶다면 git config --global이 디버깅에 유리합니다. HTTPS 클론에는 http.proxy 키 이름을 쓰는 점에 익숙해지면 혼란이 줄어듭니다.
git config --global http.proxy http://127.0.0.1:7890 git config --global https.proxy http://127.0.0.1:7890
특정 호스트만 프록시를 태우려면 URL 섹션을 쓰는 방법도 있습니다. 사내 Git은 no_proxy와 함께 DIRECT로 두고, GitHub만 위 프록시로내면 일상적으로 속도와 안정성의 균형이 좋아집니다. 개발용으로 npm·Cursor 등 더 넓은 분기를 Clash 규칙으로 묶는 패턴은 Cursor·npm 개발자 분기 가이드와 짝을 이룹니다.
6단계: 빠른 검증과 흔한 실수
설정을 바꾼 뒤에는 반드시 (1) curl -x로 프록시 경로를 확인하고, (2) git ls-remote https://github.com/...처럼 가벼운 읽기 명령으로 Git을 시험하고, (3) sudo apt update 한 번으로 패키지 인덱스가 갱신되는지 봅니다. 세 단계 중 하나만 실패해도 원인 범위가 좁혀집니다 — 예를 들어 curl만 되고 apt만 안 되면 루트 환경의 프록시 누락을 의심합니다.
Windows Defender 방화벽이 WSL vSwitch 대역을 차단한 사례, Clash가 재시작되며 포트가 바뀐 사례, VPN이 별도 어댑터를 끼워 넣으며 호스트 라우팅이 바뀐 사례도 흔합니다. 증상이 날마다 바뀌면 «IP를 하드코딩한 셸 프로필」보다 부팅 시 게이트웨이를 읽는 스크립트가 더 오래 갑니다.
.wslconfig 예시(미러형 네트워킹)
사용자 프로필 폴더의 .wslconfig는 WSL 전역에 적용됩니다. 아래는 개념을 보여 주는 최소 예시이며, 이미 다른 키가 있다면 병합해야 합니다.
[wsl2]
networkingMode=mirrored
dnsTunneling=true
autoProxy=true
autoProxy는 Windows 쪽 «프록시 설정»을 WSL에 전달하려는 실험적 기능으로, 빌드에 따라 체감이 다를 수 있습니다. 어쨌든 CLI 도구는 여전히 자체 규칙을 가질 수 있으므로, 본 글에서 다룬 apt·git 명시 설정은 병행하는 편이 안전합니다.
마무리
WSL2와 Windows Clash를 함께 쓸 때 핵심은 두 가지입니다. 첫째, 셸과 패키지 매니저가 참조하는 주소가 실제로 윈도우의 localhost 프록시 포트에 닿는지(미러 네트워크 여부에 따라 127.0.0.1 또는 호스트 IP)를 맞출 것. 둘째, 브라우저에만 의존하지 않고 http_proxy 계열·apt Acquire·git proxy를 같은 값으로 정리할 것입니다. 이 두 축이 맞으면 «윈도우만 되고 리눅스는 안 된다»는 불균형이 대부분 사라집니다.
장기적으로는 미러형 네트워킹을 켤 수 있는 환경이라면 루프백 기준으로 설정을 단순화하고, 그렇지 않다면 호스트 IP를 주기적으로 검증하는 습관을 들이는 쪽이 운영 부담이 적습니다. GUI 클라이언트마다 포트 표기는 다르지만, 한 번 숫자와 Allow LAN만 확인해 두면 이후 트러블슈팅이 빨라집니다.