前回はwsl.confを使ってSSHサーバなどをWSL2の起動時に動かせるようになりました。
これでWSL2の実用度が上がりましたが、こうなってくるとやりたいのがWSL2に外部(LAN上の他のPC)から接続するということです。
今回はこの設定を行いたいと思います。
外部からのWSL2への接続問題
WSL2ではWindowsとLinuxが仮想ネットワークで接続された構成になります。
このとき仮想ネットワークのアドレスは172.28.32.0/24というようなクラスBのプライベートネットワークアドレスが振られます。
このネットワークアドレスも固定ではないようですが、この記事ではこのネットワークアドレスを例にして紹介します。
そして、WSL2のLinuxのIPアドレスは、このネットワークアドレスの範囲内で、起動する毎に異なる値が割り当てられます。
Windowsの仮想ネットワーク上のIPアドレスは、Power Shellでipconfigコマンドを実行すると「イーサネット アダプター vEthernet (WSL)」として表示されます。
> ipconfig (省略) イーサネット アダプター vEthernet (WSL): 接続固有の DNS サフィックス . . . . .: リンクローカル IPv6 アドレス. . . . .: fe80::84d2:xxxx:xxxx:xxxx%42 IPv4 アドレス . . . . . . . . . . . .: 172.28.32.1 サブネット マスク . . . . . . . . . .: 255.255.240.0 デフォルト ゲートウェイ . . . . . . .:
Linux側のIPアドレスが起動毎に異なると、Windowsから接続する前にLinuxのIPアドレスを調べなければ行けません。
これでは使いにくいということで、WSL2を起動しているWindows上から「localhost」というホスト名でアクセスすると、Linuxにデータが転送される仕組みになっています。
この機能を使うと、例えば、SSHであれば、Windowsからlocalhostに対してSSH接続を行うと、WSL2のLinuxへのSSH接続を行うことができます。
ところが、外部のPC(LAN上のPC)からWSL2のLinuxに接続するときには状況が変わってきます。
この状況では「localhost」という芸当は使えません。というのも「localhost」がそのPC自体を示すため、データがWSL2の方に飛んでいきません。
それではということで、WSL2のLinuxのIPアドレス(172.28.?.?)を調べて、そのIPアドレスで接続しようとしてもそれもうまくいきません。
これは他のPCからは、WindowsとWSL2のLinuxをつなぐ仮想ネットワークの存在がわからないからです。
それではということで、WSL2を動かしているWindowsのアドレス(この例では192.168.10.2)を使ってみても、WSL2にはデータが届きません。
このようにWSL2では外部のPCからWSL2上のLinuxへの接続は一筋縄でいきません。
Windowsのポートプロキシを使った接続
これまで説明した外部からのWSL2へ接続問題に対し、MicrosoftからはWindowsのポートプロキシ機能を使うように案内されています。
2022年3月現在の話です。Microsoftは他の方法も検討しているようです。
「ポートプロキシ機能」というのは聞き慣れない機能ですが、要は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への接続なので「パブリック」はチェックを外しておきます。
最後にこの規則の名前と説明を入力します。
これで受信の規則一覧に、今回作成した規則が現れれば設定完了です。
WSL2のLinuxのIPアドレスの確認
あとで必要になるので、WSL2のLinux上で下記のコマンドを実行してIPアドレスを調査しておきます。
$ hostname -I 172.28.37.141
ポートプロキシの設定
ようやく本丸のポートプロキシの設定となりました。
Wndows側でPowerShellを管理者権限で立ち上げます。そして次のコマンドを実行してみます。
> netsh interface portproxy add v4tov4 listenport=10022 connectaddress=172.28.37.141 connectport=22
これでWindowsのポート10022へのアクセスをWSL2のLinuxのポート22(SSHサーバ)に転送する様になります。
転送したいポートが複数ある場合は、listenportとconnectportの数値を変えて同様の設定をしていきます。
> netsh interface portproxy add v4tov4 listenport=13390 connectaddress=172.28.37.141 connectport=3390
ちなみに設定状態を確認するコマンドは「netsh interface portproxy show all」になります。
> netsh interface portproxy show all ipv4 をリッスンする: ipv4 に接続する: Address Port Address Port --------------- ---------- --------------- ---------- * 10022 172.28.37.141 22 * 13390 172.28.37.141 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のIPアドレスは起動する毎に変わってしまう
→ ポートプロキシの設定を毎回やり直す必要がある
ということです。
Windowsを再起動すると、WSL2のLinuxも起動し直すことになるので、ポートプロキシの設定をやり直す必要があります。
毎回、WindowsでPowerShellを立ち上げてコマンドを打ち込むのも面倒です。そこでポートプロキシの設定処理をスクリプト化してワンタッチでできるようにしましょう。
まず適当なディレクトリに下記の内容のファイルを作成し、wsl2-portproxy.batという名前で保存します。
FOR /F "usebackq" %%i in (`wsl -d Ubuntu exec hostname -I`) do set IP=%%i netsh interface portproxy delete v4tov4 listenport=10022 netsh interface portproxy add v4tov4 listenport=10022 connectaddress=%IP% connectport=22 netsh interface portproxy delete v4tov4 listenport=13390 netsh interface portproxy add v4tov4 listenport=13390 connectaddress=%IP% connectport=3390
WSL2でUbuntu以外のディストリビューションを利用している方は、1行目の「Ubuntu」の部分をお使いのディストリビューションに合わせて変更してください。
このバッチファイルでは、1行目でwslコマンドを使ってLinux側のIPアドレスを取得(IP変数に格納)し、その値を使ってポートプロキシのの設定をおなっています。
ポートプロキシの設定をしたい場合は、このwsl2-portproxy.batを右クリックして「管理者として実行」を選択します。
管理者として実行すると「このアプリがデバイスに変更を加えることを許可しますか?」という表示が出るので「はい」を選択します。
WSL2でLinuxを起動したら、このwsl2-portproxy.batを管理者権限で1回実行すれば、外部から接続するためのポートプロキシの設定が行われます。
WSL2のLinuxが停止している状況でこのwsl2-portproxy.batを実行すると、自動的にWSL2のLinuxが起動します(そのため、数秒時間がかかります)。
これはLinuxのIPアドレスを取得するために、WSLコマンドを利用しているからです。
まとめ
今回はWindows Subsystem for Linux (WSL2)で導入したUbuntuに、外部のPCから接続する方法を紹介しました。
WSL1の頃は簡単にできたのですが、WSL2になってからネットワークの構成が変更になっているため、少々設定が複雑になっています。
次回はWSL2のLinuxをWndowsの起動時に自動的に立ち上げる設定をしたいと思います。
コメント
WSL インスタンスのホストの WIndows 上で Windows 付属の OpenSSH sshd を動作させ、WSL に connect する側の外部マシンの ssh に ProxyCommand を以下のように ~/.ssh/config に:
Host win11-wsl
User auser
ProxyCommand ssh win11 -W localhost:22
と設定しておくと、外部マシンから:
% ssh win11-wsl
で win11 というホストで動作している WSL インスタンスに ssh できます。
公開鍵認証をするなら、win11, WSL のそれぞれの ~auser の .ssh/ に公開鍵を置き、.ssh/authorized_keys に公開鍵の中身を追記した上で、適宜 ssh のオプションに -A など追加することで可能です。