昨今 Windows 環境がたいへんデベロッパーフレンドリーになってきたので、なんか1つ WSL で開発できるような環境を持ち歩けるようにしておこうかとラップトップのパソコンを1つ調達してみたのだが、まあどうにも Windows はショートカット体系がなってなさすぎて使いにくい。
ということで WSL を常時起動しておいてサーバとして使い、Mac からリモートで使ってみることにした。ssh と vscode のリモート接続があればまあそんなに困ることはない、はず。
Windows 11 で意図したユーザー名のローカルアカウントを作る
最近の Windows は意図したユーザー名を付けるのが難しい。ssh のときなどに自動で使われるし、C:\Users
以下に作られるディレクトリ名にもなるのでホントやめて欲しい。
上記サイトによるとセットアップ中に Shift + F10 を押すとコマンドプロンプトが出てきて、これで C:Windows\System32\oobe\BypassNRO.cmd
を実行すると再起動し、ネットワーク接続の設定で「インターネットに接続していません」という選択肢が現れるのだそうだ。
これでローカルアカウントでセットアップできるようになる。秘密の質問がうざったいがしょうがない。こんなのまったくセキュアじゃないのに。
Home Edition で Hyper-V を有効化する
Windows 11 Home Edition では Hyper-V がないのだが、手動でインストールすれば使えるらしい。ライセンス的にも問題ないと聞くのだがちょっとエビデンスが見つからない。問題があれば Pro にアップグレードしようかなあと思いつつ、
上記サイトのバッチファイルをそのまま使わせていただいた。
WSL のインストール
Winキー → cmd と入力 でコマンドプロンプトが出てくる。必要があればそのまま「管理者として実行」が選べるの便利だねこれ。
wsl --install -d Debian
これだけで Debian がインストールされるの便利。なんか文字化けエラーが出たけど、Microsoft から WSL のアップデータを入手したら治った。
WSL の常時起動
WSL すぐ死ぬ。メモリも食うしそりゃ普通ならそうだろうが、今回はサーバとして使うので常時稼働しててもらわないと困る。
wsl -u root -- service cron restart
とかやっておくと daemon が起動し続けてくれるので常時起動状態になるようだ。
最近の wsl は systemd に対応していて、設定で systemd を動かしておけるのだが、この状態だと上のコマンドを実行しても WSL すぐ死ぬ。
/etc/wsl.conf
で設定できるようだ。
[boot] systemd=false
デフォルトで false なのでこの設定は要らないのだが、将来デフォルトが変わるかもしれないのでまあメモ的に書いておく。
localhost forwarding と外部から接続するためのポート転送
WSL に Windows から localhost で接続できる仕組みがあるらしい。
これは今ではデフォルトで動いてるとのこと。なるほど確かに wsl で sshd を起動しておくと、コマンドプロンプトから ssh localhost
でログインできる。意図したユーザー名がつけられてなければ ssh {wslusername}@localhost
とやらねばならなかったところ。
Windows 環境だけで開発するならもうこれだけで十分だね。
だが今回外部からアクセスするための設定をしないといけない。それに関しては localhost forwarding が動いてるならぜんぶ ::1
にフォワードしちゃえばいいんじゃね? という話がおもしろかった。
IPv4でアクセスしたものをIPv6に変換してしまえば良いと考えました。「192.168.0.10」を「::1」に変換するのです。
なるほどこれなら今の IP アドレスを見なくてもいいし、1回設定すれば済んでしまうな。
起動用バッチファイル
というわけで出来上がったバッチファイルは以下の通り。 まだ環境が流動的なので portproxy はリセットして設定し直すようにしている。docker は起動してない時に restart しても動かないので start にしてある。
@echo off cd %~dp0 netsh interface portproxy reset wsl -u root -- service cron restart wsl -u root -- service ssh restart wsl -u root -- service docker start set ports=22 80 3000 8080 for %%p in (%ports%) do ( netsh interface portproxy add v4tov6 listenport=%%p connectaddress=::1 connectport=%%p netsh interface portproxy add v6tov6 listenport=%%p connectaddress=::1 connectport=%%p )
タスクスケジューラで自動起動……が動かない
さてあとは Windows のタスクスケジューラで OS 起動時に上のバッチファイルを自動実行させておけば便利……かと思いきやこれが動かない。
「ユーザーがログオンしているかどうかにかかわらず実行する(Run whether user is logged in or not)」では wsl コマンドが実行されない現象があるようだ。手元の別の Windows 10 のマシンでは動くので Windows 11 の一部バージョンでの現象かもしれない。
すでに github に issue があがってていろんな回避策が議論されているが、どれもこれもうまくいったりいかなかったりしてる様子。
Strange how everyone has a different method that works.
不思議なことに、人によってうまくいく方法が違うんですね。
Unable to start WSL via Task Scheduler · Issue #8835 · microsoft/WSL · GitHub
このコメントがおもしろかった。こんな不可思議なことが最先端のソフトウェアでも起きるんだから、本当にソフトウェア開発というのは複雑なものである。
しょうがないので上のバッチファイルへのショートカットをデスクトップに作ってしばらく手動起動することにしよう。
なんにせよバッチファイル一つでさくっとサーバ化できるのだからたいへん便利なものである。
おまけ: オーディオを転送する
# apt install sox libsox-fmt-all
これで play
コマンドで mp3 などが再生できるようになる。
ssh で接続先のマシンで鳴らした音を手元の環境で再生するには pulseaudio を使えばいい。
$ brew install pulseaudio $ brew services restart pulseaudio
これで Mac 側で pulseaudio が起動する。Venture にアップグレードしたら「バックグラウンド項目が追加されました」の通知がうざいことになったが、オンオフしたりなんだりしてると止むので我慢してる。なんとかならんのかこれ。
あ、あと IPv6 でアクセスされることもあるので、/usr/local/etc/pulse/default.pa
で以下のように設定しておく。
load-module module-native-protocol-tcp auth-ip-acl=127.0.0.0/8;::1
それから ~/.ssh/config
でポート転送を仕掛けておく。
Host wsl-machine HostName wsl-machine.local # PulseAudio RemoteForward 14713 localhost:4713
あとは環境変数を PULSE_SERVER=tcp:localhost:14713
としておけば、リモートのマシンで
$ play -q path/to/audio/file.mp3
として手元のマシンから音が鳴るはず。
enjoy!