前回はwsl.confを使った設定を紹介しました。
最近のWSL2ではsystemdが使えるようになったため、SSHサーバなど必要なサーバ類はWSL2の起動時に自動的に動かせるようになりました。
これでWSL2の実用度が上がりましたが、こうなってくるとやりたいのがWSL2に外部(LAN上の他のPC)から接続するということです。
今回はこの設定を行いたいと思います。
外部からのWSL2への接続問題
WSL2ではWindowsとLinuxが仮想ネットワークで接続された構成になります。
このとき仮想ネットワークのアドレスは172.21.50.0/20というようなクラスBのプライベートネットワークアドレスが振られます。
以前のWSL2は仮想ネットワークのIPアドレスは変化したと記憶していますが、この記事作成時点のバージョンでは仮想ネットワークのアドレスは一定のようです。
この仮想ネットワーク上のWindowsのアドレスは、PowerShellでipconfigコマンドを実行すると「イーサネット アダプター vEthernet (WSL (Hyper-V firewall))」として表示されます。
> ipconfig
(省略)
イーサネット アダプター vEthernet (WSL (Hyper-V firewall)):
接続固有の DNS サフィックス . . . . .:
リンクローカル IPv6 アドレス. . . . .: fe80::84d2:xxxx:xxxx:xxxx%42
IPv4 アドレス . . . . . . . . . . . .: 172.28.32.1
サブネット マスク . . . . . . . . . .: 255.255.240.0
デフォルト ゲートウェイ . . . . . . .:
そして、WSL2のLinuxのIPアドレスは、このネットワークアドレスの範囲内で割り当てられます。仮想ネットワーク上のLinux側のアドレスを確認するためには、hostnameコマンドを実行すればOKです。
$ hostname -I
172.21.92.66
この例では下記のようなネットワーク構成になっています。
Windows 11のPCの192.168.10.2というIPアドレスは家庭内LANのIPアドレスです。
WindowsからWSL2(Linux)へ接続するためにはこのLinuxのIPアドレスあるいはlocalhostを使うことによって、アクセスすることができる。
通常、localhostというホスト名は自分自身を指すことになるのですが、WSL2を起動しているWindows上から「localhost」というホスト名でアクセスすると、Linux側にデータが転送される仕組みになっています。
この機能を使うと、たとえば、SSHであれば、Windowsからlocalhostに対してSSH接続を行うとWSL2のLinuxへのSSH接続を行うことができます。

ところが、外部のPC(LAN上のPC)からWSL2のLinuxに接続するときには状況が変わってきます。
この状況では「localhost」という芸当は使えません。というのも「localhost」がそのPC自体を示すため、データがWSL2の方に飛んでいきません。
それではということで、WSL2のLinuxのIPアドレス(172.21.92.66)で接続しようとしてもそれもうまくいきません。
これは他のPCからは、WindowsとWSL2のLinuxをつなぐ仮想ネットワークの存在がわからないからです。
それではということで、WSL2を動かしているWindowsのアドレス(この例では192.168.10.2)を使ってみても、WSL2にはデータが届きません。
このようにWSL2では外部のPCからWSL2上のLinuxへの接続は一筋縄でいきません。
Windowsのポートプロキシを使った接続
これまで説明した外部からのWSL2へ接続問題に対し、MicrosoftからはWindowsのポートプロキシ機能を使うように案内されています。
WSL2の設定を変更してネットワークモードを「ミラーモード」にする方法もありますが、ミラーモードについては別の機会に紹介したいと思います。

「ポートプロキシ機能」というのは聞き慣れない機能ですが、要はWindowsがあるネットワークから受信したデータを他のネットワークに転送する機能です。

この機能を使って次のように通信できるようにするということのようです。
使用するポートの確認
ポートプロキシ機能では転送するポートをひとつずつ設定する必要があります。
このため、WSL2のLinuxのポートに接続したいのかを決めておきます。また、対応するWindowsのポート番号も決めておきます。
今回は次のようにしました。
用途 | プロトコル | Windowsのポート (転送元) | Linuxのポート (転送先) |
---|---|---|---|
ssh | TCP | 10022 | 22 |
xrdp | TCP | 13390 | 3390 |
転送元を転送先と同一にしても良いのですが、Windowsで使用する可能性もあるかもしれないので、10000を足したポート番号を転送元のポート番号としました。
今回はssh用とxrdp用のポート番号しか設定しませんが、WSL2のLinuxでWebサーバを動かしたりする場合はポート番号80やポート番号433を転送先とした設定が必要になります。
Windowsのファイルアウォールの設定変更
Windowsで接続を受け付けるポート(転送元となるポート)が決まったら、そのポート番号を受信可能にする必要があります。
「コントロールパネル」→「システムとセキュリティ」から「Windows Defenderファイアウォール」を開きます。
右側に「詳細設定」があるのでこれを選択します。
これでファイアウォールを設定する画面なりますので、左側のペインで「受信の規則」を選択したら、右側のペインで「新しい規則」を選択します。
規則の種類は「ポート」を選択します。
次にWindowsで受信可能とするポートを指定します。今回はTCPの10022と13390を受信するので次のようになります。
操作は「接続を許可する」とします。
次はこの規則がいつ適用されるかの設定ですが、目的はLAN上のPCからWSL2のLinuxへの接続なので「ドメイン」「プライベート」はチェックし、「パブリック」のチェックは外しておきます。
最後にこの規則の名前と説明を入力します。
これで受信の規則一覧に、今回作成した規則が現れれば設定完了です。
ポートプロキシの設定
ようやく本丸のポートプロキシの設定となりました。
Windows側でPowerShellを管理者権限で立ち上げます。そして次のコマンドを実行してみます。
netsh interface portproxy add v4tov4 listenport=10022 listenaddress=0.0.0.0 connectport=22 connectaddress=(wsl hostname -I)
「(wsl hostname -I)
」の部分は、WSLのLinuxでhostname -I
を実行した結果に置き換えられます。
すなわちWSL2のLinuxのIPアドレスがconnectaddressに設定されることになります。
これでWindowsのポート10022へのアクセスをWSL2のLinuxのポート22(SSHサーバ)に転送する様になります。
転送したいポートが複数ある場合は、listenportとconnectportの数値を変えて同様の設定をします。
netsh interface portproxy add v4tov4 listenport=13390 listenaddress=0.0.0.0 connectport=3390 connectaddress=(wsl hostname -I)
ちなみに設定状態を確認するコマンドは「netsh interface portproxy show all
」になります。
> netsh interface portproxy show all
ipv4 をリッスンする: ipv4 に接続する:
Address Port Address Port
--------------- ---------- --------------- ----------
0.0.0.0 10022 172.21.92.66 22
0.0.0.0 13390 172.21.92.66 3390
LAN上のPCからの接続
あとはLAN上のPCから、WSL2を動かしているWindowsのIPアドレスに対して、WSL2のLinuxで使用したい機能に応じたポート番号で接続します。
今回の例では、WSL2のLinuxへSSHで接続したい場合は、WindowsのIPアドレス(192.168.10.2)のポート番号10022に対して接続を行います。
WSL2のSSHサーバで公開鍵認証のみにしている場合は、公開鍵の登録を行っておきましょう。
接続先をIPアドレスではなくホスト名(コンピューター名)としている場合は、PuTTYの接続設定でIPv4を使用するようにしておきましょう。
ポートプロキシの設定はIPv4のみを行っていますので、プロトコルを自動としておくと、IPv6で接続を試して失敗→IPv4で接続して成功という流れになり、接続確立まで時間がかかります。
これで問題なく接続できるはずです。これは次のような通信になるからです。
同様にWSL2のLinuxへxrdpで接続する場合は、リモートデスクトップの設定で接続先のコンピューターとし「WindowsのIPアドレス:転送するポート番号」とすればOKです。今回の例では「192.168.10.2:3390」を指定することになります。
自動化する
これまで行った設定でLAN上のPCからWSL2のLinuxへ接続できることを確認しました。
あとはWSL2のLinuxを起動したら自動的にポートプロキシの設定がされるようにしてみましょう。ただ、ポートプロキシを変更するためにはWindowsの管理者権限でnetshコマンドを実行する必要があるので、ひと工夫する必要があります。
バッチファイルの作成
まず下記内容のバッチファイルを作成しましょう。
@echo off
FOR /F "usebackq" %%i in (`wsl -d Ubuntu hostname -I`) do set IP=%%i
netsh interface portproxy delete v4tov4 listenport=10022 listenaddress=0.0.0.0 >NUL
netsh interface portproxy add v4tov4 listenport=10022 listenaddress=0.0.0.0 connectport=22 connectaddress=%IP%
netsh interface portproxy delete v4tov4 listenport=13390 listenaddress=0.0.0.0 >NUL
netsh interface portproxy add v4tov4 listenport=13390 listenaddress=0.0.0.0 connectport=3390 connectaddress=%IP%
WSL2でUbuntu以外のディストリビューションを利用している方は、3行目と5行目の「Ubuntu」の部分をお使いのディストリビューションに合わせて変更してください。
このファイルを適当なフォルダーに「portproxy-ubuntu.bat」として保存しておきます。
テストをするにはこのバッチファイルを右クリックして「管理者として実行」をしてみましょう。
その後、PowerShellで「netsh interface portproxy show all
」を実行して、ポートプロキシの設定が表示されればOKです。
タスクを作成
先ほど作成したバッチファイルを管理者権限で実行するために、タスクスケジューラで新しいタスクを設定します。
まずスタートメニューで「タスクスケジューラ」と入力してタスクスケジューラを起動しましょう。
タスクスケジューラでは「タスクの作成」を選択します。
タスクの作成画面では、「全般」タブでまずタスクに名前をつけます。このとき、タスクの名前は半角英数字のみとしたほうが無難です。また「ユーザーがログオンしているかどうかにかかわらず実行する」を選択して、さらに「最上位の特権で実行する」をチェックします。
次に「操作」タブに移り、「新規」を選択します。
そして「操作」が「プログラムの開始」担っていることを確認の上、「プログラム/スクリプト」に先ほど作成したバッチファイルを指定して、「OK」を選択します。
タスクの作成のウィンドウに戻ったら、最後に「OK」を選択して作成したタスクを保存します。
タスクを保存するとユーザーアカウント情報を入力するように要求されます。
Windows11にMicrosoftアカウントを使ってサインインしている場合は、Microsoftアカウントにしているメールアドレスとパスワードを入力しましょう。
これでタクスの作成は完了です。
タスクスケジューラの「タスクスケジューラライブラリ」に作成したタスクが表示されているはずです。
WSL2からのタスクの実行テスト
ここまで来たら先ほど作成したタスクが正しく実行できるか確認してみましょう。
まずは、Windowsで管理者権限でPowerShellを起動し、下記のコマンドを実行してポートプロキシの設定がなにもない状況にします。
netsh interface portproxy delete v4tov4 listenport=10022 listenaddress=0.0.0.0
netsh interface portproxy delete v4tov4 listenport=13390 listenaddress=0.0.0.0
次のコマンドを実行して何も表示されなければポートプロキシの設定は削除されています。
netsh interface portproxy show all
次にWSL2(Ubuntu)で次のコマンドを実行します。
powershell.exe -Command "Start-ScheduledTask -TaskName 'portproxy for Ubuntu'"
「portproxy for Ubuntu」の部分は作成したタスクの名前です。タスクを別の名前にしたときにはこの部分を変更してください。
コマンドがエラーなく実行できたら、Windows側のPowerShellでポートプロキシの状態を確認しましょう。
> netsh interface portproxy show all
ipv4 をリッスンする: ipv4 に接続する:
Address Port Address Port
--------------- ---------- --------------- ----------
0.0.0.0 10022 172.21.92.66 22
0.0.0.0 13390 172.21.92.66 3390
このようにポートプロキシの設定が表示されればOKです。
wsl.confの設定
最後にWSL2の起動時にさきほどのタスクを実行して、自動的にポートプロキシの設定が行われるようにします。
この設定にはWSL2(Linux)の/etc/wsl.confというファイルを利用します。
まず、WSL2におけるpowershell.exeのパスを確認しておきましょう。
$ which powershell.exe
/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0//powershell.exe
そして起動時にpowershell.exeを使ってタスクを実行するように、wsl.confを開いて次の行を追加します。
[boot]
command = "/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0/powershell.exe -Command \"Start-ScheduledTask -TaskName 'portproxy for Ubuntu'\""
Start-ScheduledTaskの前の「”」と末尾から2番目の「”」には「\」がいていることに注意してください。
これでWSL2の起動時に作成したタスクが実行されポートプロキシの設定が行われます。
まとめ
今回はWindows Subsystem for Linux (WSL2)で導入したUbuntuに、外部のPCから接続する方法を紹介しました。
WSL1の頃は簡単にできたのですが、WSL2になってからネットワークの構成が変更になっているため、少々設定が複雑になっています。
次回はWSL2のLinuxをWindowsの起動時に自動的に立ち上げる設定をしたいと思います。
コメント