WireGuard メッシュでプライベートな VPS クラスターを構築する
WireGuard のフルメッシュで VPS ノードをプライベートクラスターに接続:1つのアドレス計画、ノードごとに1つの [Peer]、/32 の AllowedIPs、厳格なファイアウォール、wg0 にバインドしたサービス。
結論:複数の VPS をプライベートクラスターにするには、各 VPS ノードに1つのプライベートサブネットからアドレスを割り当てた WireGuard インターフェースを用意し、他のすべてのノードを公開 `Endpoint` と `AllowedIPs` の `/32` 付きで `[Peer]` として追加し、UDP 51820 を自分のノードからのみ許可し、データベースや内部サービスをパブリック IP ではなく `wg0` のアドレスにバインドします。10ノード程度までなら手作業やテンプレートで簡単に保守できますが、それを超えたら設定を生成・配布するツールを使いましょう。
このガイドは、WireGuard VPN ガイドの基本をすでに理解し、SSH 強化ガイドのとおりすべてのノードで SSH を強化済みであることを前提としています。エージェント転送を使わずに踏み台経由でノードに接続する方法は、StrictModes とエージェント転送のガイドを参照してください。
VPN ノードのアドレス計画
他に使っているもの(自宅 LAN、Docker、Kubernetes の Pod レンジ)と衝突しないプライベートレンジを1つ選びます。小規模クラスターなら `/24` で十分で、アドレスも読みやすく保てます。各ノードに固定アドレスを割り当て、すべての設定はこの計画から導かれるので、計画はバージョン管理しておきましょう。
| ノード | 役割 | パブリック IP | wg0 アドレス | ListenPort |
|---|---|---|---|---|
| node1 | アプリ | 203.0.113.11 | 10.88.0.1/24 | 51820 |
| node2 | アプリ | 203.0.113.12 | 10.88.0.2/24 | 51820 |
| node3 | データベース | 203.0.113.13 | 10.88.0.3/24 | 51820 |
| node4 | 監視 | 203.0.113.14 | 10.88.0.4/24 | 51820 |
各 VPS ノードのピアごとの設定
フルメッシュではすべてのノードが他のすべてのノードと直接通信するので、各設定には1つの `[Interface]` と N-1 個の `[Peer]` セクションがあります。4ノードなら合計6本、10ノードなら45本のトンネルになります。すべてのノードにパブリック IP があるので、通常 `PersistentKeepalive` は不要です。詳細はキープアライブと PresharedKey のガイドを参照してください。
- 01.各ノードで `apt install wireguard` を実行し、続いて `umask 077; wg genkey | tee /etc/wireguard/wg0.key | wg pubkey > /etc/wireguard/wg0.pub` を実行します。
- 02.すべての公開鍵とアドレス計画を1か所にまとめます。
- 03.必要に応じて、耐量子の保険としてノードの組ごとに `wg genpsk` で鍵を1つ生成します。
- 04.以下のとおり、各ノードに `/etc/wireguard/wg0.conf` を書きます。
- 05.`systemctl enable --now wg-quick@wg0` を実行し、`wg show` ですべてのピアと最近ハンドシェイクしていることを確認します。
# /etc/wireguard/wg0.conf on node1
[Interface]
Address = 10.88.0.1/24
ListenPort = 51820
PrivateKey = <node1 private key>
[Peer]
# node2
PublicKey = <node2 public key>
Endpoint = 203.0.113.12:51820
AllowedIPs = 10.88.0.2/32
[Peer]
# node3
PublicKey = <node3 public key>
Endpoint = 203.0.113.13:51820
AllowedIPs = 10.88.0.3/32
[Peer]
# node4
PublicKey = <node4 public key>
Endpoint = 203.0.113.14:51820
AllowedIPs = 10.88.0.4/32メッシュにおける AllowedIPs の働き
`AllowedIPs` は2つの役割を同時に果たします。送信時はルーティングテーブルとして働き、`10.88.0.3` 宛てのパケットは `10.88.0.3/32` を持つピアへ送られます。受信時はアクセスリストとして働き、そのピアから届いたパケットは、送信元アドレスがそのピアの `AllowedIPs` 内にある場合にのみ受け入れられます。だからこそ、各ピアには `/24` 全体ではなく、自分の `/32` だけを割り当てるのです。
`Address` 行の `/24` は `wg0` 上にサブネットのカーネルルートを作るだけで、宛先ごとに適切なピアを選ぶのは WireGuard です。
- ▹同じインターフェース上で、2つのピアの `AllowedIPs` の範囲が重なってはいけません。最後のものが優先されます。
- ▹ノードがプライベートサブネット(例:node3 上の Docker)もルーティングする場合は、他のノードで node3 の `AllowedIPs` にそのサブネットを追加します。
- ▹すべてのトラフィックをそのノードから出したいのでない限り、メッシュのピアに `0.0.0.0/0` を入れないでください。
ファイアウォール:トンネルに到達できるのは自分のノードだけ
WireGuard は認証されていないパケットに応答しませんが、UDP 51820 を既知のノード IP に限定すればノイズをさらに減らせます。トンネル内では、各サービスに必要なポートだけを開放します。この Debian 12/13 と Ubuntu 24.04 向けの nftables の例は `/etc/nftables.conf` に置きます。`nft -f /etc/nftables.conf` で読み込み、`nftables.service` を有効にしてください。テスト中は SSH のセッションを開いたままにしておきましょう。
table inet filter {
set mesh_peers {
type ipv4_addr
elements = { 203.0.113.11, 203.0.113.12, 203.0.113.13, 203.0.113.14 }
}
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
iif lo accept
meta l4proto { icmp, ipv6-icmp } accept
tcp dport 22 accept
udp dport 51820 ip saddr @mesh_peers accept
iifname "wg0" ip saddr 10.88.0.0/24 tcp dport { 5432, 6379, 9100 } accept
}
}サービスを wg インターフェースにバインドする
ファイアウォールは1つ目の層で、2つ目の層はそもそもパブリックアドレスで待ち受けないことです。内部サービスをノードの `wg0` アドレスにバインドすれば、ファイアウォールの設定ミスがあっても露出しません。サービスがバインドする前に `wg0` が存在している必要があるので、systemd のドロップインでユニットの順序を指定するか、`net.ipv4.ip_nonlocal_bind = 1` でまだ立ち上がっていないアドレスへのバインドを許可します。
# PostgreSQL on node3: postgresql.conf
listen_addresses = '10.88.0.3'
# pg_hba.conf
host all all 10.88.0.0/24 scram-sha-256
# Redis: /etc/redis/redis.conf
bind 10.88.0.3
# systemctl edit postgresql (repeat for other services)
[Unit]
[email protected]
[email protected]Note · `ss -tlnp` で結果を確認しましょう。内部サービスには `10.88.0.x` が表示されるべきで、`0.0.0.0` やパブリック IP が表示されてはいけません。
スケーリング:ツールに切り替えるタイミング
ノード数が少なく変更もまれなうちは、手書きのメッシュで問題ありません。新しいノードを追加するたびに既存のすべての設定を編集する必要があるので、作業量はノード数の2乗で増えていきます。それが面倒になったら、設定を手で書くのではなく生成しましょう。
NoctisNode では、新規 VPS ノードはすべて FI-1(フィンランド)にデプロイされ、それぞれに専用 IPv4 と従量制なしの 1 Gbps ポートが付きます。時間単位の課金とエージェント API(自動削除の TTL 付き)により、テスト用ノードを安価に追加・削除できます。プランは Wisp から。VPS プランを参照してください。
| クラスターの規模 | アプローチ |
|---|---|
| 2〜5ノード | 手書きの設定、アドレス計画はテキストファイルで管理 |
| 5〜15ノード | Ansible などの構成管理ツールで、1つのインベントリから wg0.conf をテンプレート生成 |
| 15ノード以上、または頻繁な入れ替え | 鍵とピアを自動配布するメッシュマネージャー、またはハブ&スポーク構成 |
よくある質問
Q複数の VPS をプライベートネットワークに接続するには?
A各 VPS に WireGuard をインストールし、各ノードに1つのプライベートサブネットからアドレスを割り当て、他のすべてのノードを公開エンドポイントと /32 の AllowedIPs 付きでピアとして列挙します。そのうえで、内部サービスを WireGuard のアドレスにバインドします。
QWireGuard メッシュの VPN ノードに PersistentKeepalive は必要ですか?
A通常は不要です。すべての VPS ノードにパブリック IP があり、直接到達できるからです。`PersistentKeepalive = 25` は NAT の内側にあるノードにだけ追加してください。
Q各 VPS ノードの AllowedIPs はどう設定すべきですか?
A各ピアには自分の WireGuard アドレスを /32 で割り当て、そのノードがルーティングするサブネットがあればそれも加えます。すべてのピアにクラスターのサブネット全体を使うと、ルートが重複してメッシュが壊れます。
QWireGuard メッシュには何ノードまで参加できますか?
AWireGuard 自体は多数のピアを扱えますが、手で保守するフルメッシュは、すべてのノードが他のすべてのノードの設定を必要とするため、10ノード程度を超えると面倒になります。それ以上は自動化で設定を生成するか、メッシュマネージャーを使いましょう。