v6プラスでもWireGuard VPNは使える? 実際に検証してみた
VPN ネットワーク WireGuard 検証 IPv6 IPv4
訳あって自宅にVPN環境を構築する必要が出てきました。
しかし自宅の回線はv6プラス(MAP-E)で使えるポートが240個に制限されます。
※なぜ制限されるかというと、v6プラス(MAP-E)は1つのグローバルIPv4を複数の契約者で共有する仕組みだからです。1つのIPを分け合っているため、ポートもそれに応じて分割され制限されます。
ポートの数が制限されているとはいえ、ISPから割り当てられた利用可能ポートを用いてUDP待受を行えればVPN接続は出来るはず。(理論上は)
実際に検証してみました。
今回の検証ポイント
・外部のIPv4アドレスから接続できる事
→外でVPN接続をいざするとなった際に、その環境が必ずしもIPv6アドレスが払い出されるという保証がありません。 IPv4アドレスが全く使えない接続環境は現実的にほぼ無いといっても過言では無いので「IPv4で接続を受け付ける」のが最重要。
試験環境
・インターネット回線 : v6プラス(MAP-E方式のIPv4 over IPv6)
・ルーター : NEC Aterm WG2600HS2(v6プラスモード、モデム直結のルーターモードで動作)
・サーバー(オンプレ) : Ubuntu Server 24.04 LTS。 ※使ってなかったデスクトップPCに直接Linuxをインストール。
・VPN : WireGuard
・接続確認端末 : iPhone13 pro(モバイル回線)、接続用のWireGuardアプリをインストール済み。
検証開始
早速検証していきます。
※OSはクリーンインストールして事前にパッケージ情報を更新済み。
まずは外部に出ていくグローバルIPv4アドレスを確認します。
curl -4 ifconfig.me
→ 表示されたIPv4アドレスをメモ。
(検証用のダミーとして203.0.113.10としておきます。)
次に利用できる割り当てポートの確認。
これはルーターの管理画面で確認できました。 その中から使用するポートを選択します。
(検証用のダミーとして51820としておきます。)

IPv4アドレスと割り当てポートを控えたら、いよいよWireGuardの設定です。
以下コマンドでインストール。
ちなみに、今まで全くWireGuardを触った事が無かったので知らなかったのですが、本体はLinuxカーネルに既に結合されているらしいです。下記のコマンドでインストールしているのは設定と管理をするためのツール群って事ですね。
sudo apt install -y wireguard
インストールが無事に完了したら、VPNクライアントの通信をサーバー経由でインターネットに抜けさせるためにIPv4のパケット転送を有効化します。
設定ファイルに記述しておいて、再起動後も維持されるようにしました。
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl -p /etc/sysctl.d/99-wireguard.conf
次に鍵ペアの作成です。
WireGuardは公開鍵暗号で認証します。OpenVPNのような認証局(CA)は不要で、サーバーとクライアントそれぞれの鍵ペアを作るだけ。とっても簡潔ですね。
鍵ファイルは所有者だけが読める権限に設定しています。
umask 077
sudo sh -c 'wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key'
sudo sh -c 'wg genkey | tee /etc/wireguard/client_private.key | wg pubkey > /etc/wireguard/client_public.key'
次にサーバー設定ファイルを作成します。
Addressに記載するのは、先ほどメモったIPv4アドレスではなく、VPN専用の仮想アドレスです。 ListenPortは待ち受けポートで、事前にメモったポート番号を記載します。 PrivateKeyにはサーバー自身の秘密鍵を記述。
PostUp/PostDown は、トンネルの起動・停止時にNAT(マスカレード)と転送許可を設定/解除する処理で、VPN経由の通信をインターネットへ抜けさせるために必要。
[Peer] は接続を許可するクライアントの定義で、PublicKey にはクライアントの公開鍵を記述します。
sudo tee /etc/wireguard/wg0.conf > /dev/null << 'EOF'
[Interface]
Address = 10.9.0.1/24
ListenPort = 51820
PrivateKey = <サーバーの秘密鍵>
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o enp2s0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o enp2s0 -j MASQUERADE
[Peer]
PublicKey = <クライアントの公開鍵>
AllowedIPs = 10.9.0.2/32
EOF
設定ファイルが書き終わったら、ファイアウォールの許可をしておきます。
ついでにWireGuardも起動しておきます。
sudo ufw allow 51820/udp
sudo systemctl enable --now wg-quick@wg0
もう一息です。
クライアントの設定ファイルを作成しましょう。
[Peer]のEndpointに、最初の手順で確認したIPv4アドレスとポート番号を指定します。
クライアントはこのEndpointに向かって接続しに行くって事ですね。
AllowedIPs = 0.0.0.0/0 は全通信をVPN経由にするフルトンネル設定。
PersistentKeepalive = 25 はNAT越え環境で接続を維持するための設定です。
sudo tee /etc/wireguard/client.conf > /dev/null << 'EOF'
[Interface]
PrivateKey = <クライアントの秘密鍵>
Address = 10.9.0.2/24
DNS = 1.1.1.1
[Peer]
PublicKey = <サーバーの公開鍵>
Endpoint = 203.0.113.10:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
EOF
サーバー側の設定作業はこれで完了です。
しかし、今のままでは通信ができません。
外部からの待受けポート(UDP)を、サーバーのLAN内部IPの同一ポートへ転送しないと通信が通らないからです。
こちらもルーター側の設定画面でNATエントリの追加項目があったので設定は簡単にできました。
(ルーターの機種によってこの設定自体が出来ない物もあるんですかね?その場合構築自体できるのかどうか・・)
優先度は1。 LAN側ホストはサーバーの物理NICのIPを調べて記入。(例:192.168.10.x)
プロトコルはUDP。 変換対象ポート番号、宛先ポート番号は共に「51820」です。

最後に検証用クライアント(iPhone13 pro)のWireGuardアプリに設定ファイルを取り込んで完了です。
実はqrencodeというパッケージツールを導入すれば、設定ファイルをターミナル上でQRコード化してそのまま取り込めるというので実際に利用してみたのですが、 形式が崩れてしまい取り込める状態になりませんでした。 (SSHでサーバーを操作してたから?)
検証スコープではないのでさっさとファイル転送に切り替えましたが、形式崩れは 何か理由がありそうなので別の機会に確認します。
それではいよいよVPNの接続テストです。
検証用クライアントのWi-fi接続を停止して、VPNを起動。
UIがあまりに簡素。
VPNをオンにしても画面上では何も変化なし。ステータスとか表示されないんですね。

ちゃんと接続できているか不安だったのですが、cman.jpでIPを確認してみた所、ちゃんと自宅のIPv4アドレスが表示されました。

検証結果
IPv6プラスの環境でも、利用可能ポートを明示してあげればIPv4アドレスを利用したVPNの構築は可能。
「MAP-E環境ではVPNサーバーは立てられない」という情報もたまに見かけますが、少なくとも今回のv6プラス環境では、割り当てポートを正しく利用する事でIPv4経由のWireGuard接続が成立しました。
今回は接続成立までを検証しましたが、実用にあたっては速度や複数クライアントの管理など、詰めるべき点も見えてきました。
このあたりは別の機会に検証してみたいと思います。