リモートWindowsのWSLへSSH接続
Table of Contents
クライアントからリモートWindowsのWSLへSSH接続をする場合、Windowsのポートフォワーディング機能を利用します。
前提
この記事でリモートWindowsへのSSH接続ができていること。未設定の場合は、先にこちらを参考にしてリモートWindowsへのSSH接続を確立してください。
リモートのWSLへOpenSSHサーバをインストール
sudo apt update
sudo apt upgrade -y
sudo apt install openssh-server
Port 22222など、Windows側(22)と被らないポートに変更:
sudo vim /etc/ssh/sshd_config
SSHサーバを再起動:
sudo service ssh restart
sshdが22222で待ち受けているか確認:
ss -tlnp | grep 22222
# 出力例
# LISTEN 0 128 0.0.0.0:22222 0.0.0.0:*
# LISTEN 0 128 [::]:22222 [::]:*
この設定が完了したら、リモートWindowsからWSLへSSH接続できることを確認します。
# WSLのパスワードが必要
ssh -p 22222 wsluser@localhost
Windowsの設定
以下、リモートWindowsの管理者権限のPowerShellで実行します。
portproxyの待ち受けポート設定
WSLのIPアドレスを取得し、Windowsのportproxyでポートフォワーディングを設定します。
WSLはIPアドレスが2つ以上表示される(例:IPv4とIPv6, Docker)ことがあるため、最初のIPアドレス(IPv4)を取得します。
# WSLのIPアドレス(IPv4)を取得
$wslIp = (wsl hostname -I).Trim().Split(' ')[0]
# Windowsのportproxyでポートフォワーディングを設定
netsh interface portproxy add v4tov4 listenport=22222 listenaddress=0.0.0.0 connectport=22222 connectaddress=$wslIp
# 確認
# Listen on ipv4: 0.0.0.0:22222 → Connect to ipv4: 172.x.x.x:22222 のように表示されればOK
netsh interface portproxy show v4tov4
ファイアウォールでport 22222を許可
Windows Defenderファイアウォールでこのポートを開けると、外部からWSLのSSHサーバへ接続できるようになります。
New-NetFirewallRule -DisplayName "WSL SSH" -Direction Inbound -LocalPort 22222 -Protocol TCP -Action Allow
クライアントからリモートのWSLへSSH接続
以下で接続を確認します。
注意:IPv4で接続するための-4オプションを明示的に指定します。無しの場合、環境によってはIPv6が使用され接続に失敗する可能性があります。
ssh -4 -p 22222 wsluser@<hostname>
接続が成功すれば、リモートWindowsのWSLへSSH接続できています。
パスワードなしで接続したい場合は、SSHキーを生成してリモートWindowsのWSLに公開鍵を配置してください。
注意:SSH公開鍵は既に生成済みの前提です。詳細はこの記事を参照。
type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh -4 -p 22222 wsluser@<hostname> "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
また、接続簡略化のために、クライアント側の~/.ssh/configに以下の設定を追加することもできます。
Host remote-wsl
HostName <hostname> # or <hostname>.local or <ip-address>
Port 22222
User wsluser
AddressFamily inet # IPv4を強制
これにより、以下のコマンドで簡単にSSH接続できるようになります。
# ssh -4 -p 22222 wsluser@<hostname> の代わりに以下で接続可能
ssh remote-wsl
トラブルシューティング
段階的に切り分けると原因が見つけやすいです:
- リモートWSL:
ss -tlnp | grep 22222でsshdが22222で待ち受けているか確認 - リモートWindows:
netsh interface portproxy show v4tov4で転送設定を確認 - リモートWindows:
ssh -p 22222 wsluser@localhostでWSLへのローカル経由の接続を試す - クライアント:
ssh username@hostnameでリモートWindowsへのSSH接続を試す - クライアント:
ssh -4 -v -p 22222 wsluser@<WindowsのIP>で外部経由を試す (-vで詳細なログを表示)
WSLのIPアドレス自動更新
WSLは仮想NIC上で動作し、起動するたびにIPが変わるため、Windowsのportproxy設定も更新する必要があります。
リモートWindowsで以下の更新用PSスクリプトを作成しておきます。
# update-wsl-portproxy.ps1
$wslIp = (wsl hostname -I).Trim().Split(' ')[0]
netsh interface portproxy delete v4tov4 listenport=22222 listenaddress=0.0.0.0 2>$null
netsh interface portproxy add v4tov4 listenport=22222 listenaddress=0.0.0.0 connectport=22222 connectaddress=$wslIp
Write-Host "Forwarded 22222 -> $wslIp:22222"
スクリプトは netsh を使うため、Windows側で管理者権限のPowerShellから実行する必要があります。WSL内では動きません。実行するタイミングとして、以下の2通りの方法があります。
方法1:Windowsログオン時にタスクスケジューラで自動実行
Windows再起動のたびにWSLのIPが変わる可能性があるため、ログオン時に自動で更新するのが便利です。
-
管理者権限のPowerShellで以下を実行し、タスクを登録します(
C:\Scripts\update-wsl-portproxy.ps1は実際のスクリプト配置パスに置き換え)。$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -File C:\Scripts\update-wsl-portproxy.ps1" $trigger = New-ScheduledTaskTrigger -AtLogOn $principal = New-ScheduledTaskPrincipal -UserId "$env:USERDOMAIN\$env:USERNAME" -RunLevel Highest Register-ScheduledTask -TaskName "Update WSL PortProxy" -Action $action -Trigger $trigger -Principal $principal -
登録後、タスクスケジューラのGUI(
taskschd.msc)から「Update WSL PortProxy」を確認できます。 -
動作確認したい場合は、タスクを右クリック →「実行する」で手動起動できます。
注意:スクリプト内で wsl hostname -I を呼ぶため、WSLが停止していても自動で起動されます。
方法2:WSL再起動後に手動実行
wsl --shutdown などでWSLを再起動した直後は、IPが変わっている可能性があります。その場合は、管理者権限のPowerShellで手動実行します。
powershell -NoProfile -ExecutionPolicy Bypass -File C:\Scripts\update-wsl-portproxy.ps1
実行後、netsh interface portproxy show v4tov4 で転送先IPが最新のWSL IPに更新されていれば成功です。