WireGuard
WireGuard のホームページより:
- Wireguard は最先端の暗号技術を使用する非常にシンプルで高速な VPN です。IPSec よりも高速・単純・軽量・有用であることを目指しており、面倒なことを避けています。OpenVPN と比べると高いパフォーマンスを発揮します。WireGuard は組み込みインターフェイスからスーパーコンピュータまで様々な環境に対応する汎用の VPN として設計されています。最初は Linux カーネル用にリリースされましたが、現在はクロスプラットフォーム(Windows、macOS、BSD、iOS、Android)であり、広く展開できます。
この記事で使用されている主な概念の大まかな紹介は、WireGuard のプロジェクトホームページにあります。 WireGuard は、2019年後半から Linux カーネルに組み込まれています。
インストール
ユーザースペースユーティリティの wireguard-tools パッケージをインストールしてください。
または、ピアキーが使用可能な場合、さまざまなネットワークマネージャーが WireGuard のサポートを提供します。詳細については、#設定の永続化 を参照してください。
グラフィカルクライアント
- Qomui — 高度な機能と複数のプロバイダーのサポートを備えた OpenVPN GUI。
Command-line tools
- wg_tool — Tool to manage wireguard configs for server and users.
使用方法
ここでは以下の構成でピア間のトンネルを設定する方法を説明します:
Peer A | Peer B | |
---|---|---|
外部 IP アドレス | 10.10.10.1/24 | 10.10.10.2/24 |
内部 IP アドレス | 10.0.0.1/24 | 10.0.0.2/24 |
wireguard 使用ポート | UDP/48574 | UDP/39814 |
外部アドレスはあらかじめ用意してください。例えば、ピア A からピア B に ping 10.10.10.2
で ping が通るようにする必要があります。内部アドレスは ip
コマンドで作成する新しいアドレスで、WireGuard ネットワーク内で内部的に共有します。IP アドレスの /24
は CIDR です。
鍵の生成
秘密鍵を作成するには:
$ wg genkey > privatekey
公開鍵を作成するには:
$ wg pubkey < privatekey > publickey
もしくは、秘密鍵と公開鍵を同時に作成するには:
$ wg genkey | tee privatekey | wg pubkey > publickey
量子コンピュータが実用化された場合を考慮して、既存の公開鍵暗号に対称鍵暗号のレイヤーを追加するために事前共有鍵を生成することもできます:
# wg genpsk > preshared
Peer A の設定
このピアでは UDP ポート 48574 を開いて内部・外部 IP アドレスと公開鍵を紐づけてピア B からの接続を許可します:
# ip link add dev wg0 type wireguard # ip addr add 10.0.0.1/24 dev wg0 # wg set wg0 listen-port 48574 private-key ./privatekey # wg set wg0 peer [Peer B public key] persistent-keepalive 25 allowed-ips 10.0.0.2/32 endpoint 10.10.10.2:39814 # ip link set wg0 up
[Peer B public key]
は EsnHH9m6RthHSs+sd9uM6eCHe/mMVFaRh93GYadDDnM=
という形式で指定してください。allowed-ips
はトラフィックの送信を許可するアドレスのリストを指定してください。allowed-ips 0.0.0.0/0
であらゆるアドレスにトラフィックを送信できるようになります。
Peer B の設定
ピア A とほとんど同じですが、wireguard デーモンで使用するのは UDP ポート 39814 でピア A からの接続だけを許可します:
# ip link add dev wg0 type wireguard # ip addr add 10.0.0.2/24 dev wg0 # wg set wg0 listen-port 39814 private-key ./privatekey # wg set wg0 peer [Peer A public key] persistent-keepalive 25 allowed-ips 10.0.0.1/32 endpoint 10.10.10.1:48574 # ip link set wg0 up
基本チェック
パラメータを付けずに wg コマンドを呼び出すことで現在の設定を確認できます。
例えば、ピア A で実行すると以下のように表示されます:
peer-a$ wg interface: wg0 public key: UguPyBThx/+xMXeTbRYkKlP0Wh/QZT3vTLPOVaaXTD8= private key: (hidden) listening port: 48574 peer: 9jalV3EEBnVXahro0pRMQ+cHlmjE33Slo9tddzCVtCw= endpoint: 10.10.10.2:39814 allowed ips: 10.0.0.2/32
トンネルの末端にアクセスすることができるはずです:
peer-a$ ping 10.0.0.2
設定の永続化
showconf
を使うことで設定を保存できます:
# wg showconf wg0 > /etc/wireguard/wg0.conf # wg setconf wg0 /etc/wireguard/wg0.conf
ピア設定例
/etc/wireguard/wg0.conf
[Interface] Address = 10.0.0.1/32 PrivateKey = [CLIENT PRIVATE KEY] MTU = 1420 [Peer] PublicKey = [SERVER PUBLICKEY] AllowedIPs = 10.0.0.0/24, 10.123.45.0/24, 1234:4567:89ab::/48 Endpoint = [SERVER ENDPOINT]:51820 PersistentKeepalive = 25
systemd-networkd の設定例
/etc/systemd/network/30-wg0.netdev
[NetDev] Name = wg0 Kind = wireguard Description = Wireguard [WireGuard] PrivateKey = [CLIENT PRIVATE KEY] [WireGuardPeer] PublicKey = [SERVER PUBLIC KEY] PresharedKey = [PRE SHARED KEY] AllowedIPs = 10.0.0.0/24 Endpoint = [SERVER ENDPOINT]:51820 PersistentKeepalive = 25
/etc/systemd/network/30-wg0.network
[Match] Name = wg0 [Network] Address = 10.0.0.3/32 DNS = 10.0.0.1 [Route] Gateway = 10.0.0.1 Destination = 10.0.0.0/24
VPN サーバーの設定
このセクションでは OpenVPN などと同じように暗号化されたトンネルを使ってサーバー・ネットワークリソースにアクセスできるようにするため、WireGuard の「サーバー」と汎用的な「クライアント」を設定します。サーバーは Linux で稼働させますがクライアントのプラットフォームは複数選択できます (WireGuard プロジェクトは Linux ネイティブや macOS のソフトウェアに加えて iOS や Android プラットフォームのアプリも提供しています)。詳しくは公式プロジェクトの インストールリンク を見てください。
サーバー
サーバー側のマシンではまず IPv4 フォワーディングを有効にしてください:
# sysctl net.ipv4.ip_forward=1
変更を永続化するには /etc/sysctl.d/99-sysctl.conf
に net.ipv4.ip_forward = 1
を追加します。
インターネットに接続する場合はファイアウォールを設定することが推奨されます:
- WireGuard が動作するポートの UDP トラフィックを許可してください (例えば 51820/udp のトラフィックを許可)。
- WireGurad の設定
/etc/wireguard/wg0.conf
に転送ポリシーを記述しない場合はファイアウォールで転送ポリシーを設定してください。以下の例はそのまま動作します。
最後に、WAN からアクセスできるようにするため WireGuard のポートをルーターからサーバーの LAN の IP に転送するようにする必要があります。
鍵の生成
サーバーとクライアントの鍵を#鍵の生成で説明しているように生成してください。
サーバーの設定
サーバーの設定ファイルを作成:
/etc/wireguard/wg0.conf
[Interface] Address = 10.200.200.1/24 SaveConfig = true ListenPort = 51820 PrivateKey = [SERVER PRIVATE KEY] MTU = 1420 # note - substitute eth0 in the following lines to match the Internet-facing interface PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE [Peer] # client foo PublicKey = [FOO's PUBLIC KEY] PresharedKey = [PRE-SHARED KEY] AllowedIPs = 10.200.200.2/32 [Peer] # client bar PublicKey = [BAR's PUBLIC KEY] PresharedKey = [PRE-SHARED KEY] AllowedIPs = 10.200.200.3/32
インターフェイスは手動あるいは systemctl で制御できます。
wg-quick up wg0
でインターフェイスが立ち上がり wg-quick down wg0
で終了します。
systemctl で制御したい場合、wg-quick@.service
を起動・有効化してください。"@" 記号の後ろにサーバーの設定の名前を入力してください。例:
# systemctl start wg-quick@wg0
クライアントの設定
クライアントの設定ファイルを作成:
foo.conf
[Interface] Address = 10.200.200.2/24 PrivateKey = [FOO's PRIVATE KEY] DNS = 10.200.200.1 MTU = 1420 [Peer] PublicKey = [SERVER PUBLICKEY] PresharedKey = [PRE-SHARED KEY] AllowedIPs = 0.0.0.0/0 Endpoint = my.ddns.address.com:51820
bar.conf
[Interface] Address = 10.200.200.3/24 PrivateKey = [BAR's PRIVATE KEY] DNS = 10.200.200.1 MTU = 1420 [Peer] PublicKey = [SERVER PUBLICKEY] PresharedKey = [PRE-SHARED KEY] AllowedIPs = 0.0.0.0/0 Endpoint = my.ddns.address.com:51820
クライアントがスマートフォンなどの場合、qrencode を使って設定を共有することができます:
$ qrencode -t ansiutf8 < foo.conf
Testing the tunnel
Once a tunnel has been established, one can use netcat to send traffic through it to test out throughput, CPU usage, etc.
On one side of the tunnel, run nc
in listen mode and on the other side, pipe some data from /dev/zero
into nc
in sending mode.
In the example below, port 2222 is used for the traffic (be sure to allow traffic on port 2222 if using a firewall).
On one side of the tunnel listen for traffic:
$ nc -vvlnp 2222
On the other side of the tunnel, send some traffic:
$ dd if=/dev/zero bs=1024K count=1024 | nc -v 10.0.0.203 2222
Status can be monitored using wg
directly.
# wg
interface: wg0 public key: UguPyBThx/+xMXeTbRYkKlP0Wh/QZT3vTLPOVaaXTD8= private key: (hidden) listening port: 51820 peer: 9jalV3EEBnVXahro0pRMQ+cHlmjE33Slo9tddzCVtCw= preshared key: (hidden) endpoint: 192.168.1.216:53207 allowed ips: 10.0.0.0/0 latest handshake: 1 minutes, 17 seconds ago transfer: 56.43 GiB received, 1.06 TiB sent
ヒントとテクニック
秘密鍵を暗号化して保存
設定ファイルの [Interface] セクションの PrivateKey 行を以下のように置き換えることで pass を使って秘密鍵を暗号化できます:
PostUp = wg set %i private-key <(su user -c "export PASSWORD_STORE_DIR=/path/to/your/store/; pass WireGuard/private-keys/%i")
user はユーザー名に置き換えてください。詳しくは wg-quick(8) を参照。
IP が変わるエンドポイント
サーバーのドメインの解決後、WireGuard は DNS で再度変更をチェックすることはありません [1]。
WireGuard サーバーの IP アドレスが DHCP, Dyndns, IPv6 などによって頻繁に変更された場合、WireGuard クライアントは接続を失います。その際 wg set "$INTERFACE" peer "$PUBLIC_KEY" endpoint "$ENDPOINT"
などのようにエンドポイントを更新しなくてはなりません。
また、エンドポイントがアドレスを変更したとき (例えば新しいプロバイダ・データセンターに移行した場合)、DNS を更新するだけでは不十分となるため、DNS ベースのセットアップでは reresolve-dns を定期的に実行する必要が出てきます。
wireguard-tools には WG の設定ファイルを読み込んでエンドポイントのアドレスを自動的にリセットするスクリプト /usr/share/wireguard/examples/reresolve-dns/reresolve-dns.sh
が含まれています。
/usr/share/wireguard/examples/reresolve-dns/reresolve-dns.sh /etc/wireguard/wg.conf
を定期的に実行することで IP が変わったエンドポイントから復旧できます。
systemd タイマーを使って30秒ごとに WireGuard のエンドポイントを更新する例 [2]:
/etc/systemd/system/wireguard_reresolve-dns.timer
[Unit] Description=Periodically reresolve DNS of all WireGuard endpoints [Timer] OnCalendar=*:*:0/30 [Install] WantedBy=timers.target
/etc/systemd/system/wireguard_reresolve-dns.service
[Unit] Description=Reresolve DNS of all WireGuard endpoints Wants=network-online.target After=network-online.target [Service] Type=oneshot ExecStart=/bin/sh -c 'for i in /etc/wireguard/*.conf; do /usr/share/wireguard/examples/reresolve-dns/reresolve-dns.sh "\$i"; done'
上記ファイルを作成したら wireguard_reresolve-dns.timer
を起動・有効化してください。
Generate QR code
If the client is a mobile device such as a phone, qrencode can be used to generate client's configuration QR code and display it in terminal:
$ qrencode -t ansiutf8 -r client.conf
Enable debug logs
When using the Linux kernel module on a kernel that supports dynamic debugging, debugging information can be written into the kernel ring buffer (viewable with dmesg and journalctl) by running:
# modprobe wireguard # echo module wireguard +p > /sys/kernel/debug/dynamic_debug/control
Reload peer (server) configuration
In case the WireGuard peer (mostly server) adding or removing another peers from its configuration and wants to reload it without stopping any active sessions, one can execute the following command to do it:
# wg syncconf ${WGNET} <(wg-quick strip ${WGNET})
Where $WGNET
is WireGuard interface name or configuration base name, for example wg0
(for server) or client
(without the .conf extension, for client).
トラブルシューティング
ルートが定期的にリセットされる
NetworkManager が WireGuard のインターフェイスを管理しないようにしてください:
/etc/NetworkManager/conf.d/unmanaged.conf
[keyfile] unmanaged-devices=interface-name:wg0
NetworkManager で切断される
デスクトップの場合、全てのトラフィックを WireGuard のインターフェイス経由にすると切断が発生することがあります。アクセスポイントに新しく接続してしばらくした後に切断が発生します。
デフォルトでは wg-quick は openresolv などの resolvconf プロバイダを使用して新しい DNS エントリを登録します (設定ファイルの DNS
キーワード)。しかしながら NetworkManager はデフォルトでは resolvconf を使用しません。新しい DHCP リースが取得されるたびに NetworkManager は DHCP によって提供されたアドレスで全体の DNS アドレスを上書きします。
resolvconf を使う
システムで resolvconf を使っていて接続が切れる場合、NetworkManager が resolvconf を使うように設定してください:
/etc/NetworkManager/conf.d/rc-manager.conf
[main] rc-manager=resolvconf
dnsmasq を使う
Dnsmasq#openresolv を見てください。
systemd-resolved を使う
2018年9月時点では、systemd-resolvconf による resolvconf 互換モードは wg-quick で機能しません。ただし PostUp
フックを使うことで wg-quick から systemd-resolved を使用することはできます。まず NetworkManager で systemd-resolved を使うように設定: NetworkManager#systemd-resolved。それからトンネルの設定を変更:
/etc/wireguard/wg0.conf
[Interface] Address = 10.0.0.2/24 # The client IP from wg0server.conf with the same subnet mask PrivateKey = [CLIENT PRIVATE KEY] PostUp = resolvectl domain %i "~."; resolvectl dns %i 10.0.0.1; resolvectl dnssec %i yes MTU = 1420 [Peer] PublicKey = [SERVER PUBLICKEY] AllowedIPs = 0.0.0.0/0, ::0/0 Endpoint = [SERVER ENDPOINT]:51820 PersistentKeepalive = 25
新しく利用可能になった DNS サーバーに優先度を与えるためにドメイン名は "~."
に設定する必要があります。
wg0
が落ちたときに systemd-resolved は自動的に全てのパラメータを戻すため PostDown
キーは必要ありません。