Tailscaleは、迅速なセットアップとほぼゼロ構成のWireGuard設定により、メッシュVPNを構築する際の最有力な選択肢です。しかし、無料のSaaS版には3ユーザーおよび100台のデバイスという制限があります。厳格なセキュリティポリシーを持つ企業や、多数のノードを抱えるホームラボにとって、ルーティングメタデータのすべてをサードパーティのサーバーに送信することは最適な選択とは言えません。Headscaleはこの課題を解決します。Tailscaleクライアントと完全な互換性を持つ、独立したオープンソースのcoordination serverです。
サーバー環境において、Fedoraは最新のカーネル6.x、カーネルレベルで組み込まれたWireGuardモジュール、そしてSELinuxによる強固なセキュリティにより高い評価を得ています。以下に、Fedora Server 39/40上でHeadscaleを実際にデプロイする手順を解説します。
1. クイックスタート:5分でHeadscaleをデプロイ
IPアドレス 203.0.113.10(またはAレコードがこのIPを指しているドメイン vpn.example.com)が割り当てられた、クリーンなFedora Serverが準備されている前提で進めます。
ステップ1:バイナリのダウンロードとシステム権限の設定
# 最新の安定版リリースを取得
HEADSCALE_VERSION=$(curl -s https://api.github.com/repos/juanfont/headscale/releases/latest | grep tag_name | cut -d '"' -f 4 | sed 's/v//')
wget https://github.com/juanfont/headscale/releases/download/v${HEADSCALE_VERSION}/headscale_${HEADSCALE_VERSION}_linux_amd64 -O /usr/local/bin/headscale
chmod +x /usr/local/bin/headscale
# セキュリティ向上のため、ログインシェルを持たないサービスユーザーを作成
useradd --system --shell /sbin/nologin --create-home headscale
mkdir -p /etc/headscale /var/lib/headscale /var/run/headscale
chown -R headscale:headscale /etc/headscale /var/lib/headscale /var/run/headscale
ステップ2:最小限の設定ファイルを作成
基本設定を記述した /etc/headscale/config.yaml ファイルを作成します:
cat <<'EOF' > /etc/headscale/config.yaml
server_url: http://203.0.113.10:8080
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 127.0.0.1:9090
grpc_listen_addr: 127.0.0.1:50443
grpc_allow_insecure: true
prefixes:
v4: 100.64.0.0/10
v6: fd7a:115c:a1e0::/48
derp:
server:
enabled: false
urls:
- https://controlplane.tailscale.com/derpmap/default
auto_update_enabled: true
update_frequency: 24h
disable_check_updates: true
ephemeral_node_inactivity_timeout: 30m
database:
type: sqlite3
sqlite:
path: /var/lib/headscale/db.sqlite
EOF
ステップ3:systemdサービスの起動とファイアウォールの開放
cat <<'EOF' > /etc/systemd/system/headscale.service
[Unit]
Description=Headscale Coordination Server
After=network.target
[Service]
User=headscale
Group=headscale
ExecStart=/usr/local/bin/headscale serve
Restart=always
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now headscale
# firewalldで調整ポート8080を開放
firewall-cmd --add-port=8080/tcp --permanent
firewall-cmd --reload
ステップ4:ユーザー作成と最初のノードの接続
管理用ユーザー(以前はnamespaceと呼ばれていました)を作成します:
headscale users create devteam
クライアント端末(tailscale パッケージインストール済み)に切り替え、自前のサーバーを指定して認証コマンドを実行します:
tailscale up --login-server http://203.0.113.10:8080
ターミナルに mkey:0123456789abcdef... のような認証キーが表示されます。このキーをコピーし、Fedoraサーバーのターミナルに戻って登録を承認します:
headscale nodes register --user devteam --key <クライアントからのNODE_KEY>
クライアント上で tailscale status を実行して確認します。端末に 100.64.x.x の範囲のIPが割り当てられ、接続が完了しているはずです。
2. 動作の仕組み:Headscaleが安全かつ軽量な理由
コントロールプレーンとデータプレーンの分離
OpenVPNやIPsecのような従来のVPNモデルは、すべてのトラフィックを中央サーバーに集中させるハブ&スポーク型(Hub-and-Spoke)を採用しています。この場合、サーバーがボトルネックになったりダウンしたりすると、すべての接続が麻痺します。これに対してWireGuardのメッシュアーキテクチャは、役割を明確に分離しています:
- データプレーン(実際のトラフィック):暗号化されたデータはクライアントAとクライアントBの間でピアツーピア(Peer-to-Peer)で直接流れます。同じラボ内にある2台のマシン間でのファイル転送であれば、LANポートの上限速度(1〜10 Gbps)を最大限に引き出せます。Headscaleサーバーが中継して復号することもなく、トラフィックの負荷がかかることもありません。
- コントロールプレーン(調整サーバー):Headscaleは公開鍵の保持、内部IPの割り当て管理、NATトラバーサル(STUN)のサポートのみを担当します。2つのノードが互いを見つけて暗号化セッションを確立した後は、仮に調整サーバーを停止しても、確立済みのマシン間通信は通常どおり継続します。
押さえておくべき3つの重要設定パラメータ
server_url:クライアントがコントロールサーバーに接続するためのパブリックアドレスです。NginxやCaddyなどのリバースプロキシ経由でHTTPS運用する場合は、正規のドメインURL(例:https://headscale.company.internal)に変更する必要があります。インターネット外部から接続するクライアントがいる場合、ここにプライベートIPを設定してはいけません。prefixes.v4:メッシュネットワークに割り当てるIPレンジです。TailscaleではRFC 6598で定義されているCGNAT帯(100.64.0.0/10)を採用しています。この設定を維持することで、自宅ネットワーク(192.168.1.0/24)やオフィスネットワーク(10.0.0.0/8)とIPアドレスが競合する心配がなくなります。derp.urls:パブリックDERPリレーサーバーのリストです。両方のクライアントがSymmetric NAT(4G/5G回線や公衆Wi-Fiなどの対称型NAT)配下にあり、UDPホールパンチングによる直接通信ができない場合、Headscaleは中継用のDERPサーバーを介してパケットを転送し、接続を維持します。
3. 本番環境向けの詳細設定
事前認証キー(Pre-auth Key):CI/CDとサーバー接続の自動化
Kubernetesのワーカーノード構築やステージング環境の仮想マシンを自動生成する際、ノードを作成するたびに手動で mkey をコピーするのは現実的ではありません。その解決策として、あらかじめ再利用可能な認証キーを発行しておきます:
# 開発環境向けに24時間有効な再利用可能キーを作成
headscale preauthkeys create --user devteam --reusable --expiration 24h
生成されたキーをcloud-initスクリプトやデプロイパイプラインに組み込みます:
tailscale up --login-server http://203.0.113.10:8080 --authkey <PREAUTH_KEY> --accept-routes
Subnet Router:ノードをLANへのブリッジとして活用する
ネットワークプリンター、マネージドスイッチ、IPカメラなど、多くのデバイスはTailscaleのインストールに対応していません。そこで、Fedora Serverノード自体をゲートウェイ(Subnet Router)として設定すれば、外部からでも 192.168.1.0/24 ネットワーク全体にアクセスできるようになります。
# 1. カーネルレベルでパケット転送を有効化
echo 'net.ipv4.ip_forward = 1' | tee -a /etc/sysctl.d/99-tailscale.conf
echo 'net.ipv6.conf.all.forwarding = 1' | tee -a /etc/sysctl.d/99-tailscale.conf
sysctl -p /etc/sysctl.d/99-tailscale.conf
# 2. 内部LANレンジのアドバタイズを要求
tailscale up --login-server http://203.0.113.10:8080 --advertise-routes=192.168.1.0/24
# 3. Headscale側でルートを承認
headscale routes list
headscale routes enable -r 1
これで、カフェなどの外部環境からでもTailscaleを有効にしたノートPCから、自宅ルーターのポートを一切開放することなく、https://192.168.1.50:8006 にあるProxmoxダッシュボードへ直接アクセスできるようになります。
アクセスコントロールリスト(ACL)によるアクセス制御
ACLを設定しない場合、同じユーザーに属するすべてのノード間で無制限に通信が可能です。権限を厳密に制限したい場合(例:開発チームに対してWebサーバー群のポート80/443へのアクセスのみを許可するなど)、/etc/headscale/acl.json を作成します:
{
"acls": [
{
"action": "accept",
"src": ["devteam"],
"dst": ["tag:web:80,443"]
}
],
"tagOwners": {
"tag:web": ["devteam"]
}
}
設定ファイルに acl.policy_path: /etc/headscale/acl.json のパスを指定してサービスを再読み込みします。これにより、webタグが付けられたノードへのSSH(ポート22)やデータベース(ポート5432)へのアクセス試行はすべて即座にドロップされます。
4. 運用ノウハウとトラブルシューティング
P2P接続の最適化:ダイレクト接続とリレー接続の違い
2つのノードがNATホールパンチングに成功し、リレーを経由せずにUDPで直接通信できるようにするには、サーバーのファイアウォールでデフォルトのWireGuardポートを開放しておくことを推奨します:
firewall-cmd --add-port=41641/udp --permanent
firewall-cmd --reload
通信状態を確認するため、クライアント端末で tailscale status を実行します:
# 理想的な接続状態(レイテンシ約15ms、帯域800Mbps以上)
100.64.0.2 workstation devteam linux active; direct 14.225.2.18:41641
# リレー経由となっている状態(レイテンシが90〜180msに急増、帯域は5〜15Mbpsに低下)
100.64.0.2 workstation devteam linux active; relay "hkg"
relay "hkg"(香港リレー)のような表示になっている場合は、ファイアウォールやルーターでUDPのアウトバウンド通信がブロックされていないか確認してください。
SQLiteデータベースの安全なホットバックアップ
ノード一覧、認証キー、ルーティングテーブルのすべてが /var/lib/headscale/db.sqlite という単一のファイルに保存されます。サーバーが書き込みを行っている最中に cp コマンドで単純コピーするとデータベース破損の原因になるため、SQLiteの安全なバックアップコマンドを使用します:
sqlite3 /var/lib/headscale/db.sqlite ".backup '/var/backups/headscale_$(date +%F_%H%M).sqlite'"
バックアップファイルのサイズは数百KB程度と非常に小さいため、毎日午前2時に実行するcronジョブなどに登録しておくと安心です。
FedoraクライアントにおけるMagicDNSの名前解決エラー対策
クライアントマシンからIPアドレス 100.64.0.2 へのpingは通るものの、ホスト名指定の ping workstation が解決できない場合、その原因の9割は systemd-resolved の設定競合にあります:
resolvectl status tailscale0
tailscale0 インターフェースがDNSサーバー 100.100.100.100 を正しく認識しているか確認してください。サーチドメインが設定されていない場合は、次のコマンドを実行してクライアント端末にTailscaleのDNSを強制的に優先させます:
resolvectl domain tailscale0 "~example.com"

