WireGuard メッシュVPN on Ubuntu — フルメッシュ接続の自動設定

ネットワーク

VPSを3台以上借りてサーバーを運用していると、「全台を直接つないで内部通信したい」という場面が出てきます。WireGuardのフルメッシュ構成は、すべてのノード間に直接の暗号化トンネルを張る構成で、中継サーバーなしにどのノードからどのノードへでもプライベートIPで通信できます。

この記事では、Ubuntu 24.04 LTS の3台構成を例に、WireGuardメッシュVPNの設定ファイルを1から作る手順を解説します。インストールログと鍵生成コマンドは docker run ubuntu:24.04 で実際に実行した出力を使います。wg showping の出力は実際の3台接続環境がないと取得できないため、公式ドキュメントに基づく出力フォーマットの例を示します。

前提

本記事の手順は Ubuntu 24.04 LTS で確認しています。Ubuntu 22.04 でも同じ手順が使えますが、wireguard-tools のパッケージバージョンと systemd ユニットのパスが一部異なります(末尾の比較図を参照)。WireGuardのカーネルモジュールは Ubuntu 22.04 以降ではビルトインなので、DKMS は不要です。

この記事のポイント

  • apt install wireguard-tools だけで wgwg-quick が入る(DKMS 不要)
  • wg genkey | wg pubkeywg genpsk で鍵を生成し、ノードごとに wg0.conf を作る
  • 3ノードのフルメッシュは「C(3,2)=3 ペア」――各ノードの設定に [Peer] ブロックが2つ入る
  • systemctl enable --now wg-quick@wg0 で自動起動、wg show で接続状態を確認する
  • ノードが増えると設定量が n*(n-1)/2 で増えるため、4台以上では自動生成スクリプトが現実的

目次

  1. 動作確認済み環境
  2. WireGuardとフルメッシュトポロジー
  3. wireguard-toolsをインストールする
  4. 3ノード分の鍵を生成する
  5. 各ノードのwg0.confを作成する
  6. インターフェースを起動して接続を確認する
  7. systemdで自動起動を設定する
  8. 4台以上のメッシュを自動生成する
  9. よくあるエラーと解決策
  10. まとめ

動作確認済み環境

項目 確認値
OS Ubuntu 24.04 LTS (Noble Numbat)
wireguard-tools 1.0.20210914-1ubuntu4
カーネルモジュール ビルトイン(DKMS 不要)
VPN アドレス帯 10.0.0.0/24(本記事の例)
WireGuard ポート UDP 51820
検証方法 docker run –rm ubuntu:24.04 で実際に実行・確認

WireGuardとフルメッシュトポロジー

WireGuardは Linux カーネル 5.6 からメインラインに取り込まれた VPN プロトコルです。設定ファイルの構造がシンプルで、「自分の秘密鍵」と「相手の公開鍵」を並べるだけでトンネルが張れます。

フルメッシュ(full mesh)は、すべてのノードが他のすべてのノードと直接 P2P で接続するトポロジーです。中継サーバー(ハブノード)を置かず、node1 から node3 へ通信するとき、node2 を経由しません。VPS を複数台運用する場合に多く使われます。

デメリットは設定量の増え方です。n 台のフルメッシュでは接続ペア数が n*(n-1)/2 になります。3台なら3ペアですが、5台になると10ペア、10台で45ペアと急増します。

フルメッシュVPNのノード数とピア数(概念表)
フルメッシュVPNのノード数とピア数(概念表)

wireguard-toolsをインストールする

Ubuntu 24.04 では wireguard-tools パッケージを apt で入れるだけです。カーネルモジュールはカーネルにビルトインなので、別途インストール不要です。




ubuntu@node1: ~
$ sudo apt update && sudo apt install -y wireguard-tools
Reading package lists… Done
The following NEW packages will be installed:
wireguard-tools nftables libmnl0 libxtables12 …
Setting up wireguard-tools (1.0.20210914-1ubuntu4) …
$ wg –version
wireguard-tools v1.0.20210914 – https://git.zx2c4.com/wireguard-tools/

インストールに成功すると /usr/bin/wg(鍵管理・状態確認コマンド)と /usr/bin/wg-quick(設定ファイルからのインターフェース起動スクリプト)の2つのコマンドが入ります。また、/usr/lib/systemd/system/wg-quick@.service の systemd ユニットが同梱されており、後で自動起動を設定するときに使います。

wireguard-tools インストールログ(ubuntu:24.04 実測)
wireguard-tools インストールログ(ubuntu:24.04 実測)

3台すべてで同じコマンドを実行してください。

Ubuntu 22.04 の場合

wireguard-tools のパッケージバージョンは 1.0.20210914-1ubuntu2 で、systemd ユニットのパスが /lib/systemd/system/wg-quick@.service になります(Ubuntu 24.04 は /usr/lib/)。機能面の差はありません。

Ubuntu 22.04 vs 24.04 wireguard-tools バージョン比較(実測)
Ubuntu 22.04 vs 24.04 wireguard-tools バージョン比較(実測)

3ノード分の鍵を生成する

WireGuard の鍵は Curve25519 を使います。秘密鍵は wg genkey で生成し、そこから公開鍵を wg pubkey で導出します。フルメッシュでは、加えてノードペアごとに事前共有鍵(PSK)を1本作ります。PSK は必須ではありませんが、量子コンピュータに対する追加の保護層になります。

鍵はどのノードで作っても構いません。作業用のマシン1台で3ノード分をまとめて生成し、各ノードに配布するのが一般的です。




ubuntu@node1: ~
$ NODE1_PRIV=$(wg genkey)
$ NODE1_PUB=$(echo “$NODE1_PRIV” | wg pubkey)
$ NODE2_PRIV=$(wg genkey)
$ NODE2_PUB=$(echo “$NODE2_PRIV” | wg pubkey)
$ NODE3_PRIV=$(wg genkey)
$ NODE3_PUB=$(echo “$NODE3_PRIV” | wg pubkey)
# ノードペアごとにPSKを生成(3ノード = C(3,2) = 3ペア)
$ PSK_12=$(wg genpsk) # node1 ↔ node2
$ PSK_13=$(wg genpsk) # node1 ↔ node3
$ PSK_23=$(wg genpsk) # node2 ↔ node3
$ echo $NODE1_PUB
oOigv2jHUXtrAeWfX8b4o0obHfiZb7/lv52H/mdQu3Q=
$ echo -n “$NODE1_PRIV” | base64 -d | wc -c
32
3ノードメッシュの鍵ペア生成(ubuntu:24.04 実測)
3ノードメッシュの鍵ペア生成(ubuntu:24.04 実測)

実測で確認した通り、wg genkey の出力は Base64 エンコードされた44文字の文字列で、デコードすると32バイト(256ビット)の Curve25519 秘密鍵になります。公開鍵も同じく44文字です。

秘密鍵の扱いに注意

生成した秘密鍵(NODE1_PRIV など)は絶対に外部に漏らさないでください。設定ファイルに書き込んだ後は chmod 600 /etc/wireguard/wg0.conf でパーミッションを制限します。公開鍵は他ノードに渡すために相手に教えて問題ありません。

各ノードのwg0.confを作成する

各ノードに /etc/wireguard/wg0.conf を作ります。設定の構造は「[Interface](自分の設定)+ [Peer](相手ノードの数だけ繰り返し)」です。

①node1 の wg0.conf

node1 は VPN アドレス 10.0.0.1/24 を持ち、node2 と node3 を [Peer] として登録します。




ubuntu@node1: /etc/wireguard
$ sudo nano /etc/wireguard/wg0.conf
[Interface]
PrivateKey = <NODE1_PRIV>
Address = 10.0.0.1/24
ListenPort = 51820

[Peer]
PublicKey = <NODE2_PUB>
PresharedKey = <PSK_12>
Endpoint = <node2の実IPまたはFQDN>:51820
AllowedIPs = 10.0.0.2/32
PersistentKeepalive = 25

[Peer]
PublicKey = <NODE3_PUB>
PresharedKey = <PSK_13>
Endpoint = <node3の実IPまたはFQDN>:51820
AllowedIPs = 10.0.0.3/32
PersistentKeepalive = 25

以下は docker run ubuntu:24.04 で実際に生成した設定ファイルの例です(鍵は実際の wg genkey 出力)。

node1 wg0.conf(実測生成・実鍵使用)
node1 wg0.conf(実測生成・実鍵使用)

設定ファイルを作ったら、権限を変更します。




ubuntu@node1: ~
$ sudo chmod 600 /etc/wireguard/wg0.conf
$ ls -la /etc/wireguard/
-rw——- 1 root root 627 Jun 21 15:59 wg0.conf

②node2 の wg0.conf

node2 は 10.0.0.2/24 を持ち、node1 と node3 を [Peer] に登録します。PSK に注意してください。node1 ↔ node2 のペアには PSK_12、node2 ↔ node3 のペアには PSK_23 を使います。




ubuntu@node2: /etc/wireguard
[Interface]
PrivateKey = <NODE2_PRIV>
Address = 10.0.0.2/24
ListenPort = 51820

[Peer]
PublicKey = <NODE1_PUB>
PresharedKey = <PSK_12> # ← node1↔node2 共通
Endpoint = <node1の実IP>:51820
AllowedIPs = 10.0.0.1/32
PersistentKeepalive = 25

[Peer]
PublicKey = <NODE3_PUB>
PresharedKey = <PSK_23> # ← node2↔node3 共通
Endpoint = <node3の実IP>:51820
AllowedIPs = 10.0.0.3/32
PersistentKeepalive = 25

③node3 の wg0.conf

node3 は 10.0.0.3/24 を持ち、node1 と node2 を [Peer] に登録します。PSK は PSK_13PSK_23 を使います。




ubuntu@node3: /etc/wireguard
[Interface]
PrivateKey = <NODE3_PRIV>
Address = 10.0.0.3/24
ListenPort = 51820

[Peer] # node1
PublicKey = <NODE1_PUB>
PresharedKey = <PSK_13>
Endpoint = <node1の実IP>:51820
AllowedIPs = 10.0.0.1/32
PersistentKeepalive = 25

[Peer] # node2
PublicKey = <NODE2_PUB>
PresharedKey = <PSK_23>
Endpoint = <node2の実IP>:51820
AllowedIPs = 10.0.0.2/32
PersistentKeepalive = 25
著者アイコン
著者アイコン

AllowedIPs = 10.0.0.2/32/32 にするのが詰まりやすいポイントです。/24 にすると「10.0.0.0/24 へのパケットは全部このピアへ」という意味になり、他のピアへのルーティングが上書きされてしまいます。フルメッシュではピアごとに /32 を指定するのが正解です。

インターフェースを起動して接続を確認する

3台すべての設定ファイルを配置したら、各ノードで wg-quick up wg0 を実行します。




ubuntu@node1: ~
$ sudo wg-quick up wg0
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.0.0.1/24 dev wg0
[#] ip link set mtu 1420 up dev wg0
(公式ドキュメントに基づく出力フォーマット例)
$ sudo wg show
interface: wg0
public key: oOigv2jHUXtrAeWfX8b4o0obHfiZb7/lv52H/mdQu3Q=
listening port: 51820

peer: dwyEqSDiQFrnNKJPPRen3XjuH3eCCwiH1s1pgNj5/kc=
endpoint: 192.168.1.2:51820
allowed ips: 10.0.0.2/32
latest handshake: (接続が確立すると秒数が表示される)
transfer: (受送信バイト数が表示される)

latest handshake: 〜 seconds ago が表示されれば接続が確立しています。ハンドシェイクが見えない場合はファイアウォールで UDP 51820 が開いていない可能性があります。上の端末ブロックは wg show の出力フォーマットを公式ドキュメントに基づいて示したものです。実際の transfer 値やハンドシェイク時間は環境によって異なります。

wg show の出力フォーマット参考(公式ドキュメントに基づく表示例)
wg show の出力フォーマット参考(公式ドキュメントに基づく表示例)



ubuntu@node1: ~
(接続が確立した場合の出力フォーマット例)
$ ping -c 3 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=X.XX ms
3 packets transmitted, 3 received, 0% packet loss
$ ping -c 3 10.0.0.3
64 bytes from 10.0.0.3: icmp_seq=1 ttl=64 time=X.XX ms
3 packets transmitted, 3 received, 0% packet loss

3台すべてから相互に ping が通れば、フルメッシュの完成です。実際のレイテンシはノード間の物理距離によって異なります(同一データセンター内なら1ms未満、異リージョン間なら数十ms程度が一般的です)。

systemdで自動起動を設定する

サーバーが再起動したときに WireGuard を自動で起動するには systemctl enable します。




ubuntu@node1: ~
$ sudo systemctl enable –now wg-quick@wg0
Created symlink /etc/systemd/system/wg-quick.target.wants/wg-quick@wg0.service
→ /usr/lib/systemd/system/wg-quick@.service.
(シンボリックリンクの作成先は Ubuntu 24.04 での実測値)
$ sudo systemctl status wg-quick@wg0
● wg-quick@wg0.service – WireGuard via wg-quick(8) for wg0
Loaded: loaded (/usr/lib/systemd/system/wg-quick@.service; enabled)
Active: active (exited)(接続確立後の正常状態)

active (exited) は正常な状態です。wg-quick はインターフェースを設定した後に終了するタイプのサービスなので、実行中(running)ではなく exited になります。

systemctl status wg-quick@wg0 の出力フォーマット例
systemctl status wg-quick@wg0 の出力フォーマット例

4台以上のメッシュを自動生成する

4台以上になると手作業での設定ミスが増えます。Python スクリプトで自動生成するのが現実的です。以下は3台分を例にした最小構成のスクリプトです。




ubuntu@node1: ~/wg-mesh
$ cat gen_mesh.py
#!/usr/bin/env python3
import subprocess, itertools, os

NODES = [
{“name”: “node1”, “endpoint”: “192.168.1.1”, “vpn_ip”: “10.0.0.1”},
{“name”: “node2”, “endpoint”: “192.168.1.2”, “vpn_ip”: “10.0.0.2”},
{“name”: “node3”, “endpoint”: “192.168.1.3”, “vpn_ip”: “10.0.0.3”},
]

def wg_genkey():
priv = subprocess.check_output([“wg”, “genkey”]).decode().strip()
pub = subprocess.check_output([“wg”, “pubkey”],
input=priv.encode()).decode().strip()
return priv, pub

# 鍵を生成
for n in NODES: n[“priv”], n[“pub”] = wg_genkey()

# PSK をペアごとに生成
psks = {}
for a, b in itertools.combinations(NODES, 2):
key = (a[“name”], b[“name”])
psks[key] = subprocess.check_output([“wg”, “genpsk”]).decode().strip()

# 各ノードの設定を出力
for n in NODES:
conf = f”[Interface]\n”
conf += f”PrivateKey = {n[‘priv’]}\n”
conf += f”Address = {n[‘vpn_ip’]}/24\n”
conf += f”ListenPort = 51820\n”
for peer in NODES:
if peer[“name”] == n[“name”]: continue
key = tuple(sorted([n[“name”], peer[“name”]]))
conf += f”\n[Peer]\n”
conf += f”PublicKey = {peer[‘pub’]}\n”
conf += f”PresharedKey = {psks[key]}\n”
conf += f”Endpoint = {peer[‘endpoint’]}:51820\n”
conf += f”AllowedIPs = {peer[‘vpn_ip’]}/32\n”
conf += f”PersistentKeepalive = 25\n”
print(f”# === {n[‘name’]} ===\n{conf}”)
$ python3 gen_mesh.py | head -20
# === node1 ===
[Interface]
PrivateKey = …
Address = 10.0.0.1/24
ListenPort = 51820

NODES リストにエントリを追加するだけで4台、5台のメッシュにも対応できます。生成した設定ファイルを各サーバーに scp で配布したあと、sudo wg-quick up wg0 を実行します。

よくあるエラーと解決策

①RTNETLINK answers: Operation not permitted




ubuntu@node1: ~
Error: RTNETLINK answers: Operation not permitted

原因:sudo なしで実行した、またはカーネルモジュールが読み込まれていない。sudo wg-quick up wg0 と先頭に sudo を付けて再実行してください。Ubuntu 22.04/24.04 ではモジュールはビルトインなので読み込み失敗は通常発生しません。

②latest handshake が表示されない(接続できない)

原因の大半は UDP 51820 ポートがファイアウォールでブロックされていることです。VPS を使っている場合、VPS のコントロールパネル側(セキュリティグループ)と OS 側(ufw)の両方を確認します。




ubuntu@node1: ~
$ sudo ufw allow 51820/udp
Rule added
$ sudo ufw status
51820/udp ALLOW Anywhere

③AllowedIPs 設定で他のノードに到達できない

AllowedIPs = 10.0.0.0/24 と書いた場合、そのピアが「VPN 内の全パケットの出口」になります。フルメッシュでは複数ピアがこの設定を持つと競合します。必ず AllowedIPs = <相手のVPN IP>/32 と指定してください

④設定変更後に反映されない




ubuntu@node1: ~
$ sudo wg-quick down wg0 && sudo wg-quick up wg0

wg syncconf でダウンタイムなしに設定を更新することもできますが、まずは down → up のほうが確実です。

まとめ

手順のまとめ

  • 全ノードで apt install wireguard-tools を実行(Ubuntu 22.04/24.04 は DKMS 不要)
  • wg genkey | wg pubkey で各ノードの鍵ペアを生成、wg genpsk でノードペアごとの PSK を生成
  • 各ノードの /etc/wireguard/wg0.conf に [Interface] と [Peer] × (n-1) を書く
  • AllowedIPs/32 で指定すること(フルメッシュでは /24 にしない)
  • wg-quick up wg0wg show で handshake を確認 → systemctl enable --now wg-quick@wg0 で自動起動
  • 4台以上では Python スクリプトで設定ファイルを自動生成するのが現実的

VPS を複数借りてサーバーを運用するなら、Vultr や DigitalOcean は複数リージョンに東京・シンガポール・欧米のリージョンを持ちつつ月5〜6ドルから始められます。WireGuardメッシュを組む前提なら、各ノードに独立した固定 IP があるプランが適しています。

複数 VPS の選び方については もあわせて読んでみてください。

コメント

タイトルとURLをコピーしました