VPSにNetBird VPNサーバーをセルフホストする方法
VPS 1台で NetBird のメッシュVPNを構築します。DNSとTLS、固定した quickstart script、無人接続用の setup key、Headscaleとの違いを詳しく解説します。
NetBird VPN サーバーをセルフホストするメリット
NetBird VPN サーバーをセルフホストすると、自分が所有する VPS にコントロールプレーンを配置できます。コントロールプレーンは、ピアの一覧を保持し、どのマシンがどのマシンへ到達できるかを決定し、NAT(ネットワークアドレス変換)の背後にある2つのピアが相互に検出できるよう支援します。トンネル自体は引き続き WireGuard であり、マシン間で直接暗号化されます。変わるのは、デバイス一覧やログイン処理を外部企業が保持しなくなる点です。ただし、これによって得られるものを正しく理解してください。ホスト型コントロールプレーンがトラフィックを暗号化する鍵を保持するわけではありません。また、侵害された調整サーバーが実際に実行できることは、内容を確認する前に多くの人が想定するより限定的です。詳しくは調整サーバーが侵害された場合に実際に可能なことを参照してください。
NetBird は、すでに知っているかもしれない2つの仕組みの中間に位置します。メッシュオーバーレイなので、すべての通信を1つのゲートウェイ経由で送るのではなく、ピア同士が接続します。また、エンドツーエンドでセルフホストできるため、セルフホスト型の Tailscale コントロールサーバーである Headscale と比較できます。単一ゲートウェイ型のトンネルしか運用したことがない場合は、まず通常の WireGuard とメッシュオーバーレイの違いを読んでください。この違いを理解すると、このページの後半を把握しやすくなります。
実際に必要なのが、すべての通信を1台のサーバーから外部へ出す構成だけであれば、メッシュは目的に対して過剰な仕組みです。単一の VPS 上に構築する通常の WireGuard VPN、またはTailscale の exit nodeなら、稼働させるコンポーネントを大幅に減らして同じことを実現できます。また、目的がマシン同士を接続することではなく、1つのプライベートネットワークへ到達することなら、VPS 上の Tailscale subnet routerを使えば、以下のスタックを導入せずに、そのネットワーク範囲を既存の tailnet に通知できます。
実際に動作する構成
最近レイアウトが変更され、多くの古い記事では以前の構成が説明されています。2026年8月現在、release v0.76.2 では、quickstart script によりデフォルトで3つのサービスを含む Compose file が作成されます。
netbird-serverは管理 API、signal service、組み込み STUN listener を備えた relay、組み込み identity provider を提供します。以前の release では、これらは別々の container で動作し、identity provider も別途 Zitadel をインストールして、先に構築する必要がありました。dashboardは管理用 Web console です。traefikは TLS (transport layer security) を終端し、初回起動時に Let's Encrypt へ証明書を要求します。
さらに2つのサービスがあります。プロンプトで yes と答えない限り、これらは起動しません。NetBird Proxy service は、内部サービスを公開 hostname で公開します。CrowdSec は不正な network traffic をフィルタリングします。どちらも動作する mesh の構築には不要で、小規模なホストではメモリも消費します。
単一の Docker container で動作する wg-easy から移行する場合、構成要素の数が増えます。その代わり、アクセスポリシーとユーザーごとのアカウントを利用でき、peer 同士が1つの gateway を経由せず直接接続できるようになります。
開始前に必要なもの
公開ドメイン名は必須です。ダッシュボード、API、relay はすべてポート 443 の HTTPS を使用します。Traefik は HTTP challenge を使用して Let's Encrypt から証明書を取得するため、パブリックインターネットからこの VPS に名前解決できるドメイン名が必要です。この手順では、IP アドレスだけでは使用できません。
A レコードを 1 つ作成し、netbird.example.com を VPS のパブリック IPv4 アドレスに向けます。何かを実行する前に、DNS の反映を待ってください。
dig +short netbird.example.comこれにより、サーバーのアドレスが表示される必要があります。DNS が反映される前に installer を実行すると、初回起動時の証明書要求が失敗します。失敗した検証を繰り返すと Let's Encrypt の rate limit に達するため、再試行まで 1 時間待つことになります。
インターネットから到達できる必要があるポートは 3 つです。証明書 challenge と HTTPS への redirect には TCP 80、ダッシュボード、API、signal、relay の通信には 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 statusprovider のネットワーク firewall でもこれらを開放してください。多くの VPS パネルでは、これは別の制御項目です。サーバー自身の ufw status が正しく見えても接続を拒否する原因は、ここにあります。
STUN(session traversal utilities for NAT)は、peer が自身の NAT に割り当てられたパブリックアドレスとポートを確認するための仕組みです。これにより、2 つの peer は直接トンネルを確立できます。UDP 3478 をブロックしても、peer は TCP 443 の relay 経由で接続できるため、問題がないように見えます。しかし、すべての peer で Connection type: Relayed となり、すべての通信が peer 間ではなく VPS を経由します。
ソフトウェア側では、Compose v2 plugin を備えた Docker と、jq および curl が必要です。script はこれらをすべて確認し、1 つでも不足していると停止します。このサーバーで Docker を初めて使用する場合は、先に VPS で Docker Compose を動作させる を参照してください。
組み込み reverse proxy を使用しない場合のポート
Traefik を使用しない場合、各 service が直接公開されるため、必要なポートが増えます。
- TCP 80、HTTP redirect
- TCP 443、HTTPS
- TCP 33073、management gRPC
- TCP 10000、signal gRPC
- TCP 33080、WebSocket または QUIC 経由の relay
- 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] を選択してください。Options 2 through 5 は設定の一部を書き込み、残りの接続設定を利用者に任せます。これは、すでにプロキシを運用しているサーバーでは適切ですが、新規構築のサーバーでは適切ではありません。Option 0 を選ぶと、Let's Encrypt のメールアドレスを尋ねられます。このアドレスは証明書の有効期限通知に使用されます。
初回インストールでは、NetBird Proxy service に no と答えてください。追加で 2 つの DNS レコード、proxy.netbird.example.com とワイルドカードの *.proxy.netbird.example.com が必要になりますが、通常の mesh には不要です。CrowdSec にも no と答えてください。どちらも後から追加できます。
スクリプトは現在のディレクトリに次のファイルを書き込みます。docker-compose.yml、mode 600 の config.yaml、dashboard.env、および bundled 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 です。
最初の管理者アカウントを作成する
https://netbird.example.comを開きます。新規インストール直後はログインフォームではなく、セットアップページが表示されます。メールアドレス、名前、パスワードを入力し、Create Accountをクリックします。このアカウントが最初の管理者になり、ページはログインフォームへリダイレクトされます。
このアカウントは、netbird-serverコンテナに組み込まれたアイデンティティプロバイダーを基盤とする、NetBird独自のユーザーストアに保存されます。外部のコンポーネントは必要ありません。これは、1年前のセルフホスト型NetBirdからの最大の変更点です。当時は、動作する環境を用意するには、まずZitadelまたはKeycloakを構築し、4つのOIDC(OpenID Connect)値をsetup.envにコピーする必要がありました。それを済ませなければ、何も起動しませんでした。
セットアップページではなく、ブラウザーに証明書の警告が表示された場合、証明書は発行されていません。先にこの問題を解決してください。ダッシュボードは同じホスト名を使用して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 に対応する任意のプロバイダーを受け入れます。プロバイダーで confidential OIDC client を登録し、NetBird のダッシュボードに name、client ID、client secret、issuer の4つの値を入力します。NetBird は redirect URL を表示するため、それをプロバイダーに貼り付けます。Google、Microsoft Entra ID、Okta、Zitadel、Keycloak、Authentik、Pocket ID には専用の連携設定があり、それ以外は generic OIDC として設定します。すでに セルフホスト型のシングルサインオンとして Authentik を運用している場合は、アカウント一覧を2つに分けずに済む方法です。
プロバイダーを追加した後もローカルログインは利用でき、設定済みの各プロバイダーがログインページに表示されます。強力なパスワードを設定したローカルの admin アカウントを1つ残してください。OIDC の設定に問題があっても、そのアカウントからログインできます。
NetBird と Headscale: どちらのコントロールプレーンを運用すべきか
どちらも、クライアントが通常接続するホスト型コントロールサーバーへの依存をなくします。ただし、プロジェクトの構成は同じではありません。
Headscale は Tailscale のコントロールサーバーを再実装したもので、公式の Tailscale クライアントを引き続き使用します。公式の Web コンソールはありません。ユーザーと事前認証キーは、設定ファイルに対して headscale コマンドで管理します。コミュニティ製の Web インターフェースは存在しますが、プロジェクトの一部ではありません。状態をファイルで管理し、変更をバージョン管理に置きたい場合に適しています。
NetBird は、独自のクライアント、独自のダッシュボード、組み込みの ID プロバイダー、ブラウザーで編集するアクセス ポリシーを含む製品全体を提供します。VPS 上で稼働する要素は増えますが、ターミナルを開くことのない同僚に引き継ぐ作業は大幅に減ります。
すでに Tailscale クライアントを利用している場合や、可能な限り小規模なコントロールプレーンを求める場合は Headscale を運用します。複数人でピアを管理する必要があり、コンソールと SSO を自分で構築せずに利用したい場合は NetBird を運用します。いずれかに決める前に、Tailscale の無料プランで実際に利用できる範囲を確認してください。6 ユーザー以内でデバイス数が無制限のグループであれば、ホスト型コントロールプレーンの料金はかからず、そもそも自分で運用する理由がない場合があります。その上限を超えると、料金はマシン数ではなくユーザー数に応じて増えます。そのため、Tailscale がグループに請求する料金を算出することで、この構成に必要な VPS 費用と作業時間に見合うか比較できます。
この構成を実行できる 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 ボリュームです。これらを一緒にバックアップしてください。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 はボリューム名にプロジェクトディレクトリの名前を付けます。そのため、netbird_data と記載されているボリュームは通常、netbird_netbird_data として表示されます。最初に docker volume ls を実行し、表示された名前を使用してください。そうしないと、docker run は空のボリュームを作成して何もアーカイブせず、失敗したことも通知しません。アーカイブは 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 の hosted service に登録されています。netbird status --detail を実行すると、接続先のサーバーが Management: の行に表示されます。https://api.netbird.io:443 のような値であれば、そのことを確認できます。sudo netbird down を実行し、続いて sudo netbird up --management-url https://netbird.example.com を実行すると、peer がダッシュボードに表示されます。
self-hosted NetBird は Headscale とどう違いますか?
どちらも、ホスト型の control server を自分で運用するサーバーに置き換えます。Headscale は control plane のみです。headscale コマンドと設定ファイルで管理し、公式の Web コンソールはありません。また、公式の Tailscale client を制御します。NetBird は独自の client、admin dashboard、identity provider 連携を同じ stack で提供します。Headscale は小規模に運用しやすく、状態をファイルに保持します。NetBird は terminal を使わない利用者に引き渡しやすい構成です。
self-hosted NetBird サーバーには、どの程度のサイズの VPS が必要ですか?
ドキュメント上の最小要件は 1 CPU と 2 GB の memory で、購入するなら 2 GB が基準です。近年のリリースでは identity provider が別のデプロイではなく組み込みになったため、実用上の下限は約 1 GB まで下がっています。インストール時に任意の proxy と CrowdSec service は選択せず、PostgreSQL が本当に必要になるまではデフォルトの SQLite store を使用してください。