家のデスクトップにWSL2(Windows Subsystem for Linux 2)環境を作ったはいいものの、そこにSSH接続するのに苦闘した。
今回の苦闘の主要因は、一言でいうと**「管理者からWSL環境にアクセスできなかった」**こと。この条件でもうまく行った(であろう)方法をメモしておく。
やりたいこと
Winの起動さえすれば(ログインしなくても)、LAN内からUbuntuにSSH接続できるようにする。
家族共用のPC(スペック強め)なので、自身のmacノートからアクセスできるならありがたい。1
SSH用の鍵設定等はここでは省略する。
実行環境
-
Windows 10 Home ver.21H1(OSビルド: 19043.1348)
- ローカルIPアドレスはDHCP固定割当
-
WSL2 ディストリビューション: Ubuntu
20.04.3 LTS (GNU/Linux 5.10.16.3-microsoft-standard-WSL2 x86_64)
-
Winの管理者でないユーザーに、Ubuntuディストリビューションをインストール済み
- 管理者ユーザー(Administratorsにあるユーザー)のパスワードは持っている
課題
①SSHサーバーが自動起動してくれない
Ubuntu上のSSHサーバーが常に走ってくれていれば良いが、Ubuntuを起動してもsshプロセスは自動起動してくれない。どうも、普通のlinuxでの自動起動方法は使えないらしい。
手動であれば、Ubuntu上でsudo service ssh restart
とすれば起動できる。
→タスクスケジューラを使う
②Ubuntuが勝手に閉じる
SSHサーバーを起動しても、しばらくするとUbuntuがシャットダウンしてしまっていた。たぶん、wsl.exeの(Ubuntuでなにか行う)プロセスが何かしら起動したままでないといけない。
調べている限りでは、そんなはずは無いのだろうけど…
そして、いったん閉じられてしまうと、再度起動してもsshは停止状態のままになってしまう。
→wsl.exeを(コマンドをつけずに)実行して、そのままバックグラウンドで走らせておく。
③UbuntuのポートにWin外からアクセスできない
UbuntuがWinの作った仮想ネットワーク上にあるため、別端末からアクセスできない。
Winからは、UbuntuのIPアドレスを使う以外に、localhostからでもアクセスできる(デフォルトでフォワーディングされる)。
→localhostへのポートフォワーディングを設定する。
基本的には以上の3つ。
なお、ファイアウォールに関してはLAN内からの接続を信頼しているため、特に弾かれることはなかった。
①③の解決策は検索すればいろいろ出てくるが、どれも、管理者ユーザーから、インストールしたディストリビューションにアクセスできることを暗黙の前提としていた。
しかし、管理者権限でwsl -l -v
を実行したところ、「ディストリビューションがインストールされていません」と返ってきた。つまりアクセスできていないのだ。(これは仕様…?バグ…?)
手順
1. Ubuntuの自動バックグラウンド起動を設定
先に②を解決していく。
タスクスケジューラを検索して管理者権限で起動。スタートメニューのWindows管理ツールの中から見つけることもできる。
「操作」→「タスクの作成」から作成していく。
「全般」タブで、「名前」には適当なタスク名を入力。
「ユーザーまたはグループの変更」から、Ubuntuにアクセスできるアカウントを実行時ユーザーとして指定。このとき、「詳細設定」→「検索」で出てきたリストから選択すると確実。
「ログオンしているかどうかに関わらず実行する」を選択する。一応、「パスワードを保存しない」もオンに。
「トリガー」タブでトリガー「スタートアップ時」を追加。
「操作」タブでは、「プログラム/スクリプト: wsl
」で引数なしのものを追加。(ディストリビューションを指定したい場合は、引数が-d <ディストリビューション>
)
これで自動起動タスクを作成できたわけだが、作成後、実行時ユーザーには「バッチジョブとしてログオン」権限が必要だと言われた。ということで手順2へ。
###2. 「バッチジョブとしてログオン」権限の割り当て
この権限の割り当ては、グループポリシーエディタ(ローカルセキュリティポリシー)から行える。これはHOME Editionには用意されていないので、有効化する。
以下のバッチファイルを作成し、実行する。
@echo off
pushd "%~dp0"
dir /b %SystemRoot%\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientExtensions-Package~3*.mum >MumList.txt
dir /b %SystemRoot%\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientTools-Package~3*.mum >>MumList.txt
for /f %%i in ('findstr /i . MumList.txt 2^>nul') do dism /online /norestart /add-package:"%SystemRoot%\servicing\Packages\%%i"
del MumList.txt
pause
そしたら「ローカルセキュリティポリシー」が追加されるので、検索して管理者権限で起動。
「ローカルポリシー」→「ユーザー権利の割り当て」→
「バッチ ジョブとしてログオン」から、先ほどの実行時ユーザーを追加する。
以上で、②が解決。
実際に再起動したあと、wsl -l -v
で確認すると実行状態になっている。
3. SSHの自動起動
手順1と同様にして、wsl sudo service ssh restart
をタスク登録しても良いが、
Ubuntuの起動時に1回だけ行いたいことは他にも増えそうなので、それをまとめたスクリプトをUbuntu上に用意しておく。
#!/bin/bash
service ssh start
# その他やりたいことあれば
このスクリプトを、パスワードなしでsudo実行できるようにする。
sudo visudo
を実行、エディタが開くので、最後の行に
%sudo ALL=NOPASSWD: /opt/bin/on-startup.sh
を追加する。
そしたら、このスクリプトの実行をタスクスケジューラに登録していく。
「全般」と「トリガー」タブは手順1と同様。「操作」は、wsl
を引数sudo /opt/bin/on-startup.sh
で実行する。
ただし、念の為トリガーに30秒遅延をかけておいた。これは、このスクリプト実行後に一旦Ubuntuが閉じてから、手順1のタスクが起動する可能性を避けるためだ。実際にそうなりうるかは未検証。
「バッチジョブとしてログオン」権限はすでに手順2で割り当ててあるので、これで①も解決。
4.ポートフォワーディング
基本的には、管理者権限でnetsh.exe interface portproxy add v4tov4
を叩けばいい。WinのローカルIPは固定割当にしているので、1回そのIPの好きなポート(今回は51234)からlocalhost:22にフォワーディング設定をすればうまくいく…はずだった。
しかし、Winを再起動するとうまく動いてくれない。2それなら再起動後に再設定してやればいい。
netsh.exe interface portproxy delete v4tov4 listenport=51234 listenaddress=<WinのIPアドレス>
netsh.exe interface portproxy add v4tov4 listenport=51234 listenaddress=<WinのIPアドレス> connectport=22 connectaddress=localhost
このようなbatファイルを適当な場所に置き、またタスクスケジューラでスタートアップ時に呼び出すが、今回は
- 実行時ユーザーを管理者ユーザーにする
- 最上位の特権で実行
にする点が異なる。トリガーの遅延も一応つけた。
以上で無事SSH接続できるようになった。快適。
近々来るWin10 21H2で、WSL2からGPUにアクセスできるようになるそうで。まだかな。
参考
- wsl2でsshサーバを起動し、外部からそこに接続
- Windows WSL2に外部から直接アクセスするための設定
- タスクスケジューラ設定時に"バッチ ジョブ としてログオン"の権利が必要と言われる
- 「Windows 10 Home」でローカルグループポリシーエディターを使用する方法