HeadscaleでTailscaleのサーバーを自前運用する方法
VPS上でTailscaleのコントロールサーバーを自前運用します。公式の.debをインストールし、server_urlを設定して再起動後、最初のノードを参加させる手順を解説します。
headscale とは
headscale は Tailscale のコントロールサーバーを自分でホストする実装です。そのため、プライベートネットワークを調整するマシンを、自分が所有する VPS にできます。これはコミュニティプロジェクトであり、Tailscale Inc. が運営しているものではありません。各マシンでは公式の tailscale クライアントを引き続き実行し、1 つのフラグ --login-server で自分のサーバーを指定します。
コントロールサーバーは、ネットワークに所属するノードを把握する役割を担います。各ノードに 100.64.0.0/10 からアドレスを割り当て、公開鍵を配布し、他のノードの場所を通知します。トンネル自体は WireGuard のままで、ノード間に構築されます。2 台のマシン間のトラフィックは、直接経路を構築できず、ノードがリレーへフォールバックする場合を除き、headscale のサーバーを経由しません。この調整機能を自分で運用しても、担い手が変わるだけで、機能自体が変わるわけではありません。そのため、移行自体をセキュリティ上の改善とみなす前に、このモデルでコントロールサーバーから到達できるものとできないものを理解しておくことが重要です。
Headscale はインスタンスごとに 1 つの tailnet(1 つの Tailscale ネットワーク)を提供します。このプロジェクトでは、個人利用または小規模な組織に適していると説明されています。マシンが 3 台または 4 台であれば、自分で所有する VPS 上の単純な WireGuard VPN のほうが、運用するソフトウェアが少なく、壊れる箇所も少なくなります。新しいノート PC を追加するたびに [Peer] ブロックを手動で記述したくなくなった段階で、Headscale の導入効果が出てきます。費用がきっかけで調べ始めることも多いため、サーバーを用意する前に、ホスティング型の無料プランで実際に利用できる範囲を確認する価値があります。個人所有のマシンが少数であれば、通常は無料プランの範囲に収まります。すでにその上限を超えている場合は、ユーザーあたり、およびタグ付きリソースあたりの有料プランの料金と比較して計算してください。ユーザーデバイスは無制限ですが、タグ付きリソースには別の上限と料金が設定されています。自己ホスト型のコントロールプレーンを使用したい一方で、Tailscale のドロップイン置換ではなく、独自のクライアントとピア管理用の Web インターフェースを使いたい場合は、単一の VPS 上で動作する NetBird が検討に値する代替手段です。どちらも WireGuard 経由でトラフィックを転送するため、選択のポイントはアクセスルールの記述方法とリレーの動作です。導入前に、これらの点で NetBird と Tailscale を比較することをおすすめします。2 つのモデルをより広く比較する場合は、WireGuard と Tailscale の違いを参照してください。
インストール前に必要なもの
- パブリック IPv4 アドレスと sudo アクセス権を持つ Ubuntu 24.04 実行中の VPS。サーバーが新規の場合は、先に 新しい VPS で最初の 10 分に行う作業を完了してください。
- そのアドレスを指す DNS A レコード。このガイドでは
headscale.example.comを使用します。 - MagicDNS 用の別のドメインまたはサブドメイン。このガイドでは
tailnet.example.netを使用します。server_urlで使用するドメインと同じであってはなりません。 - 参加させるクライアントマシン 1 台。Linux、macOS、Windows、Android、iOS のいずれかを実行しているものを使用します。Headscale 0.29.6 には Tailscale client version 1.80.0 以降が必要です。
公式の .deb から headscale をインストールする
プロジェクトは GitHub の releases ページで .deb パッケージを公開しています。2026 年 10 月 27 日時点で、最新の安定版は 2026 年 10 月 24 日にリリースされた 0.29.6 です。ファイル名にアーキテクチャが含まれるため、最初に確認してください。
sudo apt update
sudo apt install -y wget
dpkg --print-architecture通常の x86 VPS では amd64、Ampere または Graviton 系プランでは arm64 と表示されます。結果を以下の変数に設定してください。
HEADSCALE_VERSION="0.29.6"
HEADSCALE_ARCH="amd64"
wget --output-document=headscale.deb \\
"https://github.com/juanfont/headscale/releases/download/v${HEADSCALE_VERSION}/headscale_${HEADSCALE_VERSION}_linux_${HEADSCALE_ARCH}.deb"
sudo apt install -y ./headscale.deb
headscale versionファイル名の前に ./ が必要です。これがないと、apt はリポジトリ内で headscale.deb というパッケージを探し、失敗します。
パッケージは headscale システムユーザーを作成し、デフォルトの /etc/headscale/config.yaml を書き込み、systemd unit をインストールしてからサービスを起動します。そのため、apt が戻る時点ですでに headscale は実行中で、sudo systemctl is-active headscale は active を表示します。ただし、新規インストールでは unit が有効化されないため、以下の再起動手順で有効化するまで、再起動後にサービスは自動的に起動しません。また、出荷時の設定で実行されており、server_url は http://127.0.0.1:8080 を指しています。これは、どのクライアントからも到達できないアドレスです。出荷時の listen_addr も loopback 上にあるため、まだ何も公開されていません。ただし、server_url を設定してサービスを再起動するまで、クライアントを接続しないでください。次の 2 つの手順でこれを行います。
クライアントが参加する前に server_url を設定する
/etc/headscale/config.yamlをsudo nano /etc/headscale/config.yamlで編集するか、sedで同じ3つの変更を適用します。元のファイルはコピーして保存してください。ファイルは長く、コメントも多いため、残りの設定を確認する際の最も重要な参考資料になります。
sudo cp /etc/headscale/config.yaml /etc/headscale/config.yaml.orig
sudo sed -i 's|^server_url:.*|server_url: https://headscale.example.com|' /etc/headscale/config.yaml
sudo sed -i 's|^listen_addr:.*|listen_addr: 127.0.0.1:8080|' /etc/headscale/config.yaml
sudo sed -i 's|^ base_domain:.*| base_domain: tailnet.example.net|' /etc/headscale/config.yaml
sudo grep -E '^(server_url|listen_addr):|^ base_domain:' /etc/headscale/config.yamlserver_urlは、headscale が登録 URL を生成するときに使用する公開アドレスです。クライアントは--login-serverで設定した制御アドレスを使用するため、両方に同じ公開名をhttps://とともに指定します。127.0.0.1は指定しないでください。headscale のドキュメントでは、通常の HTTP、または 443 以外のポートでの HTTPS も利用できると説明されています。ただし、本番環境では 443 番ポートの HTTPS を強く推奨しており、このガイドもそれを前提とします。
listen_addrはプロセスが待ち受けるアドレスです。loopback のままにします。同じサーバー上のリバースプロキシが TLS(トランスポート層セキュリティ)を終端し、そこへ転送します。そのため、サーバー外部から port 8080 に接続できる必要はありません。
base_domainは MagicDNS のサフィックスで、ノード名に使用するドメインです。末尾にドットを付けない完全修飾ドメイン名にする必要があります。また、server_urlに指定するドメインとは別にしてください。同じにすると、2つの名前空間が衝突します。
データベースのセクションは変更しません。デフォルトでは、パッケージが作成して所有するディレクトリの/var/lib/headscale/db.sqliteに SQLite が配置されます。この規模の tailnet には SQLite で十分です。
headscale を再起動し、実行中であることを確認する
sudo systemctl restart headscale
sudo systemctl enable headscale
sudo systemctl is-active headscale
sudo systemctl is-enabled headscale
curl -sS -o /dev/null -w '%{http_code}\\n' http://127.0.0.1:8080/healthis-active は active を出力し、is-enabled は enabled を出力し、curl は 200 を出力します。編集内容を読み込むのは再起動の処理です。headscale は起動時に 1 回だけ設定を読み込むため、パッケージによって起動されたプロセスは、再起動するまで配布時の server_url を使い続けます。sudo systemctl enable --now headscale ではこの処理は行われません。サービスはすでに実行中なので、--now の start では何も変わらず、古い値が有効なままです。ブート時の起動を設定するのは enable の役割であり、自動的には設定されません。新規インストールでは、パッケージはサービスを起動しますが、自動起動は有効にしないため、上記のとおり sudo systemctl enable headscale を 1 回実行してください。
is-active が active 以外を出力する場合、または curl が 200 を出力しない場合は、sudo journalctl -u headscale -n 50 --no-pager で journal を確認します。この段階での失敗は、ほぼ常に設定ファイルが原因です。headscale はソケットを開く前にファイル全体を解析するため、インデントの誤りや必須設定の無効な値があると、何も待ち受ける前にプロセスが停止します。ファイルを修正してから、sudo systemctl restart headscale を実行します。その後の設定変更でも、同じ再起動が必要です。クライアントはその後、自動的に再接続します。systemd の unit に慣れていない場合は、systemd で独自のサービスとタイマーを実行する方法で、ここで使うコマンドを説明しています。
シェルを開いている間に、状態ファイルも確認します。
stat -c '%U %n' /var/lib/headscale/db.sqlite /var/lib/headscale/noise_private.keyどちらの行も、パッケージが作成した非特権ユーザーである headscale で始まります。noise_private.key は、クライアントから見たサーバーの識別情報です。削除しないでください。削除すると、headscale は新しい識別情報を生成します。クライアントは再接続する前に、新しいサーバーキーを取得する必要があります。既存の登録情報はデータベースに残ります。
headscale の前段に TLS を配置する
クライアントは server_url に HTTPS で接続できる必要があります。Caddy が最も簡単です。証明書の取得と更新を自動的に行うためです。
sudo apt install -y caddy/etc/caddy/Caddyfile を headscale のドキュメントにあるブロックに置き換えます。
headscale.example.com {
reverse_proxy 127.0.0.1:8080 {
header_up True-Client-IP {remote_host}
header_up X-Real-IP {remote_host}
}
}sudo caddy validate --adapter caddyfile --config /etc/caddy/Caddyfile
sudo systemctl restart caddy
sudo systemctl is-active caddy構文が正しければ、validate は adapted config to JSON を出力します。ファイルがフォーマットされていないという警告は、見た目上の問題です。ラップトップから実行した場合も、curl -sS -o /dev/null -w '%{http_code}\\n' https://headscale.example.com/health は 200 を出力するはずです。この確認だけで、DNS、ファイアウォール、証明書、プロキシが連携して動作していることを確認できます。
ここで、設定を見落とすと復旧に長時間かかるプロキシの詳細を説明します。Tailscale の制御接続は HTTP upgrade であり、GET ではなく POST で開始されます。また、Upgrade ヘッダーの値は tailscale-control-protocol です。Caddy では追加設定なしでこれが転送されます。nginx では転送されないため、nginx を前段に置く場合は Upgrade ヘッダーと Connection ヘッダーを明示的に転送する必要があります。headscale のドキュメントでは、upgrade map を使って設定しています。
map $http_upgrade $connection_upgrade {
default keep-alive;
'' close;
}
server {
listen 443 ssl;
server_name headscale.example.com;
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $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_buffering off;
proxy_pass http://127.0.0.1:8080;
}
}この行を省略しても通常のリクエストは成功します。そのため、/health は 200 を返し、すべて正常に見えます。しかし、制御接続は確立されません。新しいノードは登録できず、既存のノードも再接続してオンライン状態を報告できません。nginx を使用する場合は、Ubuntu 24.04 の nginx で Certbot を使用するで証明書の設定方法を確認できます。
UFW で開放するポート
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose443 番ポートは、すべてのクライアントから headscale への制御接続を運びます。後で組み込みの DERP リレーを有効にする場合は、以下で説明する 3478/udp も必要です。80 番ポートは、ACME(自動証明書管理環境)の HTTP チャレンジと HTTPS へのリダイレクトに使用します。Caddy は、443 番ポートの TLS-ALPN チャレンジを使用できるため、80 番ポートを閉じていても証明書を取得できます。ただし、80 番ポートを開くと両方のチャレンジを利用でき、通常の http:// リクエストもリダイレクトされます。
8080 番ポートは閉じたままにします。listen_addr は 127.0.0.1:8080 なので、プロキシは loopback インターフェース経由で headscale に接続し、ファイアウォールルールは必要ありません。UFW で 8080 番ポートを開いても、外部から待ち受けるプロセスはないため何も公開されず、メリットもありません。多くのプロバイダーは、UFW とは別にコントロールパネル側でもファイアウォールを運用している点に注意してください。そのため、サーバー上ではポートが開いていても、ネットワークの境界では閉じている場合があります。VPS での UFW ファイアウォールの基本では、ルール構文を詳しく説明しています。
ユーザーと事前認証キーを作成する
sudo headscale users create alice
sudo headscale users listheadscale コマンドはクライアントです。実行中のデーモンと、/var/run/headscale/headscale.sock にある Unix ソケット経由で通信します。このソケットのモードは 0770 で、headscale グループが所有しています。ここから 2 つの点が分かります。サービスが停止しているとコマンドは失敗します。これが、このガイドで手順の順序が重要になるもう 1 つの理由です。また、アカウントを headscale グループに追加しない限り、sudo が必要です。
users list は各名前の横に ID を表示します。この番号が必要です。key コマンドは名前ではなく数値のユーザー ID を受け取るためです。
sudo headscale preauthkeys create --user 1 --expiration 24hキーは 1 回だけ表示されます。今すぐコピーしてください。特に指定しない限り、事前認証キーは 1 回だけ使用でき、有効期間は 1 時間です。そのため、テスト中は --expiration 24h を設定しておくと便利です。複数のマシンを登録するキーには --reusable を追加してください。このキーを持つ人は誰でもネットワークに参加できるため、パスワードと同じように扱ってください。
--login-server で最初のクライアントを接続する
参加させるマシン上で実行します。
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up --login-server https://headscale.example.com --auth-key 'hskey-auth-PASTE-YOUR-KEY-HERE'
tailscale status
tailscale ip -4tailscale ip -4 は、headscale が割り当てたアドレスを 100.64.0.1 のような形式で表示します。サーバーに戻り、sudo headscale nodes list を実行すると、ID、ユーザー、オンライン状態とともにノードが表示されます。
server_url の公開 HTTPS アドレスを --login-server に使用します。クライアントはコントロール URL の末尾にあるスラッシュを削除します。末尾のスラッシュを省略しなければならないような完全一致の比較はありません。
以前 Tailscale のホステッドサービスにサインインしていたマシンでは、そのログイン状態が保持されます。まず sudo tailscale logout を実行し、その後 --login-server を指定して tailscale up を実行します。
--auth-key を省略すると、クライアントは代わりに URL を表示します。その URL を開くと、登録試行の識別子がページに表示されます。サーバーで次のコマンドを実行して承認します。
sudo headscale auth register --user alice --auth-id PASTE-THE-ID-FROM-THE-PAGEこの方法は、自分のノート PC には適しています。スクリプト化する処理には、誰かが画面を監視する必要のない Preauth key のほうが適しています。VPS 自体をノードにすると、他のマシンのインターネットトラフィックも経由させられます。これは exit node の設定です。ただし、ホステッド環境の管理コンソールではなく、サーバー上で headscale コマンドを実行して広告されたルートを承認します。その VPS の外部へ出るのではなく、VPS の背後にあるプライベートネットワークへ接続したい場合も、同じ承認手順で そのサブネットを tailnet の他のノードへ広告できます。ネットワーク全体を経由させるのではなく、ノードから 1 つのアプリケーションだけを公開する場合は、さらに別の用途です。その方法は serve と funnel の 2 つですが、どちらも Tailscale 独自の証明書と ingress の仕組みに依存します。そのため、headscale が提供する機能ではなく、ホステッド tailnet の機能として扱ってください。
DERP と、直接経路が失敗したときにトラフィックを中継する仕組み
DERP(designated encrypted relay for packets)は、フォールバック経路です。2 台のノードが直接 WireGuard 接続を確立できない場合、通常は両方が厳格な NAT(network address translation)の背後にあるため、代わりにリレー経由でパケットを送信します。リレーは鍵を保持しないため、トラフィックの内容を読み取れません。ただし、どのノード同士が通信しているかと、移動したデータ量は把握できます。
デフォルト設定の動作を明確に理解してください。Headscale は https://controlplane.tailscale.com/derpmap/default を参照し、auto_update_enabled: true と update_frequency: 3h を使用する設定で出荷されます。そのため、コントロールプレーンは自分で管理し、リレーは Tailscale のものを使用する構成になります。多くの利用者にとって、これは妥当なトレードオフです。そうでない場合は、自分でリレーを運用してください。
独自のリレーを運用するには、config.yaml の derp.server の下に enabled: true を設定します。出荷時の ipv4: 198.51.100.1 と ipv6: 2001:db8::1 をリレーの公開アドレスに置き換えるか、両方の設定を削除して DNS を使用します。その後、headscale を再起動し、sudo ufw allow 3478/udp で STUN(session traversal utilities for NAT)ポートを開きます。これらのアドレス設定は DNS より優先されます。そのため、どちらか一方のプレースホルダーを残すと、クライアントは到達できないアドレスへ接続します。設定ファイルには要件が明記されています。server_url には https を使用する必要があります。DERP には TLS が必要だからです。derp.urls リストを空にすると、Tailscale のリレーがマップから削除されます。削除する前に、組み込みリレーまたはカスタムリレーが正常に動作することを確認してください。空のリレーマップでは Headscale は起動しません。また、到達不能なリレーだけを含むマップでは、直接接続できないノード同士が通信できなくなります。
クライアントで tailscale netcheck を実行すると、認識している各リレーリージョンへの遅延が表示されます。tailscale status を実行すると、アクティブなピア接続について、アドレス付きの direct またはリージョンコード付きの relay が表示されます。relay のままのピアでは、NAT とファイアウォールのルールを含め、直接経路を確認する必要があります。direct でありながら速度が遅いピアは、さらに別の問題です。その場合の一般的な原因は、トンネル自体ではなく MTU です。
ノードがオフラインと表示されるのはなぜですか?
プロキシが upgrade を破棄しています。 /health が 200 を返す一方で、新しい登録に失敗するか、既存のノードが再接続できない場合が該当します。制御接続は Upgrade: tailscale-control-protocol を含む POST です。これを転送しないプロキシは、登録とノード状態を報告するチャネルの両方を遮断します。nginx の設定を上記の upgrade 用の行と比較するか、Caddy に切り替えてプロキシが原因かどうかを切り分けます。
公開制御アドレスが変更されています。 ノードは --login-server で設定されたアドレスへ接続し続けます。server_url を変更しても、そのクライアント設定は更新されません。古いアドレスからサーバーに到達できなくなった場合は、各ノードで sudo tailscale up --login-server https://headscale.example.com --force-reauth を実行します。
クライアントが実行されていません。 ノードで sudo systemctl is-active tailscaled と sudo journalctl -u tailscaled -n 50 --no-pager を確認します。ドメインを名前解決できない、またはドメインへ到達できないクライアントは、そこで再試行のログを出力します。
key の有効期限が切れています。 次のセクションで説明します。
テスト中にサーバー側を監視するには、VPS で sudo journalctl -u headscale -f を実行し、クライアントで tailscaled を再起動します。クライアントの journal も確認してください。headscale に到達したリクエストが、デフォルトのログレベルで必ず記録されるとは限りません。そのため、サーバーログが出力されないことだけでは、DNS、ファイアウォール、またはプロキシの障害とは断定できません。
鍵の有効期限と、数週間後に動作しなくなるノード
有効期限は2種類あります。これらを混同すると、解決に時間がかかります。
Preauth keyは、設計上すぐに期限切れになります。デフォルトは1時間かつ1回の使用です。tailscale upが鍵を拒否した場合は、クライアント側を編集せず、サーバー上で新しい鍵を生成します。
Node keyは、長期間有効な側です。config.yamlのnodeセクションでexpiry: 0を設定し、0はデフォルトの有効期限がないことを意味します。ただし、クライアントが明示的に指定した有効期限やOIDCの有効期限は適用されます。タグ付けされたノードは自動的な有効期限の対象外ですが、管理者が明示的に期限切れにすることはできます。タグ付けされていない登録に180日のデフォルトを設定する場合はexpiry: 180dを設定します。ただし、クライアントが要求した有効期限が優先され、OIDCによってデフォルトが上書きされる場合もあります。この設定を変更しても、既存の登録には遡って適用されません。有効期限が設定されたノードは、その期限までにsudo tailscale up --login-server https://headscale.example.com --force-reauthを使用して再認証する必要があります。誰も再認証しないヘッドレスサーバーは、登録の期限が切れるとネットワークから切断されます。
ノートPCを紛失した場合は、手動で対応します。sudo headscale nodes listでIDを確認し、sudo headscale nodes expire -i 3でそのノードをログアウトさせ、sudo headscale nodes delete -i 3でネットワークから完全に削除します。
バックアップとアップグレード
/var/lib/headscale と /etc/headscale を合わせると、サーバー全体に相当します。コピーする前にサービスを停止してください。SQLite では書き込みが進行中の場合があり、負荷がかかった状態でコピーしたデータベースは不整合になる可能性があります。
sudo systemctl stop headscale
sudo tar czf /root/headscale-state.tgz -C /var/lib headscale
sudo tar czf /root/headscale-config.tgz -C /etc headscale
sudo systemctl start headscale
sudo chmod 600 /root/headscale-*.tgz両方のファイルをサーバーの外部へ移します。これらには秘密鍵とすべての登録情報が含まれるため、サーバー自体と同じように慎重に扱う必要があります。VPS からの restic バックアップでは、これを定期的かつ暗号化して実行する方法を説明しています。
アップグレードでは、インストール手順を繰り返します。新しい .deb と sudo apt install ./headscale.deb をダウンロードし、再起動してから is-active と /health のチェックを再実行します。0.29 以降のアップグレード経路は厳格です。マイナーバージョンを飛ばすことはできず、古いマイナーバージョンへのダウングレードもできません。マイナーバージョンを1つずつ上げ、各手順の前にバックアップを取得してください。また、同じリリースで ACL ポリシーの動作が変更され、複数の設定キーが移動しているため、最初に対象バージョンのリリースノートを確認してください。Version 0.29.6 には証明書検証と依存関係のセキュリティ更新も含まれているため、既存の 0.29 インストールではこのパッチリリースを適用してください。
FAQ
.deb をインストールした直後に headscale はすでに起動していますか?
はい。パッケージは、インストール時に同梱の /etc/headscale/config.yaml としてサービスを起動します。このサービスは loopback のみで待ち受け、server_url を http://127.0.0.1:8080 に設定します。新規インストール時はサービスを有効化しないため、sudo systemctl enable headscale を実行するまでブート時に起動しません。同梱のアドレスはクライアントから利用できないため、server_url、listen_addr、base_domain を編集し、その後 sudo systemctl restart headscale を実行して sudo systemctl is-active headscale で確認します。restart でなければなりません。headscale は起動時にのみファイルを読み込みます。また、すでに起動しているサービスで enable --now を実行するとブート時の起動は有効になりますが、サービスは再起動されないため、古い値が有効なままになります。再起動後に失敗した場合は、sudo journalctl -u headscale -n 50 --no-pager で問題を確認できます。この段階での原因は、headscale がポートをバインドする前にファイル全体を解析するため、ほとんどの場合 YAML エラーです。
マシンには通常の Tailscale クライアントもインストールする必要がありますか?
はい。headscale が置き換えるのはコントロールサーバーだけです。各ノードでは Tailscale の公式クライアントを実行し、sudo tailscale up --login-server https://headscale.example.com でサーバーを指定します。このフラグは標準クライアントに用意されているため、パッチ適用や再ビルドは必要ありません。
トラフィックは headscale サーバーを経由しますか?
通常は経由しません。headscale はネットワークを調整し、鍵とアドレスを配布します。一方、データパスはノード間の WireGuard による直接接続です。2 つのノードが直接到達できず、DERP リレーにフォールバックした場合だけ、トラフィックは迂回します。同梱の設定では、そのリレーとして Tailscale の公開リレーが使用されます。ノード上で tailscale status を実行すると、指定したピアが direct か、relay 上にあるかを確認できます。
登録後もノードがオフラインのままになるのはなぜですか?
headscale nodes list に表示されてもオンラインにならないノードでは、リバースプロキシを含めてコントロール接続を確認する必要があります。この接続は、Upgrade: tailscale-control-protocol ヘッダーを付けた POST として送信される HTTP upgrade です。nginx は、proxy_set_header を使用して Upgrade ヘッダーと Connection ヘッダーを明示的に転送しない限り、これらを破棄します。上記の設定では、map $http_upgrade $connection_upgrade ブロックによって転送しています。これらのヘッダーを破棄すると、新しいノードの登録も妨げられます。Caddy は追加設定なしで転送するため、プロキシが原因かどうかをすばやく確認できます。
headscale にドメイン名と TLS は必要ですか?
この構成では必要です。ドメイン名と HTTPS を使用してください。証明書で未加工の IP アドレスを対象にすることもできますが、設定ファイルには DERP に TLS が必要と記載されています。ドメインと Caddy を組み合わせれば約 5 分で構成でき、自動更新される HTTPS エンドポイントを利用できます。プレーン HTTP も使用できますが、headscale のドキュメントでは本番環境に HTTPS を port 443 で使用することを強く推奨しています。また、特定の状況では Tailscale クライアントが port 443 の HTTPS を前提とすることも記載されています。