動かない時
WSL2 でポート転送できない
WSL2 上のコンテナに Windows ブラウザや同じ LAN の他端末から繋がらない問題。Windows ファイアウォール、`localhostForwarding`、`netsh portproxy` の順で切り分けます。
症状
- WSL2 内で
docker run -p 3000:3000したのに、Windows 側の Chrome からhttp://localhost:3000が開かない - 開けるときもあれば開けないときもある(PC スリープ復帰後などで再現しやすい)
- Windows からは
localhostで繋がるが、同じ Wi-Fi 上のスマホや別 PC からは繋がらない http://<Windows の IP>:3000は開かない
原因
WSL2 ネットワークの多段構造が原因です。
パケットは以下を経由します。
- コンテナ(Docker のブリッジネットワーク)
- WSL2 VM(固有の仮想 NIC、動的な IP が割り振られる)
- Windows ホスト
- LAN
典型的な詰まりどころ:
localhostForwardingが無効: Windows 側のlocalhostから WSL2 へ自動転送する仕組み。.wslconfigで無効化されているとそもそも繋がらない- Windows Defender Firewall: WSL2 からの応答を落とす / 他端末からの接続を受信ルールで拒否
- 動的 IP の変動: WSL2 VM の IP は再起動ごとに変わる。固定
netsh portproxyを書いていると PC 再起動後に別 IP を指してしまい無効化される - LAN からの到達:
localhost:3000転送はあくまで Windows→WSL2 の片方向。LAN→WSL2 にはnetsh interface portproxyによる明示的な橋渡しが必要
確認コマンド
まずどの層で詰まっているかを特定します。
PowerShell と WSL 内のシェルを並べて開いて実行するのが効率的です。
bash
# WSL2 内: コンテナが正しくリッスンしているか
ss -tlnp | grep :3000
curl -v http://localhost:3000
# WSL2 内: WSL VM 自身の IP
ip addr show eth0 | grep "inet "
hostname -I
# PowerShell: Windows から WSL の IP に直接届くか
wsl hostname -I
Test-NetConnection -ComputerName <WSL の IP> -Port 3000
# PowerShell: localhost 転送の状況
Get-Content $env:USERPROFILE\.wslconfig # localhostForwarding が false になっていないか
# PowerShell: 現在の portproxy ルール
netsh interface portproxy show v4tov4
# PowerShell: Windows ファイアウォールのルール確認
Get-NetFirewallRule -DisplayName "*WSL*" | Format-Table DisplayName, Enabled, Direction, Action解決策 1: Windows から localhost で繋げたい
多くのケースはこれで十分です。
%USERPROFILE%\.wslconfig(存在しなければ新規作成)に次を書き、PowerShell で wsl --shutdown → WSL 起動し直します。
bash
# %USERPROFILE%\.wslconfig
[wsl2]
localhostForwarding=true
# WSL を再起動して反映
wsl --shutdown解決策 2: LAN の他端末(スマホなど)から繋げたい
netsh portproxy で「Windows の全 IP の 3000 番 → WSL VM の 3000 番」へ橋渡しし、Windows ファイアウォールで受信を許可します。
管理者 PowerShell で実行してください。
WSL2 の IP は再起動ごとに変わるので、手動で最新 IP に合わせ直すか、起動時スクリプトで自動化する運用が無難です。
bash
# 管理者 PowerShell
$wslIp = (wsl hostname -I).Trim().Split(" ")[0]
netsh interface portproxy add v4tov4 `
listenaddress=0.0.0.0 listenport=3000 `
connectaddress=$wslIp connectport=3000
New-NetFirewallRule -DisplayName "WSL2 3000" `
-Direction Inbound -LocalPort 3000 `
-Protocol TCP -Action Allow
# 確認
netsh interface portproxy show v4tov4
# ルール削除
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=3000解決策 3: 根本的にネットワーク構成を単純化する(WSL 2.0.0 以降)
Windows 11 + WSL バージョン 2.0.0 以降では「mirrored networking mode」が使えます。
WSL VM に独立 NIC を持たせず Windows の NIC を共有するモードで、localhost / LAN 両方の到達性が一気に改善し、netsh portproxy もほぼ不要になります。
社内 VPN や厳密なセグメンテーションとは相性の問題があるので、導入前に検証を。
bash
# %USERPROFILE%\.wslconfig
[wsl2]
networkingMode=mirrored
localhostForwarding=true
# 反映
wsl --shutdown