Headscale: プライベートなメッシュVPNネットワーク用Tailscaleコントロールプレーンを自前で構築する

Network tutorial - IT technology blog
Network tutorial - IT technology blog

デフォルトのTailscaleが抱える問題

Tailscaleは非常に便利だ——インストールしてログインするだけで、ファイアウォールを一切触らずにデバイス同士が繋がる。しかししばらく本番環境で使っていると、気になる点が見えてきた。コントロールプレーン全体がTailscale Inc.のサーバー上に存在しているのだ。デバイス情報、IPアドレス、ルーティングポリシーのすべてが、自分でコントロールできない第三者に依存している。

個人利用なら問題ない。だがGDPR、PDPA、または社内セキュリティポリシーなどのデータレジデンシー要件に従う必要がある企業にとって、これは過剰な心配ではなく、真剣に対処すべき問題だ。さらにフリープランは100台までという制限がある——多く聞こえるが、IoTやコンテナで規模を拡大するとあっという間に上限に達する。

そこでHeadscaleに移行した。TailscaleコントロールプレーンのオープンソースなImplementationで、自分のVPS上でセルフホストできる。

Headscaleとは何か、どう動くのか

Tailscaleはスプリットアーキテクチャモデルで動作しており、完全に分離した2つの部分で構成されている。

  • コントロールプレーン: デバイスリストの管理、キーの配布、認証、ACLポリシーを担当する。デフォルトではcontrolplane.tailscale.com上に存在する。
  • データプレーン: 実際のトラフィックはWireGuardを使ってピア間で直接やり取りされる(P2P)。コントロールプレーンはデータに触れない。

Headscaleはそのコントロールプレーン部分を置き換える。自分のサーバー上でホストし、各デバイス上のTailscaleクライアントはそのまま使える——Tailscaleのサーバーの代わりにHeadscaleサーバーを指すだけでいい。

より具体的に言うと、実際のトラフィックはHeadscaleを経由しない。データはWireGuardを通じてP2Pで直接やり取りされる——HeadscaleはあくまでBrokerとして機能し、公開鍵の配布、ノードリストの管理、認証処理を担う。処理が軽量なため、CPU 1コア・RAM 1GBのVPSで数十台のノードを余裕で捌ける。CPU使用率は通常5%以下だ。

VPS上にHeadscaleをインストールする

動作環境の要件

  • Ubuntu 22.04またはDebian 12が動作するVPS(筆者はUbuntu 22.04を使用)
  • VPSのIPに向けたドメイン(例: hs.example.com
  • ファイアウォールで443番と80番ポートを開放
  • リバースプロキシとしてNginxを使用(推奨)

ステップ1: Headscaleのダウンロードとインストール

# 最新バイナリをダウンロード(GitHubリリースでバージョンを確認すること)
wget https://github.com/juanfont/headscale/releases/download/v0.23.0/headscale_0.23.0_linux_amd64.deb

# インストール
sudo dpkg -i headscale_0.23.0_linux_amd64.deb

# バージョン確認
headscale version

ステップ2: Headscaleの設定

設定ファイルは/etc/headscale/config.yamlにある。開いて重要な項目を編集する:

server_url: https://hs.example.com

listen_addr: 0.0.0.0:8080
metrics_listen_addr: 127.0.0.1:9090

grpc_listen_addr: 0.0.0.0:50443
grpc_allow_insecure: false

private_key_path: /var/lib/headscale/private.key
noise:
  private_key_path: /var/lib/headscale/noise_private.key

ip_prefixes:
  - 100.64.0.0/10

derp:
  server:
    enabled: false   # TailscaleのDERPサーバーを使用(またはセルフホスト)
  urls:
    - https://controlplane.tailscale.com/derpmap/default

dns_config:
  nameservers:
    - 1.1.1.1
  domains: []
  magic_dns: true
  base_domain: mesh.example.com

db_type: sqlite3
db_path: /var/lib/headscale/db.sqlite

log:
  level: info

acme_url: https://acme-v02.api.letsencrypt.org/directory
acme_email: [email protected]
tls_letsencrypt_hostname: ""
tls_letsencrypt_cache_dir: /var/lib/headscale/cache
tls_letsencrypt_challenge_type: HTTP-01

server_urlには特に注意が必要だ——使用するドメインと完全に一致していなければならない。ここが間違っているとクライアントが接続できず、明確なエラーメッセージも出ないため、半日デバッグする羽目になる。

ステップ3: NginxリバースプロキシYAMLの設定

sudo apt install nginx certbot python3-certbot-nginx -y

# SSL証明書を取得
sudo certbot --nginx -d hs.example.com

/etc/nginx/sites-available/headscaleにNginx設定を作成する:

server {
    listen 80;
    server_name hs.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name hs.example.com;

    ssl_certificate /etc/letsencrypt/live/hs.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/hs.example.com/privkey.pem;

    location / {
        proxy_pass http://localhost:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_buffering off;
    }
}
sudo ln -s /etc/nginx/sites-available/headscale /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

ステップ4: Headscaleの起動

sudo systemctl enable headscale
sudo systemctl start headscale
sudo systemctl status headscale

Headscaleネットワークにデバイスを追加する

ユーザー(ネームスペース)の作成

Headscaleはデバイスをグループ化するために「ユーザー」という概念を使う:

# 新しいユーザーを作成
headscale users create myteam

# ユーザー一覧を表示
headscale users list

Linux/macOSデバイスの登録

接続したいマシン上で(通常通りTailscaleクライアントをインストール済みの状態で):

# TailscaleサーバーではなくHeadscaleサーバーを指定
tailscale up --login-server https://hs.example.com

このコマンドを実行すると認証用のURLが表示される。Headscaleサーバー側で次のコマンドで承認する:

# 承認待ちのノード一覧を取得
headscale nodes list --user myteam

# ノードを承認(NODE_KEYは上記の出力で確認したキーに置き換える)
headscale nodes register --user myteam --key NODE_KEY

数台程度なら手動承認でも問題ないが、大量デプロイ時はAuth Keyを使うと格段に楽になる:

# 再利用可能なAuth Keyを作成
headscale preauthkeys create --user myteam --reusable --expiration 24h

# クライアント側でAuth Keyを使用
tailscale up --login-server https://hs.example.com --authkey tskey-auth-XXXX

接続確認

# Headscaleサーバー側で確認
headscale nodes list

# 出力例:
# ID | Hostname    | Name        | MachineKey | NodeKey | User   | IP addresses         | Ephemeral | Last seen
# 1  | web-server  | web-server  | ...        | ...     | myteam | 100.64.0.1           | false     | 2026-04-25 10:30
# 2  | dev-laptop  | dev-laptop  | ...        | ...     | myteam | 100.64.0.2           | false     | 2026-04-25 10:31
# クライアント側で接続確認
tailscale status
tailscale ping 100.64.0.1

実際のデバッグ体験談

本番運用から約3ヶ月後、厄介な問題に遭遇した。ピーク時間帯——午前9〜11時と午後14〜16時——にのみ断続的なパケットロスが発生するのだ。Tailscaleのステータス上は接続が「up」のままなのに、レイテンシが5msから200ms以上に跳ね上がり、パケットがドロップする

最初はISPのネットワーク問題かと思った。しかしtailscale ping --verboseで確認すると、トラフィックがダイレクト(P2P)ではなくDERPサーバー経由でリレーされていることが判明した。NATトラバーサルが失敗し、2つのピアがお互いにパンチスルーできていなかったのだ。

解決策は、地理的に近い場所にDERPサーバーをセルフホストで追加し、可能な場合はダイレクト接続を強制するACLを設定することだった。それ以降は安定して動作している。

得た教訓: Tailscale/Headscaleは見た目はシンプルだが、内部ではWireGuard + DERP + NATトラバーサルが動いている。問題が発生した際はどのレイヤーで障害が起きているかを特定する必要があり、tailscale statusを見るだけでは不十分だ。

ACLポリシーの管理

HeadscaleはHuJSON形式のポリシー(Tailscale ACLと同様)をサポートしている。/etc/headscale/acl.yamlを作成する:

acls:
  # 開発チームは全てにアクセス可能
  - action: accept
    src: ["myteam:*"]
    dst: ["myteam:*:*"]

  # 本番サーバーは特定のノードからの接続のみ受け付ける
  - action: accept
    src: ["myteam:dev-laptop"]
    dst: ["myteam:prod-server:22,80,443"]
# ポリシーを適用
headscale policy set --path /etc/headscale/acl.yaml

まとめ

約30台のノードでHeadscaleを6ヶ月間本番運用した率直な感想: 安定して動作しており、信頼性も高い。Tailscaleに慣れていてセルフホストが必要な場合——プライバシー、コンプライアンス、あるいは単に100台制限を回避したい場合——Headscaleは現時点で最も成熟した選択肢だ。

Headscaleの最大のメリット: 各ノードのTailscaleクライアントは何も変更不要で、--login-serverを追加するだけでいい。Tailscale SSH証明書や一部の高度なACLタグなど、Tailscaleクラウドの機能の一部はまだ移植されていない。しかしサーバー接続、開発チーム、ホームラボといった用途であれば、機能的に不足を感じることは全くない。

実際の運用コスト: 30ノードのHeadscaleを動かすVPSは月$5——Tailscale Personal Proの月$6/ユーザーと比べると、小規模チームなら1〜2ヶ月でペイできる。さらにデータ主権という、金銭では計れないメリットもある。

Share: