NetBird VPNサーバーをVPSにセルフホストする方法
VPS 1台で NetBird のメッシュ VPN を構築します。v0.76.2向けのDNSとTLS設定、固定したquickstartスクリプト、無人参加用のsetup key、Headscaleとの違いを解説します。
NetBird VPN サーバーをセルフホストすると得られるもの
NetBird VPN サーバーをセルフホストすると、所有する VPS にコントロールプレーンを配置できます。コントロールプレーンは、ピア一覧を保持し、どのマシンがどのマシンへ接続できるかを決定し、NAT(ネットワークアドレス変換)配下にある2つのピアが相互に見つけられるよう支援します。トンネル自体は引き続き WireGuard で構成され、マシン間で直接暗号化されます。変わるのは、外部企業がデバイス一覧やログイン処理を保持しなくなる点です。
NetBird は、すでに知っている可能性がある2つの仕組みの中間に位置します。メッシュオーバーレイであるため、すべての通信を1つのゲートウェイ経由で送るのではなく、ピア同士が接続します。また、構成全体をセルフホストできるため、セルフホスト型の Tailscale コントロールサーバーである Headscale と比較できます。単一ゲートウェイ型のトンネルしか運用したことがない場合は、まず 通常の WireGuard とメッシュオーバーレイの違い を読んでください。この違いを理解すると、このページの内容を把握しやすくなります。
実際に必要なのが、すべての通信を1台のサーバーから外部へ送信する構成だけであれば、メッシュは要件に対して複雑すぎます。単一の VPS 上に構築する通常の WireGuard VPN または Tailscale の exit node であれば、実行するコンポーネントを大幅に減らして同じことを実現できます。
実際に動作する構成
構成は最近変更されました。古い記事の多くは以前の構成を説明しています。2026年8月時点のリリース v0.76.2 では、quickstart スクリプトがデフォルトで3つのサービスを含む Compose ファイルを書き出します。
netbird-serverは、管理 API、シグナルサービス、組み込みの STUN リスナーを備えたリレー、組み込みの ID プロバイダーを提供します。以前のリリースでは、これらは別々のコンテナでした。また、ID プロバイダーには、事前に構築しておく別個の Zitadel インストールが必要でした。dashboardは管理用 Web コンソールです。traefikは TLS (transport layer security) を終端し、初回起動時に Let's Encrypt へ証明書を要求します。
さらに2つのサービスがあります。プロンプトで有効にすることを選ばない限り、これらは停止したままです。NetBird Proxy サービスは、内部サービスをパブリックホスト名で公開します。CrowdSec は悪意のあるトラフィックをフィルタリングします。どちらも動作するメッシュの構築には必要ありません。小規模なホストでは、いずれもメモリを消費します。
単一の Docker コンテナで動作する wg-easy から移行する場合、構成要素の数は増えます。その代わり、アクセス ポリシーとユーザーごとのアカウントを利用できます。また、ピアは1つのゲートウェイを経由せず、相互に直接接続します。
開始前に必要なもの
パブリックドメイン名は必須です。ダッシュボード、API、リレーはすべて 443 番ポートの HTTPS を使用します。Traefik は HTTP challenge を使用して Let's Encrypt から証明書を取得するため、パブリックインターネットからこの VPS に名前解決できるドメイン名が必要です。この構成では、IP アドレスを直接指定する方法は使用できません。
A レコードを 1 つ作成し、netbird.example.com を VPS のパブリック IPv4 アドレスに設定してください。何も実行する前に、DNS の反映を待ちます。
dig +short netbird.example.comこのコマンドの出力には、サーバーのアドレスが表示される必要があります。DNS が反映される前にインストーラーを実行すると、初回起動時の証明書要求が失敗します。失敗した検証を繰り返すと Let's Encrypt のレート制限に達するため、再試行まで 1 時間待つことになります。
インターネットから到達できるようにするポートは 3 つあります。証明書の challenge と HTTPS へのリダイレクトには TCP 80、ダッシュボード、API、シグナル、リレーの通信には TCP 443、STUN には UDP 3478 を使用します。
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 3478/udp
sudo ufw reload
sudo ufw statusプロバイダーのネットワークファイアウォールでも、これらのポートを開放してください。これは多くの VPS パネルで別に設定する項目です。サーバー自身の ufw status が正しく見えていても接続できない場合、その原因はこの設定であることがよくあります。
STUN(session traversal utilities for NAT)は、ピアが自身の NAT に割り当てられたパブリックアドレスとポートを確認するための仕組みです。これにより、2 つのピアは直接トンネルを確立できます。UDP 3478 をブロックしても、ピアは TCP 443 のリレー経由で接続できるため、問題が発生していないように見えます。その代わり、すべてのピアで Connection type: Relayed が表示され、すべての通信がピア間ではなく VPS を経由します。
ソフトウェア側では、Compose v2 plugin を備えた Docker に加えて、jq と curl が必要です。スクリプトはこれらをすべて確認し、1 つでも不足していると停止します。このサーバーで Docker を初めて使用する場合は、先に VPS で Docker Compose を動作させる を実施してください。
バンドルされたリバースプロキシを使用しない場合のポート
Traefik を使用しない場合、各サービスが直接公開されるため、必要なポートが増えます。
- TCP 80、HTTP リダイレクト
- TCP 443、HTTPS
- TCP 33073、管理用 gRPC
- TCP 10000、シグナル用 gRPC
- TCP 33080、WebSocket または QUIC 経由のリレー
- UDP 3478、STUN
この構成は、サーバーですでに別のサービスの TLS 終端を担っている場合だけ選択してください。それ以外では、バンドルされた Traefik のほうがルールが少なく、設定ミスも減ります。
クイックスタートスクリプトで NetBird サーバーをインストールする
ドキュメントにあるワンライナーは、最新リリースをそのまま shell にパイプします。
curl -fsSL https://github.com/netbirdio/netbird/releases/latest/download/getting-started.sh | bashバージョンを固定してください。latest は変わるため、同じコマンドでも 2 週間空けて実行すると、異なるインストール結果になります。また、どのバージョンが設定を書き込んだのかをディスク上で確認できません。タグ付きリリースをダウンロードし、内容を確認してから実行します。
mkdir -p ~/netbird
cd ~/netbird
curl -fsSL -o getting-started.sh \
https://github.com/netbirdio/netbird/releases/download/v0.76.2/getting-started.sh
less getting-started.sh
bash getting-started.shスクリプトは最初にドメインを尋ねます。
Enter the domain you want to use for NetBird (e.g. netbird.my-domain.com):次に、TLS の処理方法を尋ねます。
Which reverse proxy will you use?
[0] Traefik (recommended - automatic TLS, included in Docker Compose)
[1] Existing Traefik (labels for external Traefik instance)
[2] Nginx (generates config template)
[3] Nginx Proxy Manager (generates config + instructions)
[4] External Caddy (generates Caddyfile snippet)
[5] Other/Manual (displays setup documentation)
Enter choice [0-5] (default: 0):[0] を選択してください。オプション 2 から 5 は設定の断片を書き込み、接続設定をユーザーに任せます。これは、すでにプロキシを運用しているサーバーでは適切ですが、新規構築したサーバーでは適切ではありません。オプション 0 を選ぶと、Let's Encrypt のメールアドレスを尋ねられます。このアドレスは証明書の有効期限通知に使用されます。
初回インストールでは NetBird Proxy サービスに「no」と回答してください。このサービスには、proxy.netbird.example.com とワイルドカードの *.proxy.netbird.example.com という 2 つの DNS レコードが追加で必要です。また、単純な mesh 構成では何も行いません。CrowdSec にも「no」と回答してください。どちらも後から追加できます。
スクリプトは、現在のディレクトリに次のファイルを書き込みます。docker-compose.yml、mode 600 の config.yaml、dashboard.env、および組み込みの Traefik を選択した場合の traefik-dynamic.yaml です。このディレクトリは保持する state として扱ってください。config.yaml には、store 内のデータを暗号化する key が保存されているためです。これを失うと、再インストールしても復旧できません。
docker compose ps
docker compose logs -f netbird-server各サービスが running を読み込み、サーバーログがループ状に再起動せず安定することを確認してください。証明書は別途監視します。
docker compose logs traefik | grep -i acmeACME (automatic certificate management environment) は、Traefik が証明書を取得するために使用するプロトコルです。ここでエラーになる原因は、ほとんどの場合 DNS または閉じた port 80 です。
最初の admin アカウントを作成する
https://netbird.example.comを開きます。新規インストール直後は、ログインフォームではなくセットアップページが表示されます。メールアドレス、名前、パスワードを入力し、Create Account をクリックします。このアカウントが最初の admin になり、ページはログインフォームへリダイレクトされます。
このアカウントは、netbird-serverコンテナに組み込まれた identity provider を基盤とする、NetBird 独自のユーザーストアに保存されます。外部の仕組みは関与しません。これは、1 年前の self-hosted NetBird からの大きな変更点です。当時は、正常に動作する環境を用意するには、まず Zitadel または Keycloak を構築し、4 つの OIDC (OpenID Connect) の値を setup.env にコピーする必要がありました。これを行わなければ、何も起動しませんでした。
セットアップページではなく、ブラウザに証明書の警告が表示される場合は、証明書が発行されていません。先にこの問題を修正してください。ダッシュボードは同じ hostname を使用して API と通信するため、証明書に問題があると分かりにくい形で失敗します。
最初のピアを参加させる
メッシュに参加させる場合は、VPS 自体を含む任意の Linux マシンにクライアントをインストールします。
curl -fsSL https://pkgs.netbird.io/install.sh | shDebian と Ubuntu では、このスクリプトが NetBird のパッケージリポジトリを設定してから、apt 経由でクライアントをインストールします。そのため、いずれの場合もパッケージマネージャーがクライアントを管理します。スクリプトをシェルにパイプする方法が気になる場合は、curl -fsSL -o install.sh https://pkgs.netbird.io/install.sh でいったん保存し、sh install.sh を実行する前に内容を確認します。どちらの方法でも、インストールされた内容を確認します。
apt-cache policy netbirdnetbird はコマンドラインクライアントとデーモンです。netbird-ui はデスクトップのトレイアプリであり、ヘッドレスサーバーでは使用しません。
次に、クライアントをサーバーに接続します。
sudo netbird up --management-url https://netbird.example.com--management-url を省略すると、コンパイル時のデフォルト設定により、クライアントは NetBird のホステッドサービスに登録されます。コマンドは正常終了し、マシンにもアドレスが割り当てられますが、セルフホストのダッシュボードには何も表示されません。この問題は、ほぼ全員が一度は経験します。
コマンドの出力には、ログインを完了するためにブラウザーで開く URL が含まれます。その後、次を実行します。
netbird status
ip addr show wt0netbird status から 4 行を読み取ります。Management: Connected、Signal: Connected、利用可能なすべてのリレーを示す Relays: 行、そしてオーバーレイ範囲内の NetBird IP: です。wt0 は NetBird が作成する WireGuard インターフェースであり、同じアドレスが割り当てられているはずです。
セットアップキーを使用して2台目のマシンを無人で参加させる
ブラウザーがなく、操作する人もいないマシンでは、ブラウザーによるログインは使えません。セットアップキーは、対話操作なしでマシンを登録する事前認証トークンです。ダッシュボードの Setup Keys で作成します。
セットアップキーには2種類あります。1回限りのキーは1台のマシンだけを認証し、その後は使用済みになります。再利用可能なキーは複数のマシンを登録でき、登録数の上限も任意で設定できます。どちらにも有効期限を設定できます。また、新しい peer をグループに自動割り当てることもできます。その場合、そのグループのアクセスルールがマシンの追加直後から適用されます。
sudo netbird up --setup-key <SETUP-KEY> \
--management-url https://netbird.example.com \
--hostname build-runner-01--hostname は、ダッシュボードに表示される名前を設定します。指定しない場合、peer にはマシン自身が名乗る名前が設定されます。すべてのエントリが ubuntu という名前になった状態では、管理に役立ちません。
コンテナや短時間だけ稼働するビルドエージェントでは、キーの作成時に ephemeral を指定します。ephemeral キーで登録された peer は、10 minutes を超えてオフラインになると自動的に削除されます。これにより、不要なエントリが peer 一覧に残りません。
セットアップキーを使う前に理解しておくべき制限があります。キーの有効期限が切れたり、キーを削除したりすると、新しい登録は停止します。ただし、そのキーですでに登録されたマシンは切断されません。マシンのアクセスを削除するには、その peer を削除します。
別の ID プロバイダーはまだ必要ですか?
小規模な構成であれば、必要ありません。組み込みのユーザーストアで、ダッシュボードから作成したアカウントを管理できます。少人数で使用するなら、それで十分です。
すでに外部 ID プロバイダーを運用していて、ユーザー一覧を別に持ちたくない場合は、外部 ID プロバイダーを使用します。NetBird は OIDC に対応するプロバイダーを使用できます。プロバイダーに機密 OIDC クライアントを登録し、NetBird のダッシュボードで 4 つの値を設定します。名前、クライアント ID、クライアントシークレット、issuer です。NetBird はリダイレクト URL を表示するため、それをプロバイダー側に貼り付けます。Google、Microsoft Entra ID、Okta、Zitadel、Keycloak、Authentik、Pocket ID には専用の連携設定があります。それ以外のプロバイダーは汎用 OIDC として設定します。すでに セルフホストのシングルサインオンとして Authentik を運用している場合は、アカウント一覧を 2 つに分けずに済む方法です。
プロバイダーを追加した後もローカルログインは使用できます。設定済みの各プロバイダーはログインページに表示されます。強力なパスワードを設定したローカル管理者アカウントを 1 つ残してください。OIDC の設定に問題が発生しても、そのアカウントからログインできます。
NetBird と Headscale: どのコントロールプレーンを運用するべきか
どちらも、クライアントが通常接続するホスト型コントロールサーバーへの依存をなくします。ただし、プロジェクトの構成は同じではありません。
Headscale は Tailscale のコントロールサーバーを再実装したもので、公式の Tailscale クライアントを引き続き使用します。公式の Web コンソールはありません。設定ファイルに対して headscale コマンドを実行し、ユーザーと事前認証キーを管理します。コミュニティ製の Web インターフェースは存在しますが、プロジェクトには含まれません。状態をファイルで管理し、変更をバージョン管理したい場合に適しています。
NetBird は、独自のクライアント、独自のダッシュボード、組み込みの ID プロバイダー、ブラウザーで編集するアクセス ポリシーを含む製品全体を提供します。VPS 上の構成要素は増えますが、端末を開くことのない同僚に引き継ぐ作業は大幅に減ります。
すでに Tailscale クライアントを利用している場合、または可能な限り小規模なコントロールプレーンを求める場合は Headscale を運用します。複数人でピアを管理する必要があり、コンソールと SSO を自分で組み立てずに導入したい場合は NetBird を運用します。
この構成を実行できる最小の VPS はどの程度ですか?
文書上の最小要件は、1 CPU と 2 GB のメモリです。NetBird 自身の説明では、ユーザー管理がローカルになった現在の下限は約 1 GB の RAM です。完全な Zitadel デプロイメントをスタックに含めていた以前の構成では、2 GB から 4 GB が必要でした。2 GB を選択してください。追加の余裕があると、古いイメージをディスクに残したままアップグレードで新しいイメージを取得できます。
小規模なサーバーでは、3 つの機能を安全に省略できます。NetBird Proxy サービスは無効にしてください。このサービスは内部サービスをパブリックホスト名で公開するためのもので、ピア間の接続には関係ありません。CrowdSec も無効にしてください。公開サーバーでは後から追加する価値がありますが、初日から導入する必要はありません。デフォルトの SQLite ストアは netbird_data ボリュームに保持してください。複数のマシンにデプロイメントを分割する場合、または実際に同時実行性の問題が発生した場合にのみ PostgreSQL へ移行します。この移行は後から実施できます。
リレーは省略できない唯一のコンポーネントです。NAT によって宛先ごとに異なるポートが割り当てられる 2 つのピアは、直接トンネルを確立できません。そのため、リレーが接続を成立させる唯一の経路になります。無効にしてもメモリ使用量はほとんど減らず、原因を追跡しにくい形で接続が失敗します。
1 台では不十分になった場合、最初にリレーを別のサーバーへ移します。スタンドアロンのリレーは NB_LISTEN_ADDRESS、NB_EXPOSED_ADDRESS、NB_AUTH_SECRET、NB_ENABLE_STUN で実行します。共有 Secret はリレーとメインサーバーで同一でなければなりません。同一でない場合、クライアントはリレーへの認証に失敗します。
障害のパターンと確認できる内容
ダッシュボードに証明書の警告が表示される。 Traefik が証明書を取得できていません。docker compose logs traefik | grep -i acme を実行します。原因は2つあります。dig +short netbird.example.com がまだこの VPS を返していないか、Let's Encrypt とコンテナの間のどこかで TCP 80 が閉じています。通常は ufw ではなく、プロバイダー側のネットワークファイアウォールが原因です。ループ状態で再試行する前に原因を修正してください。検証の失敗にはレート制限があり、1時間にわたって再試行できなくなるためです。
クライアントは接続したと表示されるが、ダッシュボードが空である。 --management-url が指定されていなかったため、クライアントは NetBird のホスト型サービスに登録されています。netbird status --detail を実行し、実際に通信しているサーバーを示す Management: 行を確認します。Management: Connected to https://api.netbird.io:443 と表示される場合は、クラウドに接続しています。sudo netbird down を実行してから、再度 sudo netbird up --management-url https://netbird.example.com を実行します。
すべてのピアに Connection type: Relayed と表示される。 直接トンネルが確立されていないため、すべてのトラフィックが VPS を経由し、遅延が 1 ホップ分増えています。VPS のファイアウォールとプロバイダーのファイアウォールで UDP 3478 を確認してください。STUN により、ピアは自身のパブリックアドレスとポートを認識できます。netbird status --detail は Direct: false と、各ピアの ICE(interactive connectivity establishment)候補タイプも出力します。これにより、接続試行がどこまで進んだかを確認できます。一部のネットワークでは relayed しか利用できず、異常ではありません。
ピアは参加するが、何にも到達できない。 メッシュに参加していても、2つのピア間の通信が許可されるとは限りません。通信可否はアクセスポリシーで決まり、ポリシーが関連付けられていないグループからは何にも到達できません。ルートやファイアウォールの調査を始める前に、ダッシュボードでポリシーを確認してください。
netbird status がデーモンの問題を報告する。 サービスが実行されていません。sudo netbird service status と sudo netbird service start を使用します。クライアントのログは /var/log/netbird/client.log にあります。原因を特定できない場合は、netbird debug bundle --anonymize --system-info を使用すると、ログ、状態、ルート、DNS 設定、ファイアウォールの状態を1つのアーカイブにまとめて収集できます。
バックアップとアップグレード
インストール全体を支えるものは 2 つあります。docker-compose.yml と config.yaml を格納するディレクトリと、データベースおよび暗号化キーを保持する Docker volume です。これらは一緒にバックアップしてください。config.yaml にはストア内のデータを暗号化するキーが保存されています。そのため、これがないデータベースのコピーを復元しても、読み取れるデータには戻せません。
docker volume ls
docker compose down
sudo tar czf netbird-config.tgz -C ~ netbird
docker run --rm -v netbird_netbird_data:/data -v "$PWD":/backup \
alpine tar czf /backup/netbird-data.tgz -C /data .
docker compose up -dCompose は volume 名の先頭にプロジェクトディレクトリ名を付けます。そのため、netbird_data と記載されている volume は通常、netbird_netbird_data として表示されます。最初に docker volume ls を実行し、表示された名前を使用してください。そうしないと、docker run は空の volume を暗黙的に作成し、何もアーカイブせずに終了します。アーカイブは VPS の外部に保管してください。すでにバックアップツールを使用している場合は、restic または BorgBackup でオフサイトへの保存を行えます。
サーバーのアップグレードは、pull と再作成で行います。
docker compose pull
docker compose up -d
docker compose psこの方法を運用に組み込む前に、docker compose config | grep image: を実行してください。latest と記載されたタグは、すべてバージョンで固定してください。インストールスクリプトを固定した理由と同じです。実行中のバージョンを把握し、アップグレードに問題が発生した場合に戻せるバージョンを確保するためです。クライアントは、インストールに使用したパッケージマネージャーでアップグレードします。
FAQ
自分で NetBird をホストする場合、独自の identity provider は必要ですか?
いいえ。現在のリリースには組み込みのユーザーストアが含まれているため、https://netbird.example.com のブラウザー画面で最初の admin アカウントを作成し、その後はダッシュボードからユーザーを追加できます。外部の OIDC provider は任意で、後から name、client ID、client secret、issuer の 4 つの値を指定して追加できます。NetBird の前に Zitadel や Keycloak をデプロイするよう案内するガイドは、現在は不要な構成を説明しています。その手順に従うと、運用するサービスが 1 つ余分に増えます。
すべての peer に Connection type: Relayed と表示されるのはなぜですか?
直接接続が確立されていないため、ネットワークトラフィックが VPS 上の relay を経由しています。通常の原因は UDP 3478 がブロックされていることです。これは peer が自身のパブリックアドレスとポートを検出するために使用する STUN ポートです。VPS の firewall と、provider 側の別の network firewall の両方でこのポートを開放し、もう一度 netbird status --detail を実行して Direct: 行を確認します。NAT が接続先ごとに異なるポートを割り当てるネットワークでは、relayed になる以外に方法がありません。設定ミスではありません。
client は接続しましたが、ダッシュボードに peer が表示されません。何が起きていますか?
--management-url が省略されているため、client はあなたのサーバーではなく NetBird のホスト型サービスに登録されています。netbird status --detail は、Management: 行に通信先のサーバーを出力します。https://api.netbird.io:443 のような値なら、そのことを確認できます。sudo netbird down を実行し、続けて sudo netbird up --management-url https://netbird.example.com を実行すると、peer がダッシュボードに表示されます。
自分でホストする NetBird は Headscale とどう違いますか?
どちらも、ホスト型の control server を自分で運用するサーバーに置き換えます。Headscale は control plane のみです。headscale コマンドと設定ファイルで管理し、公式の Web console はありません。また、公式の Tailscale client を制御します。NetBird には、独自の client、admin dashboard、identity provider integration が同じ stack に含まれています。Headscale は運用規模が小さく、状態をファイルに保持します。NetBird は terminal を使わない利用者に引き渡しやすい構成です。
自分でホストする NetBird サーバーには、どの程度の VPS が必要ですか?
ドキュメント上の最小要件は 1 CPU と 2 GB のメモリであり、購入する場合は 2 GB を選びます。近年のリリースでは identity provider が別のデプロイではなく組み込みになったため、実用上の下限は約 1 GB まで下がりました。インストール時に任意の proxy と CrowdSec サービスを無効にし、PostgreSQL が本当に必要になるまではデフォルトの SQLite ストアを使用してください。