クラウドなしの6ヶ月:Headscaleへの移行体験記
長年ホームラボ(HomeLab)を構築してきましたが、ある時「CGNAT」という壁にぶつかりました。Tailscaleは接続の問題を即座に解決してくれましたが、ネットワークのメタデータが企業のサーバーに保存されることに抵抗がありました。また、エンタープライズプランに移行することなく、無料プランの100ノード制限を回避したいとも考えていました。そこで、メッシュネットワーク全体をHeadscaleに移行することにしました。
Headscaleは、Tailscaleコントロールサーバーのオープンソースでセルフホスト可能な実装です。NATトラバーサル、WireGuardによるセキュリティ、シームレスなP2P接続といった、Tailscaleの優れた機能はそのままに、運用の「脳」にあたる部分を自前のハードウェアで管理できます。3つの拠点にある25台のデバイスで半年間運用してきましたが、私のシステムスタックの中で最も安定した部分になっています。
クイックスタート:5分で稼働させる
月額5ドルのVPSや古いローカルマシンがあれば、数分でHeadscaleを稼働させることができます。必要なのは、パブリックIPを持つLinuxホスト、または適切にポートフォワーディングされた環境だけです。
1. ディレクトリ構造の準備
まずは、設定ファイルとデータベースファイルを保存するための専用スペースを作成します。
mkdir -p ~/headscale/config
cd ~/headscale
touch config/config.yaml
2. Docker Composeファイルの作成
docker-compose.ymlファイルを作成します。軽量でセキュリティパッチの適用が早い公式イメージの使用をお勧めします。
services:
headscale:
image: headscale/headscale:latest
container_name: headscale
volumes:
- ./config:/etc/headscale
- ./data:/var/lib/headscale
ports:
- "8080:8080"
- "9090:9090"
command: headscale serve
restart: always
3. 基本設定
デフォルトのconfig.yamlはかなり長いですが、開始するために確認が必要なキー項目はわずかです。データベースのパスがDockerのボリューム設定と一致していることを確認してください。
server_url: http://<YOUR_SERVER_IP>:8080
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 0.0.0.0:9090
db_type: sqlite3
db_path: /var/lib/headscale/db.sqlite
derp:
urls:
- https://controlplane.tailscale.com/derpmap/default
docker-compose up -dを実行します。これで、あなた専用のプライベートなコントロールプレーンが稼働しました。
アーキテクチャの仕組み
Tailscaleはスプリットプレーン(分離プレーン)アーキテクチャを採用しています。データプレーンは実際のトラフィックを処理し、エンドツーエンドで暗号化され、通常はデバイス間で直接通信されます。一方、コントロールプレーン(Headscale)は、ノードの登録とキーの交換のみを管理します。
この構成が強力なのは、セキュリティをサードパーティの稼働状況から切り離せる点にあります。デバイスが参加すると、自分のDockerコンテナに問い合わせてピア(通信相手)を見つけます。もしパブリックなインターネットがダウンしても、ローカルデバイスがHeadscaleインスタンスにアクセスできれば、内部メッシュは完全に機能し続けます。
最初のユーザーを作成する
Headscaleでは「ユーザー」を使用してノードをグループ化します。最初のラップトップやスマートフォンを接続する前に、少なくとも1つのユーザーを作成する必要があります。
docker exec headscale headscale users create mynetwork
応用編:活用の幅を広げる
基本設定が完了したら、Headscaleをプロフェッショナルなネットワークツールへと進化させる機能を解放しましょう。
サブネットルーター:レガシーハードウェアへのアクセス
私は1080pのIPカメラ数台と、Tailscaleを実行できない古いBrother製プリンターを持っています。これを解決するために、Raspberry Pi 4をサブネットルーターにしました。これにより、外出先のカフェからでもスマホで192.168.1.0/24の範囲全体にアクセスできるようになります。
クライアントデバイスで以下を実行します:
tailscale up --login-server http://<YOUR_IP>:8080 --advertise-routes=192.168.1.0/24
次に、Headscaleサーバーでルートを有効にします:
docker exec headscale headscale nodes list
docker exec headscale headscale routes enable -r <ID>
Pre-Authキーによる自動化
一時的なDockerコンテナやCI/CDランナーを立ち上げる際、手動でのログインは面倒です。再利用可能なPre-Authキーを使用すれば、人の手を介さずに新しいノードを自動的にメッシュに参加させることができます。
docker exec headscale headscale preauthkeys create -u mynetwork --reusable --expiration 24h
本番環境で6ヶ月運用して得た教訓
半年間この構成に頼ってきたことで、安定したメッシュネットワークを維持するためのポイントがいくつか見えてきました。
- リバースプロキシを使用する: ポート8080を直接公開するのはリスクがあります。Nginx Proxy ManagerやCaddyを使用してHTTPS化しましょう。モバイルクライアントは、有効なSSL証明書を使用したポート443経由の方が、より安定して接続できます。
- データベースを保護する:
db.sqliteファイルはネットワークの心臓部です。これが破損すると、すべてのノードを手動で再認証しなければならなくなります。私は簡単なcronジョブを使って、毎晩NASにバックアップを取っています。 - MagicDNSを有効にする: Headscaleは内部DNSをサポートしています。100.64.x.xといったIPアドレスを何十個も覚えるよりも、
ssh proxmox.mynetwork.meshのように入力する方がはるかに簡単です。 - iOSの隠し設定: iPhoneでサーバーを変更するのは少しコツがいります。Tailscaleアプリを開き、設定に移動して、上部にある「Tailscale」ロゴを10回ほどタップしてください。すると、HeadscaleのURLを入力するための隠しフィールドが表示されます。
Headscaleへの切り替えは、私のホームラボにとって最良の選択でした。将来の価格改定に対する不安がなくなり、ネットワークマップを完全にコントロールできるようになりました。クラウドに縛られず、プライベートで高性能なVPNを求めているなら、これが正解です。

