WSL2 Mirrored 모드에서 VS Code 접속 안 될 때 해결법

최규민
Claude

최규민, Claude

2026년 2월 28일2 분 소요

WSL2 Mirrored 모드에서 VS Code 접속 안 될 때 해결법
💡
WSL2 Mirrored 네트워킹 모드에서 VS Code가 접속 안 되는 진짜 원인은 2FA도, 방화벽도 아닌 loopback 라우팅 버그였습니다. ip rule 한 줄로 해결합니다.


저는 WSL2에서 networkingMode=mirrored를 사용하고 있습니다. 호스트와 IP를 공유해서 VPN이나 LAN 환경에서 편리하거든요. 그런데 어느 날부터 VS Code로 WSL에 접속하면 로딩 스피너만 무한으로 돌기 시작했습니다.


증상 확인


증상은 단순했습니다. VS Code에서 WSL을 열면 왼쪽 아래 초록색 표시가 "Opening Remote..."에서 멈춥니다. 몇 분 기다려도 안 됩니다.

제가 시도했던 기본적인 것들:

  • wsl --shutdown 후 재시작 → 안 됨
  • VS Code Server 프로세스 강제 종료 → 안 됨
  • ~/.vscode-server/bin/ 캐시 삭제 후 재설치 → 안 됨


다 해봤는데 안 됩니다. 그래서 본격적으로 로그를 까보기로 했습니다.

용의자 제거


2FA는 무죄


제 WSL에는 SSH에 Google Authenticator 2FA가 걸려있습니다. 외부에서 SSH로 접속할 일이 있어서요. 당연히 이게 원인일 거라 생각했는데, VS Code의 Remote - WSL 확장은 SSH를 사용하지 않습니다.


실제로 프로세스를 확인해보면 wslServer.sh 스크립트를 통해 직접 WSL 프로세스를 실행하는 방식입니다. SSH와 PAM 인증은 아무 관계가 없습니다.


Windows 방화벽도 무죄


PowerShell에서 방화벽 규칙을 확인해봤습니다.


plain text
DisplayName        Direction Action Enabled
-----------        --------- ------ -------
Visual Studio Code   Inbound  Allow    True
Visual Studio Code   Inbound  Allow    True
wsl2 ssh            Outbound  Allow    True


VS Code와 WSL 관련 규칙이 전부 Allow입니다. Block 규칙도 없습니다. 방화벽은 깨끗합니다.


로그에서 찾은 단서


VS Code의 renderer 로그(AppData/Roaming/Code/logs/.../renderer.log)를 열어봤습니다.


plain text
03:28:31.359 [info] resolveAuthority(wsl) returned 'WebSocket(127.0.0.1:52298)' after 4952 ms
03:28:31.360 [info] Creating a socket (renderer-Management-...)...
03:30:35.979 [info] Creating a socket (...) returned an error after 124619 ms.
03:30:35.980 [error] CodeExpectedError: WebSocket close with status code 1006


패턴이 보입니다. VS Code Server는 WSL 안에서 정상적으로 시작되고, 포트도 찾습니다. 하지만 그 다음 WebSocket 연결이 124초 후 status code 1006(비정상 종료)으로 죽습니다. 이걸 무한 반복합니다.


서버는 떠있는데 연결이 안 된다? 뭔가 네트워크 레벨에서 막히고 있다는 뜻입니다.


진짜 범인: loopback TCP가 죽어있다


WSL 내부에서 직접 VS Code Server 포트에 연결을 시도해봤습니다.


bash
$ curl -v --max-time 5 http://127.0.0.1:57124/
*   Trying 127.0.0.1:57124...
* Connection timed out after 5000 milliseconds
curl: (28) Connection timed out after 5000 milliseconds

$ nc -z -w 2 127.0.0.1 57124
FAIL


보시면 아시겠지만 절단 났습니다.

WSL 내부에서 자기 자신의 127.0.0.1로 TCP 연결이 안 됩니다.


재미있는 건, ping은 됩니다.


bash
$ ping -c 2 127.0.0.1
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.717 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.043 ms

# 다른 서비스 포트는 잘 됨
$ nc -z -w 2 127.0.0.54 53 && echo OK
OK
$ nc -z -w 2 0.0.0.0 2498 && echo OK
OK

# VS Code Server 포트만 안 됨
$ nc -z -w 2 127.0.0.1 57124
FAIL


ping(ICMP)은 되는데 TCP는 안 된다. 127.0.0.1에 바인딩된 특정 포트들이 TCP로 접근 불가합니다. 이건 networkingMode=mirrored에서 loopback 라우팅이 꼬여있다는 뜻입니다.


원인 분석: 라우팅 테이블의 함정


ip rule show로 라우팅 정책을 확인하면 답이 보입니다.


bash
$ ip rule show
0:  from all iif loopback0 ipproto tcp lookup local
0:  from all iif loopback0 ipproto udp lookup local
1:  from all ipproto tcp lookup 127          # ← 여기가 문제!
1:  from all ipproto udp lookup 127
1:  from all ipproto tcp lookup 128
1:  from all ipproto udp lookup 128
2:  from all lookup local                    # ← 127.0.0.1 → lo는 여기 있음
32766: from all lookup main
32767: from all lookup default


Mirrored 모드에서 WSL은 호스트 네트워크를 미러링하기 위해 loopback0이라는 가상 인터페이스와 별도의 라우팅 테이블(lookup 127, lookup 128)을 만듭니다.


문제는 이겁니다:


  1. 127.0.0.1로 TCP 패킷을 보내면, 우선순위 1인 lookup 127 테이블을 먼저 탐
  2. 이 테이블에서 패킷이 loopback0 가상 인터페이스로 라우팅됨
  3. loopback0에서는 실제 lo 인터페이스에 바인딩된 서비스에 도달하지 못함
  4. 패킷이 폐기(Reset)되면서 연결 타임아웃


즉, 127.0.0.1 트래픽이 진짜 loopback(lo)이 아니라 mirrored 모드의 가상 인터페이스로 빠지면서 사라지는 것입니다. Microsoft의 WSL2 mirrored networking의 알려진 버그입니다.


해결: ip rule 한 줄이면 끝


해결법은 간단했는데요, 127.0.0.0/8 대역의 트래픽을 우선순위 0으로 local 테이블에서 찾도록 강제하는 겁니다.


bash
# 127.0.0.0/8 대역을 로컬 테이블에서 찾도록 우선순위 0으로 설정
sudo ip rule add pref 0 to 127.0.0.0/8 lookup local
sudo ip rule add pref 0 to 127.0.0.0/8 ipproto tcp lookup local

# 라우팅 캐시 플러시
sudo ip route flush cache


이 룰을 추가하면 127.0.0.0/8 트래픽이 mirrored 모드의 lookup 127/128 테이블을 타기 전에 local 테이블에서 먼저 잡힙니다. 즉, lo 인터페이스로 정상적으로 라우팅됩니다.


적용 후 바로 확인:


bash
$ nc -z -w 2 127.0.0.1 57124 && echo OK
Connection to 127.0.0.1 57124 port [tcp/*] succeeded!
OK


됩니다. VS Code WSL 접속도 정상적으로 됩니다.


재부팅해도 유지되게 자동화


이 설정은 WSL 재부팅 시 초기화됩니다. .zshrc(또는 .bashrc)에 추가해서 자동으로 적용되게 합니다.


bash
# Fix WSL2 mirrored mode loopback routing (127.0.0.1 TCP)
if ip rule show 2>/dev/null | grep -q "lookup 127"; then
  sudo -n ip rule add pref 0 to 127.0.0.0/8 lookup local 2>/dev/null
  sudo -n ip rule add pref 0 to 127.0.0.0/8 ipproto tcp lookup local 2>/dev/null
  sudo -n ip route flush cache 2>/dev/null
fi


ip rule show에서 lookup 127이 있을 때만(즉, mirrored 모드일 때만) 실행됩니다. sudo -n은 비밀번호 없이 실행하는 옵션이라, sudoers에 ip 명령어에 대한 NOPASSWD를 추가해야 합니다.


bash
# /etc/sudoers.d/wsl-loopback-fix
yourname ALL=(ALL) NOPASSWD: /usr/sbin/ip


⚠️
ip 명령어 전체에 NOPASSWD를 주는 것이 불안하다면, /usr/sbin/ip rule add *로 범위를 제한할 수도 있습니다.


디버깅 과정 요약


이번 디버깅에서 확인하고 제거한 용의자들을 정리하면:


1. Google 2FA / PAM 인증 → VS Code WSL은 SSH를 안 쓰므로 무관

2. Windows 방화벽 → VS Code, WSL 관련 규칙 모두 Allow. Block 규칙 없음

3. VS Code Server 문제 → 서버는 정상 시작, 포트 리스닝 정상

4. WSL 확장 호환성 (PendingMigrationError) → 에러 발생하지만 resolve는 성공, 비치명적 에러

5. Mirrored 모드 loopback 라우팅진짜 범인!


핵심은 WSL 내부에서 curl 127.0.0.1을 때려본 순간이었습니다. 외부 네트워크나 VS Code 설정이 아니라, WSL 자체의 TCP 루프백 연결이 깨져있다는 걸 알아낸 게 포인트였습니다.


🔗참고 자료



Mirrored 모드를 포기 못하는 분들에게 도움이 됐으면 좋겠습니다. ip rule 한 줄이면 끝입니다!🤗





최규민

최규민

AI Engineer

사파(邪派)식 AI-Native LLM SWE

Claude

Claude

AI Agent

Claude for blog post automation