시나리오: 왜 WSL2에서는 Windows Clash를 붙이는가

WSL2 위의 Ubuntu는 경량 VM에 가까운 별도 네트워크 스택을 씁니다. 그래서 “같은 키보드 위의 두 OS”처럼 보여도, 루프백(127.0.0.1)의 의미가 Windows와 1:1로 겹치지 않을 때가 많습니다. 반대로 Windows 데스크톱에서 이미 GUI Clash 클라이언트를 돌리며 구독·규칙을 맞춰 두었다면, WSL2 안에 코어를 한 벌 더 깔아 systemd 서비스까지 올리는 것보다, mixed-port 한 줄만 공유하는 편이 업데이트 부담이 적습니다.

이 문서는 본인이 관리하는 PC에서, 법령·회사 정책·서비스 약관을 지키는 범위의 개발·학습용 네트워크 절차를 전제로 합니다. 원격 사무실 장비나 타인의 네트워크에 동일한 방식을 적용하지 마세요.

1단계: Windows Clash의 mixed-port와 리스닝 주소

대부분의 Clash 계열 클라이언트는 YAML에서 mixed-port(또는 별도 port·socks-port)를 엽니다. 여기서 중요한 것은 숫자가 아니라 바인드 주소입니다. 127.0.0.1에만 열려 있으면 Windows 프로세스끼리는 잘 붙지만, WSL2 가상 NIC에서 오는 연결은 “다른 인터페이스에서 온 트래픽”으로 취급될 수 있어 연결 거부가 납니다. 실무에서는 ① Clash 설정에서 bind-address: '*' 또는 0.0.0.0에 해당하는 옵션을 켜거나, ② GUI의 “LAN 허용(allow-lan)” 계열 스위치를 켜서 모든 인터페이스에서 mixed-port를 듣게 만드는 패턴이 흔합니다. 개념 정리는 LAN 프록시·방화벽 글과 같은 맥락입니다.

Windows 쪽에서 실제로 어떤 주소에 포트가 열렸는지 확인하려면 관리자 PowerShell에서 netstat -ano | findstr :포트번호처럼 확인하거나, 작업 관리자·리소스 모니터의 네트워크 탭을 병행하세요. mixed-port가 7890이라면 WSL2에서 나중에 쓸 프록시 URL도 그 숫자에 맞춥니다.

Clash for Windows·Verge 등 클라이언트별 화면 이름은 다르지만, “시스템 프록시 켜기”와 “포트가 모든 어댑터에서 열리는지”는 별개입니다. 시스템 프록시는 주로 Windows 앱용이고, WSL2의 curl은 기본적으로 그 설정을 자동으로 물지 않습니다. 그래서 아래 단계의 프록시 환경 변수가 필요합니다. Windows 설치 전반은 Clash for Windows 튜토리얼에서 먼저 정리해 두면 속도가 납니다.

2단계: WSL2에서 Windows 호스트 IP 잡기

과거 블로그에서는 cat /etc/resolv.conf에 적힌 nameserver 한 줄을 Windows 호스트 IP로 쓰는 방법이 널리 쓰였습니다. 최신 WSL(예: mirrored networking·자동 업데이트된 resolv)에서는 127.0.0.1이나 예약 대역이 보일 수도 있으니, 배포판·커널·.wslconfig 조합마다 값이 달라질 수 있다는 점만 기억하세요. 핵심은 “WSL2가 Windows 쪽 TCP 포트에 도달할 수 있는 단일 IPv4 주소”를 하나 정해 두고, 모든 프록시 URL에 동일하게 쓰는 것입니다.

$(hostname).local 같은 mDNS 이름은 환경에 따라 해석이 불안정할 수 있습니다. 스크립트에 박아 두기보다, 한 번 확인한 숫자 IP를 셸 프로파일(~/.bashrc 등)에 export WINDOWS_HOST=... 형태로 고정해 두면 팀원과 공유할 때도 설명이 쉽습니다. 회사 보안 제품이 가상 어댑터를 여러 개 깔아 두었다면, 잘못된 IP를 집으면 증상이 “프록시 타기 전에 타임아웃”으로만 보이니 순서를 바꿔 가며 재확인하세요.

3단계: HTTP(S)_PROXY, ALL_PROXY, no_proxy

대부분의 CLI는 대소문자 섞인 환경 변수를 동시에 봅니다. 실무에서 자주 쓰는 조합은 다음과 같습니다. http://호스트:포트socks5h://호스트:포트를 나란히 두면, HTTP 계열과 SOCKS 계열을 동시에 만족시키기 쉽습니다. mixed-port는 한 리스너에서 두 프로토콜을 함께 받는 경우가 많으므로, 클라이언트가 허용하는 스킴을 확인한 뒤 맞춥니다.

# Example: replace HOST and PORT with your Windows host IP and Clash mixed-port
export HTTP_PROXY="http://HOST:PORT"
export HTTPS_PROXY="http://HOST:PORT"
export ALL_PROXY="socks5h://HOST:PORT"
export NO_PROXY="localhost,127.0.0.1,::1"

no_proxy(또는 NO_PROXY)는 내부 Git 서버·사설 레지스트리·회사 VPN 대역을 직접 붙여야 할 때 필수입니다. 범위를 너무 넓히면 “왜 이 도메인만 분류 규칙을 안 타지?” 하는 혼란이 생기고, 너무 좁히면 사설 호스트까지 불필요하게 프록시로 나가며 인증 오류가 납니다. 쉼표로 나열하는 형식이 일반적이며, 최상위 도메인 단위 서픽스는 도구마다 해석이 조금씩 다르니 문제가 생기면 해당 CLI 문서를 한 번 더 확인하세요.

세션마다 수동 export가 귀찮다면 direnv·셸 플러그인으로 프로젝트별로 끄고 켤 수 있습니다. 반대로 전역으로 박아 두었다가 평소 브라우저만 쓸 때 이상 증상이 나면, 우선 해당 터미널에서 unset HTTP_PROXY HTTPS_PROXY ALL_PROXY로 원인 분리를 하세요.

4단계: DNS가 “직행”하면 생기는 함정

HTTP CONNECT 프록시를 써도, 클라이언트가 먼저 로컬 DNS로 이름을 풀고 나서 IP로 연결하는 구조라면, Clash의 fake-ip·도메인 기반 규칙과 엇박자가 날 수 있습니다. 증상은 “프록시는 타는 것 같은데 특정 도메인만 NXDOMAIN·타임아웃”, “브라우저(Windows 쪽)는 되는데 WSL2의 curl만 실패”처럼 갈립니다. TUN 모드 가이드에서 설명하는 DNS 스택과 달리, 본 시나리오는 WSL2가 자체 리졸버(systemd-resolved, nsswitch, /etc/resolv.conf)를 유지한다는 점이 변수입니다.

점검 순서는 단순합니다. ① WSL2에서 dig +trace 또는 resolvectl query(환경에 따라 패키지 필요)로 질의가 어디로 나가는지 본 뒤, ② Windows Clash의 DNS 설정이 “로컬에서 받아서 업스트림으로 넘긴다”인지 “코어 안에서만 처리한다”인지 구분합니다. ③ 필요하면 WSL2의 /etc/wsl.conf나 Windows 측 WSL DNS 옵션을 조정해, 의도한 리졸버만 쓰게 맞춥니다. 여기서 잘못 손대면 사내 필수 도메인까지 깨질 수 있으니, 변경 전 백업과 롤백 경로를 남기세요.

SOCKS5h처럼 “호스트 이름을 프록시에 넘기는” 모드를 지원하면 DNS를 로컬에서 먼저 풀지 않아 규칙 정합이 좋아지는 경우가 있습니다. 반대로 앱이 IPv6만 우선한다면 Windows와 WSL2 양쪽에서 이중 스택 설정이 어긋나 간헐적 실패가 나기도 하므로, 문제가 반복되면 IPv4 고정으로 한 번 좁혀 보는 것이 진단에 유리합니다.

5단계: curl, apt, git로 한 줄씩 검증

가장 먼저 curl -I로 대표 HTTPS 사이트에 대한 응답 헤더만 받아 보세요. 여기서 TLS 핸드셰이크까지 성공하면 프록시 경로와 방화벽은 대체로 통과한 것입니다. -v를 붙이면 실제로 어떤 프록시에 붙었는지 로그가 남습니다. 실패 시 Windows 방화벽의 “개인 네트워크” 프로필, 보안 제품의 루프백 격리, 그리고 앞 절의 바인드 주소를 다시 의심합니다.

curl -I --max-time 15 https://example.com

apt는 환경 변수를 항상 동일하게 읽지 않습니다. /etc/apt/apt.conf.d/ 아래에 Acquire::http::Proxy "http://HOST:PORT"; 형식을 쓰는 방법과, sudo -E로 환경 변수를 유지하는 방법이 공존합니다. 회사 정책상 프록시 인증이 필요하면 apt 쪽은 별도 예외가 필요할 수 있어, 보안 가이드를 먼저 확인하세요.

gitgit config --global http.proxy와 환경 변수가 동시에 있을 때 어느 쪽이 우선하는지 헷갈리기 쉽습니다. HTTPS 저장소와 SSH 저장소는 경로가 완전히 다르니, “브라우저 다운로드는 되는데 git clone만 안 된다”면 프로토콜부터 분리해 보세요. SSH는 프록시 환경 변수와 무관하게 ~/.ssh/config의 ProxyCommand를 써야 하는 경우가 많습니다.

6단계: Windows 방화벽과 allow-lan 재확인

설정을 모두 맞춰도 첫 연결에서만 막히는 경우는 대개 Windows Defender 방화벽이 mixed-port에 대한 인바운드를 차단하는 경우입니다. 개발자용 PC라면 “앱/포트 허용” 규칙을 Clash 실행 파일 또는 해당 포트에 추가해야 합니다. 공용 와이파이에서는 보안 정책상 인바운드 허용 자체가 금지될 수도 있으니, 그런 환경에서는 로컬 테스트만 하세요.

allow-lan을 켰다는 사실과 실제 Windows 네트워크 프로필이 “공용”으로 잡혀 있어 룰이 달라지는 문제를 혼동하기 쉽습니다. 방화벽 화면에서 프로필별 허용 목록을 한 번씩 훑는 것만으로도 미스매치가 줄어듭니다.

정리

WSL2Ubuntu에서 CLI 도구를 Windows Clash로 모으려면, 숫자 포트 하나를 공유한다고 끝나지 않고 “누가 어떤 주소에서 듣고 있느냐”가 먼저입니다. mixed-port를 모든 인터페이스에서 열고, WSL2가 붙을 호스트 IP를 안정적으로 잡은 다음, HTTP_PROXY·HTTPS_PROXY·ALL_PROXYno_proxy를 한 세트로 맞춥니다. 그 다음에도 증상이 남으면 DNS가 프록시 바깥에서 먼저 결정되는지 의심하고, curl·apt·git을 나눠 보면 원인이 빨리 갈립니다. 네이티브 리눅스에 코어를 올리는 장단점 비교는 문서 허브의 키워드로 이어서 찾아보시면 전체 그림이 맞습니다.

같은 구독을 쓰더라도, GUI 클라이언트가 규칙·DNS·TUN을 한 번에 묶어 주는 편이라 운영 피로도가 낮은 경우가 많습니다. 특히 여러 터미널 세션을 동시에 쓰는 개발 환경에서는 “Windows 한 벌 + WSL2는 환경 변수만”이 업데이트 충돌을 줄이는 현실적인 타협입니다.

→ Clash 공식 클라이언트 무료 다운로드 — Windows용 빌드를 받아 mixed-port와 LAN 옵션을 먼저 안정화한 뒤 WSL2 쪽 환경 변수를 맞추면, 재현과 롤백이 훨씬 단순해집니다.