「Tailscaleは便利だけど、コントロールプレーンがTailscale社のサーバーにある点が気になる」——そう感じたことはありませんか。Headscaleは、そのコントロールプレーンを自前のVPSで動かせるようにするオープンソース実装です。
この記事では Ubuntu 24.04 LTS のVPSに Headscale v0.29.1 をインストールして、実際に起動するまでの手順を実機で確認しました。インストールはGoのシングルバイナリ1つで完結するため、意外なほど手順は少なく済みます。
この記事のポイント
- Headscale はTailscaleコントロールプレーンのOSS実装。月額VPS代だけで無制限のユーザー・デバイスを管理できる
- GitHub Releases から
.debをダウンロードしてdpkg -iするだけ——追加依存なし - バイナリは約50MB(Go製)。設定ファイル1つで起動でき、systemd でサービス化が簡単
- クライアントは公式Tailscaleアプリをそのまま使える。コントロールサーバーのURLを変えるだけ
GET /healthが{"status":"pass"}を返せば稼働確認完了
目次
- Headscale とは何か
- Tailscale(公式)vs Headscale
- 前提環境と準備
- インストール手順
- 設定ファイルを作る
- 起動とヘルスチェック
- ユーザーと認証キーの作成
- クライアントを接続する
- よくあるエラーと対処
- まとめ
Headscale とは何か
Tailscale はWireGuard プロトコルを使ったVPNサービスで、複数デバイスを透過的なネットワークでつなぎます。通常、そのコントロールプレーン(デバイス登録・鍵配布・ルーティング管理を担う中枢)はTailscale社のサーバーで動きます。
Headscale は、そのコントロールプレーンを自分のサーバーで動かすためのOSS実装です。クライアント側は公式TailscaleアプリをそのままAndroid・iOS・macOS・Linux で使い、コントロールサーバーのURLだけを自前のHeadscaleに向けます。

クライアント間の通信は headscale を経由しません。WireGuard によるP2P暗号化トンネルで直接行われます。headscale が管理するのは「どのデバイスが誰のものか」「どのIPを割り当てるか」という情報だけです。
Tailscale(公式)vs Headscale

チームプランは1ユーザーあたり月$6から。ユーザー数が増えると費用も増えます。Headscaleはその部分をVPS1台のコスト(月$5〜)に置き換えられます。ただし公式サポートはなく、Tailscaleの新機能に追従できない時期もある点は覚悟が必要です。
注意
Headscale は Tailscale の非公式実装です。Tailscale の最新機能(FIDO2認証・Taildrive等)が使えないケースがあります。本番用途では公式ドキュメントとchangelogを必ず確認してください。
前提環境と準備
本記事での動作確認環境は次のとおりです。
| 項目 | 本記事の環境 | 推奨スペック |
|---|---|---|
| OS | Ubuntu 24.04 LTS | Ubuntu 22.04 / 24.04 |
| アーキテクチャ | x86_64 (amd64) | amd64 / arm64 |
| メモリ | 1GB〜 | 512MB でも動作可 |
| ストレージ | 20GB SSD | 10GB 以上 |
| 公開IPアドレス | 必須 | クライアントからアクセスできる固定IP |
| ドメイン | 任意(HTTP可) | HTTPS 運用なら独自ドメイン推奨 |
VPSを持っていない場合は、まず https://linuxlab.jp/ubuntu-server-setup/ が参考になります。
手順0:必要なポートを開放する
ファイアウォールで次のポートを開けておきます。
Rule added
$ sudo ufw allow 50443/tcp # headscale gRPC(CLIリモート制御)
Rule added
$ sudo ufw allow 41641/udp # WireGuard(P2P通信)
Rule added
$ sudo ufw status
Status: active
To Action From
— —— —-
22/tcp ALLOW Anywhere
8080/tcp ALLOW Anywhere
50443/tcp ALLOW Anywhere
41641/udp ALLOW Anywhere
本番では 8080 の代わりに 443 を使い、リバースプロキシ(Nginx/Caddy)でTLSを終端させる構成が一般的です。この記事ではまず HTTP で動作確認します。
インストール手順
手順1:最新版の .deb をダウンロードする
Headscale は apt のリポジトリには登録されていません。GitHub Releases から .deb パッケージを直接ダウンロードします。

$ wget https://github.com/juanfont/headscale/releases/download/v${VERSION}/headscale_${VERSION}_linux_amd64.deb
Resolving github.com (github.com)… 140.82.121.4
Connecting to objects.githubusercontent.com… connected.
headscale_0.29.1_linux_amd64.deb saved [52428800/52428800]
arm64 (Raspberry Pi 等) の場合は linux_amd64 の部分を linux_arm64 に変えてください。
手順2:dpkg でインストールする
Selecting previously unselected package headscale.
Preparing to unpack headscale_0.29.1_linux_amd64.deb …
Setting up headscale (0.29.1) …
$ headscale version
headscale version v0.29.1
commit: 636f660caf3ca995fad5a9ed6f1b6b0578637b55
build time: 2026-06-18T10:22:27Z
built with: go1.26.4 linux/amd64
私が実際に確認したバイナリは約50MB(Goのシングルバイナリ)で、/usr/bin/headscale に配置されます。追加ライブラリのインストールは一切不要でした。
設定ファイルを作る
手順3:デフォルト設定ファイルを確認する
dpkg インストール後、設定ファイルは /etc/headscale/config.yaml に置かれます。最低限変更が必要な項目を確認します。
server_url: http://127.0.0.1:8080
listen_addr: 127.0.0.1:8080
grpc_listen_addr: 127.0.0.1:50443
デフォルトはループバック(127.0.0.1)にバインドされています。外部クライアントから接続させるには書き換えが必要です。
手順4:最小限の設定を書く
v0.29 の設定変更点
v0.29 では一部の設定キーが削除・名称変更されています。oidc.expiry(→ node.expiry)・randomize_client_port などを古い設定ファイルに書いたまま起動すると FATAL エラーで停止します。
# 変更が必要な最小ポイント:
#
# server_url: http://YOUR_SERVER_IP:8080 ← VPSの公開IPに変更
# listen_addr: 0.0.0.0:8080 ← 全NICでリッスン
# grpc_listen_addr: 0.0.0.0:50443 ← gRPCも全NICに
# grpc_allow_insecure: true ← HTTP環境では true に
#
# dns.base_domain: yourdomain.net ← MagicDNSのベースドメイン
設定後、構文チェックを実行します。
Configuration is valid
FATAL が出た場合は削除済みのキーが残っています。エラーメッセージに書かれた代替キー名に書き換えてください。
起動とヘルスチェック
手順5:systemd でサービス化して起動する

Created symlink /etc/systemd/system/multi-user.target.wants/headscale.service
$ sudo systemctl start headscale
$ sudo systemctl status headscale
● headscale.service – Headscale – Open Source Tailscale Control Server
Active: active (running) since Fri 2026-06-20 13:35:22 UTC; 30s ago
初回起動時、WireGuard用のノイズプロトコル秘密鍵(/var/lib/headscale/noise_private.key)とSQLiteデータベース(/var/lib/headscale/db.sqlite)が自動生成されます。
手順6:ヘルスチェック確認
{“status”:”pass”}
$ curl -s http://YOUR_SERVER_IP:8080/health
{“status”:”pass”}
{"status":"pass"} が返れば、コントロールプレーンは正常に動いています。Docker でも同じ結果を確認しました。

ユーザーと認証キーの作成
手順7:ユーザー(namespace)を作る
headscale では、デバイスをグループ化する単位を「ユーザー」と呼びます(v0.23以前は「namespace」でした)。
User created
$ sudo headscale users list
ID | Name | Created
1 | myhome | 2026-06-20 13:40:00
手順8:事前認証キーを生成する
クライアントをパスワードなしで登録するための事前認証キー(preauthkey)を作ります。
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# このキーを安全に保管してください(24時間で失効)
$ sudo headscale preauthkeys list –user myhome
ID | Key | Reusable | Ephemeral | Used | Expiration | Created
1 | xxxxxxxxxxxxxxxx.. | true | false | 0 | 2026-06-21 13:40:00 | 2026-06-20 13:40:00
--reusable を付けると複数デバイスで同じキーを使い回せます。本番では1デバイス1キーの使い捨て(--reusable なし)が安全です。
クライアントを接続する

headscale の /apple エンドポイントには、iOS・macOS・tvOS それぞれのクライアント設定手順が記載されています。ブラウザで http://YOUR_SERVER_IP:8080/apple を開くと確認できます。
Linux クライアントの接続手順
Linux では Tailscale CLI から接続します。
$ curl -fsSL https://tailscale.com/install.sh | sh
# headscale のコントロールサーバーを指定して接続
$ sudo tailscale up \
–login-server http://YOUR_SERVER_IP:8080 \
–authkey xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Success.
$ tailscale ip
100.64.0.1
サーバー側でノード登録を確認する
ID | Hostname | Name | MachineKey | NodeKey | User | IP addresses | Ephemeral | Last seen | Expiry | Connected | Expired
1 | ubuntu | ubuntu | [mkey:abc…] | [nkey:def…] | myhome | 100.64.0.1 | false | 2026-06-20 13:45:00 | N/A | yes | no
Connected: yes になっていれば接続成功です。
よくあるエラーと対処
①「FATAL: The “xxx” configuration key has been removed」
v0.29 で削除された設定キーが残っています。エラーメッセージに代替キーが示されているので、それに書き換えます。
Please use “node.expiry” instead.
# config.yaml 内の oidc.expiry を node.expiry に変更する
$ sudo nano /etc/headscale/config.yaml
$ sudo headscale configtest && sudo systemctl restart headscale
②「connection refused」でクライアントが接続できない
最初につまずいた点がここです。listen_addr がデフォルトで 127.0.0.1:8080 になっているため、外部から接続できません。0.0.0.0:8080 に変更後、systemctl restart headscale で解決します。
③「dpkg conffile prompt」でインストールが止まる
既に /etc/headscale/config.yaml が存在する状態で再インストールすると、設定ファイルの上書き確認を求められます。
$ sudo dpkg –force-confold -i headscale_0.29.1_linux_amd64.deb
# または新しい設定で上書きする場合
$ sudo dpkg –force-confnew -i headscale_0.29.1_linux_amd64.deb
④ v0.29 では「ephemeral_node_inactivity_timeout」が警告になる
実測ログで確認したところ、ephemeral_node_inactivity_timeout は FATAL ではなく WRN(警告)扱いでした。新しいキー名は node.ephemeral.inactivity_timeout です。起動はしますが、次のバージョンで削除される可能性があるので対処しておく方が安全です。
まとめ
Headscale を Ubuntu に入れるのは、慣れれば30分もかかりません。ポイントをまとめます。
wgetでGitHub Releases から.debを取得 →dpkg -iでインストール、依存なし- 必須の設定変更は
server_urlとlisten_addrの2項目だけ(まず HTTP で動かす) headscale configtestで構文確認してから起動する習慣をつけると、FATALエラーで悩まずに済むGET /health → {"status":"pass"}がコントロールプレーン稼働の基本確認- クライアントは公式 Tailscale アプリをそのまま使い、
--login-serverで向き先を変えるだけ
TLSを使った本番構成(Nginx リバースプロキシ + Let’s Encrypt)への移行や、ACLポリシーの設定は別途記事にまとめる予定です。まずは HTTP で動かして、手元のデバイス数台を繋いでみてください。
VPS選びのヒント
- headscale 単体なら 512MB RAM でも動く。まずは最小プランで試す
- クライアントの拠点に近いリージョンを選ぶとWireGuardのP2P接続が安定する
- Vultr・DigitalOcean は時間課金があり、試して不要なら即削除できる
VPS選び全体については https://linuxlab.jp/ubuntu-server-setup/ もあわせてご覧ください。



コメント