WSL の MTU による停止
WSL2 のホストは、セッションが普通につながったあと、どちらの端にもエラーを 出さずにただ止まる、唯一の構成です。原因が SSH や Tessera であることは ほとんどありません。原因は、WSL2 がその背後に置かれている仮想アダプタの MTU です。接続時にこの特徴的な停止を観測すると、Tessera はここへリンクする アンバーの WSL2 / Tailscale の MTU の問題の可能性があります カードを表示 します。
症状
- セッションはつながり、プロンプトが現れ、短いコマンドは問題なく動きます。
- 大きなまとまりを送るものはすべて固まります。長いファイルへの
cat、幅の 広いls、tmux の全画面再描画、ファイルパネルでの転送。 - 何も失敗を報告しません。セッションがただ動かなくなるだけです。接続し直せば 動きますが、同じ種類の出力でまた止まります。
- 同じホストでも、ssh より mosh のほうが調子よく動きます。
接続がプロンプトにたどり着きさえしない場合は、同じ不具合が、それ自体が 大きい SSH の鍵交換を飲み込んでいる可能性があります。以下のテストはそのまま 当てはまります。
なぜ起きるのか
WSL2 は Hyper-V の仮想スイッチの背後で動き、その eth0 は MTU 1500 で
立ち上がります。Windows ホストが実際にはもっと小さい経路 — VPN、PPPoE、
あるいは何らかのトンネル — でネットワークに出ている場合、その実際の経路 MTU
を超えるパケットは途中のどこかで捨てられます。
経路 MTU 探索は、まさにこれを扱うためのものです。パケットを転送できない ホップが ICMP の fragmentation needed を返し、送信側が下げる、という 仕組みです。ところが多くの VPN やファイアウォールはその ICMP を捨てるため、 返事は届きません。小さいパケットは流れ続け、大きいものは黙って消えます — PMTU のブラックホールです。SSH からは、理由もなく止まった接続に見えます。
確かめる
WSL の中から、インターフェイスが何と言っているかを確認します:
ip link show eth0
次に、実際に経路を通り抜けられるサイズを探します。以下の ping は
don't-fragment を立てており、ペイロードにヘッダの 28 バイトを足したものが
全体のサイズになるため、-s 1472 は 1500 バイトのパケットを試すことに
なります。同じ経路の向こう側にあるもの — 接続先のサーバーでも、任意の公開
アドレスでも — を狙ってください:
ping -M do -s 1472 -c 1 example.com # 1500 — usually times out
ping -M do -s 1372 -c 1 example.com # 1400 — usually gets through
タイムアウト がブラックホールです。(代わりにその場でローカルのエラーが
出た場合は、サイズが自分のインターフェイスの MTU を超えています。-s を
下げてやり直してください。)応答が返ってくる最大のペイロードが見つかるまで
範囲を狭め、28 を足したものが実際の経路 MTU です。
Windows 側での同等のものは、PowerShell から:
ping -f -l 1472 example.com
netsh interface ipv4 show subinterfaces
2 つ目は各アダプタの MTU を一覧します。VPN のアダプタが 1400 で、
vEthernet (WSL) が 1500 という並びが、追いかけている不一致です。
WSL 側で直す
測ったサイズをインターフェイスに設定します。これはすぐに反映されますが、 次のシャットダウンで失われます:
sudo ip link set dev eth0 mtu 1400
接続し直して、これまで止まっていたことをもう一度やってみてください。出力が きれいに流れれば、診断は裏付けられました。
定着させるには、WSL に起動時に適用させます。ディストリビューション内の
/etc/wsl.conf に:
[boot]
command = ip link set dev eth0 mtu 1400
そのあと Windows から wsl --shutdown を実行し、ディストリビューションを
起動し直します。[boot] コマンドにはある程度新しい WSL が必要です。
wsl --version で確認してください。
1400 をそのまま写すのではなく、ping のテストで出た数値を使ってください。 1400 はほとんどの VPN を通せる安全な落としどころですが、自分の経路に 合わせた値のほうが、1 パケットあたりの無駄が少なくなります。
あるいは WSL にホストをミラーさせる
Windows 11 22H2 以降で WSL 2.0 以上なら、ミラーモードのネットワークが
ホスト自身のインターフェイスを MTU ごとディストリビューションに渡すため、
そもそも不一致が起きません。%UserProfile%\.wslconfig に:
[wsl2]
networkingMode=mirrored
wsl --shutdown で適用します。これは MTU よりずっと多くのものを変え、
localhost と LAN の到達性の挙動もどちらも変わります。停止するセッション
だけが問題なのであれば、起動コマンドのほうを選んでください。
MTU の小さいホップがサーバー側にある場合
WSL がいつも制約された側とは限りません。同じ ping のテストをサーバーから 実行すれば、どちらの側が抑えられているかが分かります。間のルーターを自分で 管理できるなら、TCP の MSS を見つけた経路 MTU に合わせて抑えることで、 そこを通るすべての接続を一度に直せます:
iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --clamp-mss-to-pmtu
それでもまだ詰まっているうちは
ホストのトランスポートを mosh に切り替えるのは、直すことではなく回避することです。mosh のデータグラム は壊れた MTU の下をすり抜けられるほど小さく、バイトストリームを再生する 代わりに画面を描き直すため、対話的なセッションは生き延びます。ファイル パネルと tmux のサイドチャネルは今も SSH に乗るので、大きな転送は止まり 続ける可能性があります。
ここに書いたどれもが当てはまらない場合は、ログを取得し (設定 → 診断 → ログを書き出す、診断を参照)、 GitHub Issuesに issue を 立ててください。