WireGuardを使って、ラズパイ4をVPNサーバーとして使えるようにしたので、その際の手順をメモします。
WireGuardは、各ノード(ピア)間で通信する仕組みになっており、サーバー・クライアントという概念にはなじまないのですが、便宜上、ラズパイ4をサーバー、スマホをクライアントとし、スマホで外出先からモバイル回線経由で自宅内ラズパイ4サーバーにVPN接続し、スマホからVPN経由でIPv4/IPv6のどちらでもインターネットに出ていけるようにすることを目標とします。
1. (サーバー)WireGuardのインストール
2. (クライアント)WireGuardアプリのインストール
3. (サーバー・クライアント)キーペアの生成
4. (サーバー・クライアント)鍵およびその他の設定
5. (サーバー)パケットの転送・マスカレードの設定
6. WireGuardでのVPN通信開始と終了
7. 感想
1. (サーバー)WireGuardのインストール
WireGuardは、Linux 5.6以降のカーネルに含まれており、さらにDebian 11(bullseye)以降はツール等のパッケージが公式のリポジトリに含まれており、インストールできるようになっています。
これからWireGuardをインストールしようとしているラズパイには、Raspberry Pi OS(Release date:April 4th 2022, 64bit, Linux kernel 5.15, Debian 11(bullseye))が入っており、Linux 5.6以降かつDebian 11(bullseye)以降なので、以下のようにすれば、サーバー側でのWireGuardのインストールは完了します。
$ sudo apt install wireguard
以前はWireGuardを使うには、ソースコードから自分でビルドするか、バックポートのリポジトリを追加する必要があったのですが、現在はそうした手間なく、簡単にインストールできます。
2. (クライアント)WireGuardアプリのインストール
クライアントとなるスマホにWireGuardアプリをインストールします。サーバー・クライアント双方で秘密鍵および公開鍵(キーペア)の生成および設定を行いますので、最初にアプリをインストールしてしまいましょう。iOS版、Android版のどちらもあります。
3. (サーバー・クライアント)キーペアの生成
各ノード(ピア)には秘密鍵・公開鍵のペア(キーペア)を作成し、各ノードに相手方ノードと通信するために必要な情報として設定していきます。
まず、サーバー側で秘密鍵・公開鍵を作ります。
$ wg genkey >privatekey
$ wg pubkey
privatekey、publickeyのいずれもテキストファイルになっており、privatekeyに秘密鍵、publickeyに公開鍵が入っています。
続いで、スマホ側で秘密鍵・公開鍵を作ります。iOS版アプリ、Android版アプリのいずれにもキーペアを生成する機能があるので、これを使って作ります。
サーバー側、およびクライアント側の両方でキーペアを作成したら、公開鍵を相手方ノードで設定できるようにメール等なんらかの手段で送信します。
4. (サーバー・クライアント)鍵およびその他の設定
サーバー側の設定ファイル(/etc/wireguard/wg0.conf)を作成します。上記で作成した秘密鍵・公開鍵は、ここで設定します。
$ sudo cat /etc/wireguard/wg0.conf
[Interface]
Address = 10.0.0.1/24,fd::1/64
ListenPort = 51820
PrivateKey = (サーバーの秘密鍵)
PreUp = sysctl --write net.ipv4.ip_forward=1
PreUp = sysctl --write net.ipv6.conf.all.forwarding=1
PreUp = systemctl start nftables
PostDown = systemctl stop nftables
PostDown = sysctl --write net.ipv6.conf.all.forwarding=0
PostDown = sysctl --write net.ipv4.ip_forward=0
[Peer]
PublicKey = (クライアント(iPhone)の公開鍵)
PresharedKey = (クライアント(iPhone)の事前共有鍵)
AllowedIPs = 10.0.0.2/32,fd::2/128
[Peer]
PublicKey = (クライアント(Android)の公開鍵)
PresharedKey = (クライアント(Android)の事前共有鍵)
AllowedIPs = 10.0.0.3/32,fd::3/128
IPアドレスは、IPv4についてはサーバーは10.0.0.1/24、クライアントは、iPhoneが10.0.0.2/24、Androidが10.0.0.3/24になるように設定しています。IPv6については、ULA(ユニークローカルアドレス)を使うこととして、サーバーはfd::1/64、クライアントは、iPhoneがfd::2/64、Androidがfd::3/64になるように設定しています。(ULAのアドレスについては、MACアドレスを使って決める推奨された方法があって、こんな簡単なアドレスにはならないのですが、VPN通信時に一時的に使う小規模なネットワーク設定のサンプルということもあり、この簡単なアドレスを本記事では使います。)
サーバー側の設定において、[Interface]のAddressにはサーバーのIPアドレスを設定し、ListenPortには待ち受けポート番号を設定します。WireGuardのデフォルトのポート番号は51820ですが、変更可能です。プロトコルはUDPのみです。各ピアについて、wg0.confの[Peer]のAllowedIPsに記載されたホストとのみ通信が可能となります。サブネットマスクがIPv4は/32、IPv6は/128となっているのはそういう意味です。なおwg0.confには、秘密鍵が記載されていますので、ファイルのパーミッションは600に設定します。
続いて、クライアント側を設定します。iPhone版/Android版双方のWireGuardアプリの設定画面のスクショを以下に示します。
クライアント側の設定において、ピアの公開鍵にはサーバーの公開鍵を設定し、エンドポイントには、サーバーのホスト名(又はIPアドレス)およびポート番号を設定します。ホスト名がfoo.barでポート番号がbazの場合は、foo.bar:baz と設定します。自宅ルーターのポートを開けた上でダイナミックDNS等を使ってインターネット経由で自宅内サーバーにアクセスしている場合は、そのホスト名とポート番号になります。
Allowed IPsには、サーバー側の設定時とは異なってクライアント側の設定時には、そのピアに流すパケットの宛先のIPアドレスを指定します。「0.0.0.0/0,::/0」は、IPv4/IPv6ともにすべてのパケットをこのピアに流すという意味になります。
5. (サーバー)パケットの転送・マスカレードの設定
上記の設定で、クライアント~サーバー間でVPNを確立できるようになるものの、これだけだと、クライアントからVPN経由でインターネットに出ていけないので、サーバー側にパケットの転送およびマスカレードの設定を行います。
パケットの転送やマスカレードの設定に以前はiptablesを使っていたと思いますが、Debian 11(bullseye)には標準ではiptablesがインストールされておらず(パッケージでのインストールは可能)、nftablesの利用が推奨されているので、nftablesで設定します。
nftablesを使うと、IPv4とIPv6をまとめて「inet」として記述できるので、すっきりした記述になります。
$ sudo cat /etc/nftables.conf
table inet filter {
chain input {
type filter hook input priority filter; policy accept;
}
chain forward {
type filter hook forward priority filter; policy accept;
iifname "eth0" accept
oifname "eth0" accept
}
chain output {
type filter hook output priority filter; policy accept;
}
}
table inet nat {
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
}
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
oifname "eth0" masquerade
}
}
6. WireGuardでのVPN通信開始と終了
サーバー側で以下のようにコマンド入力すれば、設定したwg0インターフェースが有効になり、クライアント側からのVPN通信が可能となります。
$ sudo systemctl start wg-quick@wg0
スマホのWireGuardアプリでVPNを有効化すれば、スマホのすべてのトラフィックがVPN経由になります。サーバー側のwg0インターフェースを無効にするには、以下のように入力します。
$ sudo systemctl stop wg-quick@wg0
ラズパイ起動時にwg0インターフェースが自動的に有効になるようにするには、以下のように入力します。
$ sudo systemctl enable wg-quick@wg0
7. 感想
過去に、ヤマハのルーターでL2TP/IPsecを設定したり、OpenVPNのサーバーを立てて設定したことがありますが、それらと比べると、WireGuardは設定がシンプルでわかりやすいのが素晴らしいです。
IPv4もIPv6も使えるということで、正式にはIPv6に対応していないLINEMO利用時にIPv6を使ったり、IPv6オンリーのネットワークを作ってどの程度実用になるか試してみる、等々用途・使い道は無数に広がります。