自宅のWindowsを開発機にする その1: TailscaleでMacとスマホからWSLに入る

この記事でわかること
- Tailscaleで自宅WindowsのWSLにMacからSSHで入れるようにする手順
- ログオンしていないと繋がらない原因(Run unattended)
- 再起動テストで「ログオンなし」に見えて実は自動サインインしていた話
- 非対話SSHではWindowsのコマンドにPATHが通らない罠
Windows 11 + WSL2(Ubuntu 24.04、systemd有効)、Mac、Tailscaleアカウント
この記事は「自宅のWindowsを開発機にする」連載のその1です。その2では Mac の開発環境を作業状態ごと WSL に移した話、その3では Claude Code の設定とメモリの移植、その4では Orca を入れてみた話、その5では Orca で仕事用アカウントと会話履歴を扱う話を書いています。
きっかけ
普段は MacBook Air で開発しているんですが、家には使っていない Windows のデスクトップ(メモリ15GB・16コア)があって、ずっともったいないなと思っていたんですよね。
やりたいことはシンプルで、
- Mac からデスクトップの WSL に SSH で入って開発する
- スマホの Claude アプリからも、デスクトップ上の Claude Code に指示できる
- デスクトップは電源を入れておくだけで、ログオンしていなくても繋がる
の3つです。つなぐ部分は Tailscale に任せることにしました。
そもそも Tailscale って何なのか
自分も名前は聞いたことがあるくらいだったので、ざっくり整理しておきます。
Tailscale は、自分の端末同士をつなぐ VPN なんですけど、よくある「会社の VPN サーバーにつなぐ」タイプとはちょっと違っていて、端末同士が直接つながるメッシュ型の VPN なんですよね。中身の暗号化には WireGuard という VPN の仕組みを使っています。
自宅のマシンに外から入ろうとすると、普通はこういう面倒が出てきます。
- ルーターでポート開放をする
- グローバル IP を調べる(しかも変わる)
- 外に向けて SSH を開けるので、セキュリティが気になる
Tailscale だと、各端末にアプリを入れて同じアカウントでログインするだけで、これを全部すっ飛ばせます。端末同士が NAT の内側からでもお互いを見つけて、直接つながってくれるので、ルーターの設定は一切いじっていません。
いくつか用語も出てくるので、これも軽く。
- tailnet: 自分のアカウントにつながっている端末のネットワークのこと。今回は Mac・スマホ・Windows の3台が入っています
- MagicDNS: tailnet の中の端末に、IP ではなくホスト名で届くようにしてくれる機能。
ssh kt-desktopのようにマシン名で打てるのはこれのおかげです - 直接接続と中継(DERP): 端末同士が直接つながれないとき(厳しいネットワークの内側など)は、Tailscale が用意している中継サーバー(DERP)を経由します。通信は暗号化されたままですが、遠回りになる分遅くなります。どっちになっているかは
tailscale statusの表示がdirectかrelayかで分かります
料金は、個人向けの Personal プランが無料で、ユーザー6人まで・端末数は無制限です(2026年9月時点)。自分ひとりで数台つなぐくらいなら、まず困らないと思います。
デスクトップ側(ざっくり)
デスクトップ側の準備は、Windows 上の Claude(デスクトップアプリ)と一緒にスクリプトを作って進めていました。やっていることは主にこのあたりです。
.wslconfigをnetworkingMode=mirroredにして、WSL の sshd を Windows と同じポート22で受けられるようにする(Windows 側の OpenSSH サーバーは止める)- WSL で systemd を有効にして、
loginctl enable-lingerでログインなしでもユーザーサービスが動くようにする - タスクスケジューラに「起動時に WSL を立ち上げっぱなしにする」タスクを登録する(ログオンしていなくても動く S4U で)
- WSL 側で herdr と Claude Code の Remote Control を systemd のユーザーサービスとして常駐させる
Mac 側: Tailscale を入れる
Mac は Homebrew の cask で入れました。
brew install --cask tailscale-appこれがインストーラの途中で sudo のパスワードを要求するので、Claude Code の Bash ツールからだとそのまま失敗します。対話的な入力が必要なコマンドは tmux の中で走らせて、パスワードのところだけ自分でアタッチして入れる、というやり方にしています。パスワードを Claude 側に渡さずに済むのでこれが楽なんですよね。
インストールが終わってアプリを起動すると、同じアカウントでログイン済みのデスクトップがもう見えていました。
tailscale status
tailscale ping kt-desktop # 同じLAN内なら direct で数msSSH の設定
デスクトップ側で作ったスクリプトに Mac 用の setup-mac.sh もあって、~/.ssh/config に Host を足すところまでやってくれます。自分は結局「desktop」と呼ぶことが多かったので、別名も足しました。
Host kt desktop
HostName kt-desktop
User koki
IdentityFile ~/.ssh/id_rsa
ServerAliveInterval 30これで ssh desktop だけで WSL の Ubuntu に直接入れます。Windows を経由せずにいきなり Linux のシェルに入れるのは、mirrored モードのおかげですね。
あと地味に効くのが Ghostty の terminfo の転送で、これをやっておかないと SSH 先で表示が崩れます。
infocmp -x xterm-ghostty | ssh desktop -- tic -x -罠1: チェックスクリプトの ✘ が誤判定だった
デスクトップ側の状態を確認するスクリプトを SSH 越しに流したら、「起動時に WSL を立ち上げるタスクがない」と ✘ が出たんですよね。
でも PowerShell をフルパスで叩いて確認すると、タスクはちゃんと登録されていて Running でした。原因は、非対話の SSH セッションだと Windows 側の実行ファイル(schtasks.exe や powershell.exe)に PATH が通っていないことでした。WSL の interop 自体は動いているので、フルパスで呼べば普通に動きます。
/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe -NoProfile -Command "Get-ScheduledTask WSL-KeepAlive"チェックが ✘ でも、実体を見るまでは信じないほうがいいなと思いました。
罠2: Tailscale の Run unattended が OFF だった
再起動テストもやりました。最初はデスクトップを再起動して、ログオンしてから Mac で確認していたんですが、これだと「ログオンなしでも繋がるか」の確認になっていないんですよね。
で、改めて設定を見たら Tailscale の Run unattended(ForceDaemon)が OFF でした。Windows の Tailscale はこれが OFF だと、ユーザーがログオンしていない間は繋がりません。せっかく WSL 側をログインなしで動くように作っても、入口が閉じていたら意味がないという…笑
これは WSL からでも Windows 側の CLI で変えられました。
"/mnt/c/Program Files/Tailscale/tailscale.exe" set --unattended
"/mnt/c/Program Files/Tailscale/tailscale.exe" debug prefs | grep ForceDaemon再起動テストで分かったこと
その上で、再起動してログイン画面のまま触らずに置いておくと、30秒くらいで Tailscale が戻ってきて、Mac から ssh desktop で入れて、herdr と Remote Control も active になっていました。
ただ、Windows 側を見ると起動の18秒後に explorer が立ち上がっていたんですよね。自動ログオンの設定はしていないのに、です。画面はロック画面でした。
これは Windows の「再起動後にサインイン情報を使って自動で準備を完了する」機能で、裏で自動サインインしてからロックしている状態だったみたいです。なので正確には「ログオンなしで動いた」のではなく、「再起動なら何もしなくても繋がる」ことが確認できた、というところですね。停電のあとの起動みたいにこの機能が効かないケースは、まだ試せていません。
スマホから
スマホにも Tailscale を入れて同じアカウントでログインしたら、Claude アプリの Code の画面にデスクトップの環境(Remote Control)が出てきました。これで外出先からでも、家のデスクトップ上の Claude Code に作業を投げられるようになりました。
まとめ
- Tailscale で Mac・スマホ・Windows を同じネットワークに入れるだけで、つなぐ部分はほぼ終わる
- Windows 側は Run unattended を ON にしないとログオン前は繋がらない
- 非対話 SSH では Windows のコマンドに PATH が通らないので、チェックはフルパスで
- 再起動テストは「ログオンしない」状態で、Windows 側で本当にログオンしていないかまで見る
次回(その2)は、Mac の開発環境を作業状態ごと WSL に移した話を書きます。


