Herdr × Tailscaleで、どこからでも同じ開発環境を使えるようにした話
普段、開発をしていると地味に困ることがあります。
「自宅のMac miniで作業していた続きを、外出先のMacBook Airでそのままやりたい」
Gitにコミットして、MacBook Air側でpullすればコード自体は持ってこられます。
ただ、実際の開発環境はコードだけではありません。
- 起動している開発サーバー
- ターミナルの状態
- Claude CodeやCodexなどのコーディングエージェントとのやり取り
- 途中まで確認していたログ
- Node.jsやPythonなどの実行環境
- 環境変数やローカルの設定
端末を変えるたびに、これらをもう一度立ち上げ直すのは意外と面倒です。
そこで最近、
Mac miniを開発環境の「母艦」にして、外からそのまま操作できないか?
という環境を作ってみました。
使ったのが、HerdrとTailscaleです。
やりたかったこと
普段使っている端末は、大きく2台です。
- 自宅:Mac mini
- 外出先:MacBook Air
これまでは、それぞれを独立した開発端末として使っていました。
今回から考え方を変えて、開発環境そのものはMac miniに集約することにしました。
MacBook Airでは開発環境を再現するのではなく、自宅のMac miniへ接続します。
構成としては、こんなイメージです。
flowchart LR
MBA["MacBook Air<br>外出先"]
IPHONE["iPhone<br>確認・軽作業"]
TS["Tailscale<br>Private Network"]
MINI["Mac mini<br>開発母艦"]
HERDR["Herdr"]
AGENT["Claude Code / Codex"]
APP["Webアプリ / API / 開発サーバー"]
MBA --> TS
IPHONE --> TS
TS --> MINI
MINI --> HERDR
HERDR --> AGENT
HERDR --> APP
MacBook Airは、極端に言えば画面とキーボードです。
実際の処理やファイル、開発環境はMac mini側にあります。
Tailscaleで、自宅のMac miniにつなぐ
まず利用したのがTailscaleです。
Tailscaleは、WireGuardをベースにした仕組みを使って、端末同士をプライベートネットワークのようにつなげられるサービスです。
Mac miniとMacBook Airの両方にTailscaleを入れておけば、外出先からでもMac miniへアクセスできます。
例えばSSHなら、
ssh mac-mini
という感覚です。
通常、自宅のPCへ外部から接続しようとすると、
- ルーターのポート開放
- グローバルIPアドレスの確認
- DDNS
- ファイアウォール設定
- SSHをインターネットへ公開する際のセキュリティ対策
などを考える必要があります。
Tailscaleを使うことで、このあたりをかなりシンプルにできます。
個人的には、この「ネットワークをあまり意識せず、自分の端末同士をつなげられる」感覚が非常に気に入っています。
SSHだけでも便利。でもHerdrを組み合わせるともっと快適
Tailscale経由でSSH接続できるだけでも十分便利です。
ただ、SSHだけの場合は基本的に、
Mac miniのターミナルを遠隔操作する
という使い方になります。
そこで今回、組み合わせているのがHerdrです。
Herdrは、ターミナルを中心にワークスペースを構築できるツールです。
タブやペインを使って複数のターミナルを管理できますが、特に面白いと思ったのがRemote機能でした。
例えばMacBook Airから、
herdr --remote mac-mini
のように接続します。
すると、
Mac miniへSSHしてからHerdrを起動する
というより、
Mac mini側の環境を、MacBook AirにあるHerdrから操作する
という感覚にかなり近くなります。
「昨日の続き」が、そのまま残っている
この環境を作って一番便利だと感じたのが、端末を変えた感覚がほとんどなくなったことです。
例えば夜、自宅でMac miniを使いながらClaude Codeに実装をお願いしていたとします。
途中まで開発を進めて、
「今日はここまで」
と終了します。
翌日、外出先でMacBook Airを開きます。
HerdrからMac miniへ接続します。
すると、基本的には昨日まで触っていたMac mini上の環境の続きを、そのまま操作できます。
端末が変わったからといって、
git clone
したり、
npm install
したり、
Node.jsのバージョンを確認したり、環境変数を設定したりする必要はありません。
当然といえば当然です。
そもそも違うコンピューターで開発していないからです。
sequenceDiagram
participant Home as 自宅
participant Mini as Mac mini
participant Agent as Coding Agent
participant Outside as 外出先
participant Air as MacBook Air
Home->>Mini: 開発を開始
Mini->>Agent: Claude Code / Codexで作業
Agent-->>Mini: 実装・調査
Home->>Mini: 作業を中断
Note over Mini,Agent: 開発環境はMac mini側に残る
Outside->>Air: MacBook Airを開く
Air->>Mini: Tailscale + Herdrで接続
Mini-->>Air: 同じ開発環境を表示
Air->>Agent: 昨日の続きを再開
これが思っていた以上に快適でした。
コーディングエージェントとの相性がいい
特に相性がいいと感じているのが、最近利用することが増えたコーディングエージェントです。
Claude CodeやCodexなどを利用していると、一つのターミナルセッションを比較的長く使うことがあります。
例えば、
- 実装を依頼する
- コードを確認する
- テストする
- エラーを確認する
- 原因を調査してもらう
- 修正する
- 再度テストする
という流れです。
これまでの開発では、
「コードをGitで同期する」
ことが重要でした。
しかしコーディングエージェントを利用するようになると、それに加えて、
「作業しているセッションそのものを維持する」
ことの価値が大きくなってきたように感じます。
そこで、
コーディングエージェントが動いているコンピューターそのものを固定する。
という考え方が非常にしっくりきました。
MacBook Airを「もう一台の開発機」と考えるのではなく、
Mac mini上の開発環境へアクセスするためのクライアント
として考えるわけです。
開発環境を二重に持たなくていい
もう一つ大きなメリットがあります。
それは、MacBook Air側に開発環境をすべて構築しなくてもよくなることです。
例えば、
- Node.js
- Python
- Docker
- 各種CLI
- AI系CLI
- データベース
- SDK
- ローカルLLM
- プロジェクトごとの依存パッケージ
などを複数端末で管理していると、
「Mac miniでは動くのにMacBook Airでは動かない」
ということが起きます。
開発者なら一度は、
「あれ、この端末には入れてなかった」
という経験があるのではないでしょうか。
開発環境をMac miniへ寄せることで、こうした端末間の差分もかなり減らせます。
SSH接続では少しハマった
もちろん、すべてが一発で動いたわけではありません。
今回少しハマったのが、SSH接続時のターミナル環境です。
普段はGhosttyを利用しています。
SSH接続自体は成功しているのですが、Mac mini側へ接続した際、一部のキー入力などが正常に動かないことがありました。
SSH Configは、おおむね以下のような設定です。
Host mac-mini
HostName mac-mini
User <username>
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
ServerAliveInterval 30
ServerAliveCountMax 3
SendEnv LANG LC_*
原因を切り分けていったところ、ターミナルのTERM周辺の扱いが関係していました。
環境によっては、
TERM=xterm-256color ssh mac-mini
のようにTERMを明示すると改善する場合があります。
リモート開発環境は、
flowchart TD
Terminal["ターミナルエミュレータ<br>Ghosttyなど"]
SSH["SSH"]
Shell["Shell<br>zshなど"]
TERM["TERM / terminfo"]
App["Herdr / CLIアプリ"]
Terminal --> SSH
SSH --> Shell
Shell --> TERM
TERM --> App
のように複数のレイヤーが関係しています。
そのため、
SSH自体は接続できるのに、キー入力や画面描画だけがおかしい
ということも起こります。
少しハマりましたが、こういうところを一つずつ調べていくのも環境構築の面白いところではあります。
Mac miniを「母艦」にするという考え方
今回の環境を作ってから、Mac miniに対する考え方が少し変わりました。
これまでは、
Mac mini
= 自宅で使うPC
MacBook Air
= 外出先で使うPC
という認識でした。
現在は、
Mac mini
= 自分のコンピューティング環境
MacBook Air
= そこへアクセスするためのクライアント
という感覚に近くなっています。
CPU、メモリ、ストレージ、開発環境をMac miniに寄せます。
そして必要になったら、別の端末から接続します。
flowchart TB
DEV["自分の開発環境"]
DEV --> MINI["Mac mini<br>CPU / Memory / Storage"]
MINI --> PROJECT["Projects"]
MINI --> AGENTS["AI Coding Agents"]
MINI --> LLM["Local LLM"]
MINI --> SERVER["Development Servers"]
AIR["MacBook Air"] --> MINI
PHONE["iPhone"] --> MINI
FUTURE["その他の端末"] --> MINI
この構成は、今後さらに面白くなりそうです。
ローカルLLM時代にも相性が良さそう
特に期待しているのが、ローカルLLMです。
最近はMacでも、かなり大きなモデルを動かせるようになってきています。
ただし、大きなモデルを動かそうとすると当然、
- メモリ
- ストレージ
- CPU / GPU性能
が必要になります。
すべての端末を高性能にする必要はありません。
例えば将来的に、
大容量メモリを搭載したMac miniやMac Studioを1台用意して、そこへすべての端末からアクセスする
という構成も現実的になってきます。
flowchart LR
Client1["MacBook Air"]
Client2["iPhone"]
Client3["iPad"]
Tail["Tailscale"]
Host["Mac mini / Mac Studio"]
LLM["Local LLM"]
Dev["Development"]
Agent["AI Agent"]
Client1 --> Tail
Client2 --> Tail
Client3 --> Tail
Tail --> Host
Host --> LLM
Host --> Dev
Host --> Agent
クラウド上にGPUインスタンスを立てる方法もありますが、自宅にあるMacを使えば、追加のクラウド料金をかけずに自分専用の計算環境を持つこともできます。
iPhoneからもアクセスできる
Tailscaleが入っていれば、iPhoneからMac miniへアクセスすることもできます。
もちろん、iPhoneで長時間プログラミングをしようとは思いません。
ただ、
- コーディングエージェントの処理が終わったか確認する
- ログを見る
- サーバーの状態を確認する
- 簡単なコマンドを実行する
- AIエージェントへ追加で指示する
といった用途では意外と便利です。
MacBook Airを開くほどではないけれど、ちょっとだけ確認したい。
そんな場面でも、自宅のMac miniへアクセスできるようになりました。
開発環境は「端末」ではなく「場所」になる
今回HerdrとTailscaleを組み合わせてみて、一番大きく変わったのは技術そのものよりも、開発環境に対する考え方でした。
以前は、
このMacに開発環境を作る。
という考え方でした。
今は、
自分の開発環境がどこかにあって、必要な端末からそこへアクセスする。
という考え方ができます。
AIによって変わるのは、コードの書き方だけではない
ここ数年、生成AIやコーディングエージェントによって、
「どうコードを書くのか」
は大きく変わりました。
しかし最近は、それだけではないのではないかと思っています。
AIエージェントが長時間動き、ローカルLLMが常駐し、複数の処理が並列で動くようになってくると、
「どこでコードを書くか」
よりも、
「どこでAIやコードを動かしておくか」
の方が重要になるかもしれません。
そう考えると、
高性能なマシンを1台置いておき、必要な場所からアクセスする。
という昔からある考え方が、AI時代になって再び面白くなってきます。
Herdr × Tailscaleによる今回の構成は、まだ使い始めたばかりです。
それでも、
Mac miniを母艦にして、必要な場所からそこにつなぐ。
というスタイルは、かなり気に入っています。
しばらくこの環境で、開発を続けてみようと思います。



