ロゴ
システム開発・発注

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などを利用していると、一つのターミナルセッションを比較的長く使うことがあります。

例えば、

  1. 実装を依頼する
  2. コードを確認する
  3. テストする
  4. エラーを確認する
  5. 原因を調査してもらう
  6. 修正する
  7. 再度テストする

という流れです。

これまでの開発では、

「コードを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を母艦にして、必要な場所からそこにつなぐ。

というスタイルは、かなり気に入っています。

しばらくこの環境で、開発を続けてみようと思います。