📓 memotty

Tailscale 経由で WSL2 に SSH すると鍵交換で固まる問題

環境 #

  • 自宅PC: Windows + WSL2 (Ubuntu)、有線接続。Windows と WSL2 にそれぞれ Tailscale を導入(別ノード扱い)。
  • ノートPC: Tailscale 導入済み。自宅の別 WiFi に接続。

症状 #

  • ノートPC の PowerShell から WSL2 ノードへ ssh すると無反応で固まる。
  • Tailscale IP への ping は返ってくる。

原因 #

  1. Windows と WSL2 は Tailscale 上では別ノードで、それぞれ別の 100.x.x.x を持つ。最初は Windows ノードの IP に ssh していたため届いていなかった(tailscale status で WSL2 ノードの IP を確認して解決)。
  2. 本質的な原因は MTU の逆転。WSL2 の tailscale0 が 1280、その下の eth0 が 1200 になっていた。
    • sshd は tailscale0(1280) 基準でパケットを作る。
    • Tailscale が WireGuard で暗号化すると約 60 バイト増えて合計およそ 1340 バイトになる。
    • これが eth0(1200) を超えるため、大きいパケットが送り出せずドロップされる。
    • 小さいパケット(バナー)は通り、大きいパケット(鍵交換)は落ちるので KEX 段階で固まる。

切り分け手順 #

  • ssh -vvv user@<WSL2のTailscale IP> を実行 → SSH2_MSG_KEXINIT sent の直後で停止。バナー受信後・鍵交換で固まる場合は MTU / MSS を疑う。
  • DF ビット付き ping をサイズ別に実行(PowerShell)。
ping -f -l 1300 <WSL2のTailscale IP>

小さいサイズは通るのに一定サイズ以上で「パケットの断片化が必要ですが、DF が設定されています」と出れば経路 MTU が小さいと判明。

  • WSL2 内で MTU を確認。
ip link show

tailscale0 = 1280、eth0 = 1200 の逆転を確認。

対処 #

WSL2 で eth0 の MTU を tailscale0 + オーバーヘッドが収まる値(通常値 1500)に戻す。

sudo ip link set dev eth0 mtu 1500

→ ssh を再試行して接続成功。

永続化 #

ip link set は WSL2 再起動で元に戻るため /etc/wsl.conf に設定する。

[boot]
command = ip link set dev eth0 mtu 1500

既に [boot] セクションがある場合(例: systemd=true)は分割せず同じセクションにまとめる。

[boot]
systemd=true
command = ip link set dev eth0 mtu 1500

反映と確認。

wsl --shutdown

入り直したあと ip link show eth0 が 1500 になっていれば完了。

メモ #

  • Tailscale が tunnel MTU を 1280 にするのは「1280 + オーバーヘッド ≒ 1340 が通常の 1500 経路に収まる」前提のため。経路上に 1500 を下回る MTU があると破綻する。
  • eth0 が 1200 になっていた根本原因は未調査(手動設定、何らかのソフト、ホスト側 MTU の継承などの可能性)。再起動のたびに 1200 へ戻る場合は別途調査が必要。