WSL2에서 Windows Clash 쓰기: 미러 네트워크와 포트 포워딩
Edge는 Clash로 잘 나가는데 WSL2 셸의 apt·git·Docker 빌드만 멈춘다면 인터넷이 두 개 생긴 것이 아니라, Windows와 리눅스 게스트가 localhost의 의미와 호스트 HTTP/SOCKS 리스너에 닿는 주소를 다르게 보고 있는 것입니다. 이 글에서는 NAT와 미러형 네트워킹을 구분하고, Ubuntu가 호스트 IP 또는 루프백 중 무엇을 써야 하는지 정한 뒤, 필요하면 mixed-port를 열고 프록시 환경 변수를 도구별로 맞추고, 그래도 안 되면 Windows 포트 포워딩을 쓰는 순서로 정리합니다.
Windows는 되는데 WSL2만 안 되는 이유
Windows에서 Clash는 보통 mixed 포트로 로컬 HTTP·SOCKS를 열고, 브라우저와 많은 Win32 앱은 시스템 프록시를 따라 Clash로 붙습니다. 반면 WSL2 안의 Ubuntu는 별도의 가상 네트워크에 있으며, 127.0.0.1은 리눅스 게스트의 루프백일 뿐 Windows에서 Clash가 듣는 루프백과 자동으로 이어지지 않습니다. 그래서 “Edge는 되는데 apt·git·Docker만 멈춘다”는 패턴이 반복됩니다.
원인은 구독이나 노드 품질이 아니라 주소·바인딩·환경 변수 층입니다. Windows 앱이 127.0.0.1:7890에 붙는 것과, WSL2가 같은 표기를 썼을 때 실제로 도달하는 곳이 다릅니다. 미러형 네트워킹이나 포트 포워딩으로 이 간극을 메우거나, 게스트에서 호스트 측 IP를 찾아 mixed 포트로 TCP가 실제로 열리게 만든 뒤 HTTP_PROXY 등을 맞추면 대부분 정리됩니다.
Clash 대시보드가 브라우저에서 열린다고 해서 mixed 포트 번호가 예전과 같다고 가정하지 마세요. 클라이언트마다 HTTP·SOCKS·mixed 표기가 다르고 업데이트 후 포트가 바뀌기도 합니다. PowerShell에서 Test-NetConnection 127.0.0.1 -Port …로 Windows 쪽 수신을 먼저 확인한 뒤 WSL2에서 같은 번호로 curl을 시도하면 삽질 시간이 크게 줄어듭니다.
- 잘못된 루프백: NAT 모드에서 WSL2 안의
127.0.0.1:7890을 Windows Clash로 착각하는 경우. - 바인딩 범위: Clash가 Windows에서
127.0.0.1에만 바인딩되어 가상 스위치 쪽에서 SYN이 닿지 않는 경우. - 환경 변수 누락: GUI는 시스템 프록시를 쓰는데 셸에는
HTTP_PROXY가 없는 경우. - DNS·fake-ip: 경로는 살아 있는데 이름만 이상하게 풀리는 경우는 DNS·fake-ip 가이드를 TCP 연결이 확인된 다음에 보세요.
NAT WSL2와 미러형 네트워킹
기본 WSL2는 가벼운 NAT 구조입니다. 게스트는 사설 주소를 받고 Windows가 라우터 역할을 합니다. 이 레이아웃에서는 호스트 측 가상 스위치 IP를 게스트가 알아야 Clash mixed 포트로 TCP를 열 수 있습니다. 예전에는 /etc/resolv.conf의 nameserver가 호스트를 가리키는 경우가 많았지만, 빌드·정책마다 달라질 수 있으므로 휴리스틱으로만 두고, ip -4 route show default의 게이트웨이 등으로 교차 검증하는 편이 안전합니다.
Windows 11의 새로운 미러형 네트워킹(%UserProfile%\.wslconfig의 networkingMode=mirrored)은 게스트와 호스트의 주소·포트 관점을 맞추려는 모드입니다. 조건만 맞으면 127.0.0.1이 Windows 쪽 리스너와 의미 있게 연결되어, 호스트 IP를 매번 찾는 수고를 줄일 수 있습니다. wsl --shutdown 후 다시 열고 curl로 반드시 검증하세요. 회사 정책으로 옵션을 막았다면 NAT 절차로 돌아가면 됩니다.
회사 노트북에서는 Zero Trust 클라이언트가 자체 가상 어댑터를 끼워 넣어 WSL2와 Clash TUN의 우선순위가 꼬이기도 합니다. 이때 증상은 WSL2 설정이 틀린 것처럼 보이지만 실제로는 Windows 쪽 기본 경로가 바뀐 경우가 많습니다. TUN을 잠시 끄고 HTTP 프록시만으로 WSL2 연결을 먼저 증명한 뒤, 정책이 허용하는 범위에서 다시 TUN을 켜는 순서가 디버깅에 유리합니다.
또한 WSL2 배포판을 여러 개 쓰면 배포판마다 /etc/resolv.conf 정책이 다를 수 있습니다. 하나(Ubuntu 22.04)에서는 호스트 DNS가 잘 보이는데 다른 하나(미리보기 빌드)에서는 자동 생성 파일이 달라져 스크립트가 깨질 수 있으므로, “내 머신에서 검증한 한 줄짜리 주소 추출 명령”을 팀 위키에 남기기보다 라우팅·연결 테스트 결과를 기준으로 문서화하는 편이 장기적으로 안전합니다. 같은 이유로 Windows 쪽에서 VPN을 켜고 끌 때마다 WSL2 게이트웨이가 바뀌는지도 짧은 스크립트로 한 번씩 확인해 두면 밤샘 디버깅을 줄일 수 있습니다.
한 가지 모델만 고르고 검증
2019년 NAT 글과 2026년 미러 모드 설명을 섞지 말고, 127.0.0.1과 실제 호스트 IP에 각각 curl을 걸어 “지금 빌드에서 살아 있는 주소”를 하나 정해 두세요.
Windows Clash: mixed 포트·바인딩·allow-lan
게스트가 붙으려면 Windows에서 포트가 도달 가능한 인터페이스에서 열려 있어야 합니다. 루프백 전용 바인딩은 Edge에는 충분하지만 WSL2에는 부족합니다. 프로필이나 GUI에서 mixed-port(또는 분리된 port·socks-port)와 allow-lan을 확인하세요. 휴대폰이 같은 Wi‑Fi에서 PC 프록시를 쓰는 경우와 동일한 계열이라 LAN mixed-port 가이드와 결이 같습니다.
Windows Defender 방화벽에서 첫 실행 시 “차단”을 눌렀다면 루프백만 열리고 WSL2 쪽은 조용히 실패할 수 있습니다. 실제 실행 중인 Clash 바이너리에 맞는 인바운드 규칙을 다시 확인하세요. Windows 설치·구독·TUN 기준선은 Clash for Windows 설치 글에서 잡은 뒤 이 글은 WSL2 경계만 다루면 됩니다.
보안
mixed 포트를 루프백 밖으로 넓히면 같은 LAN에서도 접근 가능해집니다. 카페 등 불신 네트워크에서는 방화벽으로 출처를 제한하거나 디버깅 후 바인딩을 좁히세요.
Ubuntu에서 호스트까지: 실제로 통하는 주소
TCP가 먼저입니다. 프록시를 통한 HTTPS보다 호스트 IP(또는 미러 모드의 127.0.0.1)와 mixed 포트에 대한 curl -I --max-time 5로 응답이 오는지 확인하세요. SYN이 안 가면 방화벽·바인딩 문제이고, 연결은 되는데 TLS만 실패하면 스킴·규칙 쪽을 봅니다.
# 미러 모드에서 루프백이 Windows 리스너와 연결될 때
curl -I --max-time 5 http://127.0.0.1:7890
# NAT에서는 게스트 기준 호스트 IP를 넣기
curl -I --max-time 5 http://<HOST_IP>:7890
동작하는 조합을 찾으면 ~/.bashrc 등에 변수로 고정하세요. 예시는 아래 환경 변수 절과 같습니다. 사내 레지스트리·내부 Git은 NO_PROXY에 넣어 불필요한 상용 출구 경유를 막습니다.
IPv6만 있는 엔드포인트를 쓰는 팀이라면 게스트와 Windows의 IPv6 경로가 프록시 밖으로 다른 인터페이스를 탈 수 있습니다. curl -4와 curl -6를 나란히 시험해 보고, Clash 프로필의 IPv6 스위치와 Windows의 IPv6 접두사를 한 번에 바꾸지 말고 한 변수씩 줄여 가세요. “가끔만 실패한다”는 패턴은 종종 듀얼 스택과 타임아웃의 조합입니다.
프록시 환경 변수: 셸·apt·git·도구별 차이
export HTTP_PROXY=…만 하고 sudo apt가 실패하면, sudo가 환경을 비우기 때문일 수 있습니다. sudo -E를 쓰거나 /etc/apt/apt.conf.d/에 Acquire::http::Proxy를 두세요. systemd 사용자 유닛·cron은 대화형 셸을 안 타므로 유닛 파일에 Environment=를 넣거나 스크립트 상단에서 source하세요.
export HOST_IP=<동작하는_호스트_IP>
export HTTP_PROXY="http://${HOST_IP}:7890"
export HTTPS_PROXY="http://${HOST_IP}:7890"
export ALL_PROXY="socks5://${HOST_IP}:7891"
export NO_PROXY="localhost,127.0.0.1,::1"
export http_proxy="$HTTP_PROXY"
export https_proxy="$HTTPS_PROXY"
git config --global http.proxy로 HTTP 프록시를 따로 줄 수 있고, npm·pip·Go 모듈 등은 각 문서의 프록시 규칙을 한 번씩 확인하는 것이 좋습니다. 같은 호스트 주소를 모든 스택이 쓰게 맞추는 것이 핵심입니다.
| 도구 | 설정 | 흔한 실수 |
|---|---|---|
| curl / wget | HTTP_PROXY, HTTPS_PROXY |
NAT에서 게스트 127.0.0.1 사용 |
| apt | 소문자 env 또는 apt.conf | sudo로 env 소실 |
| git | http.proxy |
SSH 리모트는 HTTP 프록시 무관 |
| npm 등 | 레지스트리 설정·env | SSL 검사·사내 CA |
Windows netsh 포트 포워딩은 언제 쓰나
방화벽·VPN 필터·하이퍼바이저 조합 때문에 게스트에서 호스트 mixed 포트로 직접 TCP가 안 될 때, netsh interface portproxy로 Windows가 0.0.0.0:외부포트에서 받아 127.0.0.1:Clash포트로 넘기는 우회가 도움이 됩니다. 관리자 PowerShell에서 규칙을 추가하고 방화벽 인바운드를 맞춘 뒤, WSL2에서는 HOST_IP:외부포트로 테스트하세요. netsh interface portproxy show all로 남은 매핑을 주기적으로 정리하세요.
Docker Desktop과 WSL2 내부 Docker
Docker Desktop(WSL2 백엔드)은 엔진이 대화형 셸의 export를 자동으로 물려주지 않을 수 있습니다. 설정 JSON의 데몬 프록시로 이미지 풀을 맞추고, docker build에는 BuildKit용 --build-arg HTTP_PROXY=… 패턴을 쓰세요. Docker CE만 WSL2에 깔아 쓰는 경우에도 데몬 설정과 CLI 환경을 구분해 생각해야 합니다. 큰 객체 전송이 프록시 이후에도 끊기면 MTU도 한 번 비교해 보세요.
Windows TUN과 “전부 프록시”의 한계
TUN은 Win32 트래픽을 잘 가로채도, WSL2 패킷이 항상 같은 경로로 간다는 뜻은 아닙니다. TUN을 켠 뒤에도 리눅스 셸에 명시적 프록시가 필요할 수 있습니다. 반대로 TUN이 사내 스플릿 터널과 싸우면 WSL2 쪽 애플리케이션 프록시만 쓰는 편이 안정적일 때도 있습니다. 로그에서 게스트 출발 흐름이 Clash에 잡히는지부터 확인하세요.
WSL2 DNS와 Windows Clash
이름 해석이 Windows DNS 스텁을 타는지, Clash DNS·fake-ip와 맞는지에 따라 “브라우저만 된다”와 비슷한 증상이 납니다. TCP로 프록시 포트는 열리는데 dig만 이상하면 리졸버 경로를 분리해 보고, fake-ip를 쓰는 프로필이면 DNS 글과 설정을 같이 맞추세요.
증상별로 좁히기
| 증상 | 먼저 의심 | 빠른 확인 |
|---|---|---|
| WSL2에서 프록시 포트로 타임아웃 | 루프백 전용 바인딩·방화벽 | allow-lan·바인딩 조정 후 nc -vz HOST PORT |
| TCP는 되는데 HTTPS 프록시만 실패 | HTTP vs SOCKS 스킴·규칙 | curl -v -x http://HOST:PORT https://example.com |
| 대화형 셸만 됨 | 비대화형 환경에 env 없음 | 스크립트 상단에서 프록시 파일 source |
| 절전 후 깨짐 | 호스트 IP·가상 어댑터 stale | wsl --shutdown 후 주소 재확인 |
로그를 남길 때는 export 한 줄·ip route 출력·Clash 리스너 목록·한 번의 curl -v만 있어도 원인 층을 가르기 쉽습니다.
팀 단위로 WSL2 이미지를 배포한다면, 베이스 이미지에 NO_PROXY에 사내망 접두사를 미리 넣고 상용 출구만 필요한 호스트만 프록시로내도록 문서화해 두면 신입 온보딩 시 “브라우저만 된다”는 문의가 줄어듭니다. 반대로 개인 노트북 한 대만 다룰 때는 과도한 전역 프록시보다 proxy_on 같은 셸 별칭으로 켜고 끄는 편이 덜 위험합니다.
실무 체크리스트
- Windows 브라우저·Clash mixed 포트가 정상인지 확인.
- NAT vs 미러 모드를 정하고
.wslconfig변경 시wsl --shutdown. - Ubuntu에서
127.0.0.1과 호스트 IP로curl매트릭스. - 필요 시 allow-lan·바인딩·방화벽 정리.
HTTP_PROXY·HTTPS_PROXY·ALL_PROXY·NO_PROXY정렬, apt·git·Docker는 별도 설정.- 직접 접근이 막히면
netsh portproxy검토. - 라우팅이 살아도 이름만 이상하면 DNS·fake-ip 재점검.
한 번 통과한 조합(미러 여부·주소 형태·포트·portproxy 사용 여부)을 짧게 메모해 두면 다음 Windows 기능 업데이트 이후에도 같은 자리에서 다시 시작할 수 있습니다.
FAQ
WSL2 안에서 127.0.0.1 써도 되나요?
미러형 네트워킹 등으로 루프백이 실제로 Windows 리스너와 이어지고 curl로 검증된 경우에만 안심하고 쓰세요. 그렇지 않으면 라우팅 테이블·리졸버에서 얻은 호스트 IP를 씁니다.
curl은 빠른데 apt만 느리다
sudo 환경·apt 전용 프록시 설정·미러 지리(출구 ASN)를 의심하세요.
Windows 업데이트 후 깨졌다
curl 매트릭스를 다시 돌리고, 방화벽 규칙·WSL 플래그·portproxy 항목이 초기화됐는지 확인하세요.
Windows와 WSL2를 같은 그림으로
리스너 하나·규칙 한 벌·로그가 읽히게 유지하면 서브시스템마다 다른 비밀 설정을 들고 살 필요가 없습니다. WSL2가 그 리스너에 안정적으로 닿으면 터미널과 컨테이너도 “다른 인터넷”처럼 느껴지지 않습니다.
프록시 하나, 커널 둘
미러 또는 NAT, mixed-port, 환경 변수, 필요할 때만 포트 포워딩으로 WSL2를 Windows Clash 리스너에 맞춥니다.
Clash 다운로드