WireGuardでVPN接続する。

# はじめに
出先から自宅のネットワークにアクセスする際、今までは自宅で使っているQNAPのNASにインストールされている`OpenVPN`でVPN接続を行っていましたが、QNAP NASで`WireGuard`も使用できたので試しに使ってみたところ、`WireGuard`の使い勝手が良かったので紹介したいと思います。

# WireGuardとは
比較的最近登場したオープンソースのVPN技術となりますが、2020年にはLinuxのカーネルツリーにも統合されている注目のVPN技術となります。

ソースコードが他のVPNのソース（約400,000〜600,000行）より圧倒的にシンプル（約4,000行）なこともあり、`OpenVPN`や`IPsec`を使用したVPNと比べてパフォーマンスが良く、また、以下のように通信シーケンスがシンプルなことから、例えば移動中などネットワークが頻繁に切り替わるような状況に強いVPN技術だそうです。

```mermaid
sequenceDiagram
    participant init as イニシエータ
    participant resp as レスポンダ
    init->>resp: Handshake Initiation
    resp->>init: Handshake Response
    init->>resp: Transport Data
    resp->>init: Transport Data
```

また、`WireGuard`ではサーバおよびクライアントの秘密鍵・公開鍵を使う公開鍵暗号方式でVPNトンネルを生成するため、`WireGuard`の設定としては秘密鍵・公開鍵の設定を行うだけでVPN接続を行うことが出来ますが、`WireGuard`自体にはユーザ認証機能は無いため、逆に言うとVPNの設定情報が漏洩すれば誰でも接続出来てしまうことから、企業での導入を行う場合は慎重に検討する必要があるかと思います。

専用VPN装置同士で接続を行う拠点間VPNならともかく、PCなどから接続を行うリモートアクセス方式であればユーザ認証が欲しいところではありますが、今回は個人用途の使用であり、ユーザ認証はともかくトンネルのセキュリティは他のVPNと比べても高セキュリティとなっているため、導入する際にはそのような特徴を考慮してもらえればと思います。

# QNAP NASでのWireGuard設定
以下より`WireGuard`のサーバ・クライアントの設定と`WireGuard`のサーバ側となるQNAPへアクセスするためのルータ設定を行っていきます。

- [ルータの設定](#ルータの設定)
- [WireGuardサーバ側初期設定](#wireguardサーバ側初期設定)
- [WireGuardクライアント側設定](#wireguardクライアント側設定)
- [WireGuardサーバ側Peer設定](#wireguardサーバ側peer設定)

また、おまけとしてオンデマンド接続の有効化とQRコードでのスマートフォン等の設定も行っていきます。

- [オンデマンド接続の有効化](#オンデマンド接続の有効化)
- [QRコードでのクライアント設定](#qrコードでのクライアント設定)

## ルータの設定
`WireGuard`のサービスを動作させているQNAPはルータの内側にいるので、`WireGuard`が使用する**UDPの51820ポート**の通信が来たときにQNAPのアドレスに転送するように設定します。

ルータによって呼び方は様々ですが、ポートフォワーディングや静的IPマスカレードといった名前の設定になります。

以下私の環境での設定。

![Monosnap_20230826_143101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/accd0f7d-0792-2467-fef3-527bb1207c53.png)

## WireGuardサーバ側初期設定
`WireGuard`のサーバ側となるQNAP側の初期設定を行っていきます。

- [WireGuardの有効化](#wireguardの有効化)
- [事前共有キーの生成](#事前共有キーの生成)

### WireGuardの有効化
QNAP側の初期設定は簡単で、有効化のチェックを行った後、以下のように適当なサーバ名とDNSサーバアドレスを入力、「**キーペアの生成**」を選択すると、プライベートキーと、クライアント側に設定するパブリックキーが生成されるため、パブリックキーを控えておきます。

ネットワークインタフェースはVPN接続した際にQNAP NASのどのインタフェースに結びつけるかの設定となるので、ローカルネットワークと繋がっているアダプタを指定しました。

![Monosnap_20230826_143546.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/ab888cca-e1f9-6f29-cf39-bfe59a1377ea.png)

### 事前共有キーの生成
単純に`WireGuard`で繋ぐだけなら事前共有キーの設定を行わなくても接続できますが、今回は事前共有キーも設定して少しでもセキュリティを向上させたいと思います。

後ほど設定する事前共有鍵も生成しておきます。

事前共有鍵はQNAP NASのGUI画面からは生成出来ないのでSSHでQNAP NASに接続を行い、以下`WireGuard`のコマンドを実行して事前共有鍵を生成します。

ファイルとして保存しておきたい場合は出力をリダイレクトして保存しておきます。

画面に表示される事前共有鍵はサーバ側、クライアント側双方に設定するため控えておいてください。

```bash:事前共有鍵の生成
wg genpsk
```

ファイルとして保存した場合、以下のように誰でもアクセスできてしまうため、権限変更するよう警告がでます。

```bash:ファイル出力した際に表示されるメッセージ
Warning: writing to world accessible file.
Consider setting the umask to 077 and trying again.
```

そのため、ファイルとして保存しておきたい場合は以下のように権限を変更しておきましょう。

```bash:権限変更
chmod 600 [ファイル出力した事前共有鍵ファイル]
```

## WireGuardクライアント側設定
以下からはVPN接続を行うクライアント側で設定していきます。

今回のVPN構成はリモートアクセス方式でのVPN接続を想定しているため、クライアント側のグローバルIPアドレスは不定の前提で進めます。

- [WireGuardクライアントのインストール](#wireguardクライアントのインストール)
- [WireGuardクライアントの設定](#wireguardクライアントの設定)

### WireGuardクライアントのインストール
接続するクライアント側に`WireGuard`のクライアントをインストールします。

今回は`MacOS`にインストールを行ったので、`AppStore`から`WireGuard`をインストールしました。

### WireGuardクライアントの設定
以下はすでに設定が完了している画面となるため、既存設定が表示されておりますが、初回起動時は何も表示がされていないため、画面左下の「**＋**」から「**設定が空のトンネルを追加**」を選択します。

![スクリーンショット 2023-08-26 15.16.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/cc68ffc1-fa76-d51d-d62c-c0b410e52cff.png)

空のトンネルを追加すると、以下のように設定画面（というか設定を直接書き込んでいく画面）が表示されるので、適当な名前を設定。

公開鍵は後ほどQNAP NAS側の設定で必要となるため、こちらも控えておきます。

オンデマンドは常時`WireGuard`でVPN接続を行う場合にどのインタフェースが接続されている場合に有効とするかの設定で、`Wi-Fi`にチェックを行った場合、特定のSSIDに接続した場合のみ自動接続を行ったり、指定したSSID以外のネットワークに接続した場合に自動接続を行ったりすることができるので、外出時のみ自動接続するようにしておくと便利です。

![Monosnap_20230826_152251.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/1e713b8f-58e5-3dff-e7a4-adbccf73a614.png)

上記の画面に直接設定値を書き込んでいくため、コマンドラインに慣れていないと若干ハードルが高いですが、今回は以下のように設定しました。

```text:クライアント側設定
[Interface]
PrivateKey = [プライベートキー]
Address = 198.18.7.2/32

[Peer]
PublicKey = [先程控えたQNAP側のパブリックキー]
AllowedIPs = 198.18.7.1/32, 192.168.X.0/24
Endpoint = [DDNS名]:51820
PersistentKeepalive = 10
PresharedKey = [先程控えた事前共有鍵]
```

上記設定の場合、「**[Interface]**」が自分側（クライアント側）の設定、「**[Peer]**」が相手側（QNAP側）の設定となります。

以下それぞれの設定を簡単に説明します。

### Interface設定
「**PrivateKey**」はクライアント側プライベートキーとなり、デフォルトで入力されているのでそのまま使用します。

「**Address**」はクライアント側に割り振るIPアドレスとなり、QNAP VPN側が「**198.18.7.1**」となるため、クライアント側は「**198.18.7.2**」としました。

### Peer設定
「**PublicKey**」はQNAP側のパブリックキーを指定します。

「**AllowedIPs**」はいわゆるスプリットトンネルといった設定となり、ここで指定したアドレスへの通信があった場合、`WireGuard`のVPNトンネルを通って通信を行い、それ以外の通信はVPNトンネルは使わずに自分のインターネット回線を使います。

今回の場合、QNAP VPN側で使用している「**198.18.7.1/32**」と、自宅のローカルネットワークの「**192.168.X.0/24**」については`WireGuard`のVPNトンネルを経由させたいため、２つ設定しています。

「**Endpoint**」は自宅ネットワークのグローバルIPを指定しますが、私は固定のグローバルIPは持っておらず、外部から自宅のネットワークに接続する際にはダイナミックDNSのサービスで取得したドメイン名を使っています。

ダイナミックDNSで取得したドメイン名に`WireGuard`のポート番号`51820`を指定することで設定できるので、固定のグローバルIPを持っていない方（個人で持っている人は少ないかと思いますが）はダイナミックDNSを取得してください。

私は別のダイナミックDNSのサービスを使用しているため使っていませんが、QNAP NASのサービスでもダイナミックDNSを取得できるのでQNAP NASを使用している方はそちらを利用してもよいでしょう。

「**PersistentKeepalive**」は後ほど行うQNAP側のPeer設定のデフォルト値が10秒だったので、QNAP側と合わせて10秒としました。

「**PresharedKey**」はサーバ側、クライアント側双方で設定しなければ、なくても接続できるのですが、今回は先程控えた事前共有鍵も設定して少しでもセキュリティを向上したいと思います。

## WireGuardサーバ側Peer設定
`WireGuard`はサーバ、クライアント双方でお互いの値を設定する必要があるので、再度QNAP側の設定に戻り、ピア設定を行います。

先程の設定画面の下に「**ピアの追加**」ボタンがあるので、そちらを選択して、以下の設定を行っていきます。

![Monosnap_20230826_162113.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/b7284185-35ec-d2b6-7e7a-9edca727ba32.png)

「**ピア名**」は任意の名前で設定、「**パブリックキー**」はクライアント側設定を行った際に控えた公開鍵を設定します。

「**詳細設定**」は行わなくても適用できますが、今回は事前共有キー設定を行うため、「**詳細設定**」を選択し、先程控えた事前共有鍵を設定します。

なお、「**エンドポイント**」は、今回の場合リモートアクセス方式でのVPN接続となるため、エンドポイントの指定は不要です。

また、もし「**許可されている IP**」の値がクライアント側で指定したIPと異なる場合はクライアント側の設定を修正してください

## WireGuardでの接続
`WireGuard`のクライアントアプリを起動して「**macToggleStatusButtonEnableOnDemand**」を選択するか、システム設定の「**VPN**」に追加されている`WireGuard`を有効化することで接続できます。

通信シーケンスがシンプルなため、`OpenVPN`と比べてかなり早く有効状態になります。

接続できれば「**AllowedIPs**」で指定した宛先への通信はVPNトンネルにルーティングされるため、Ping等で接続できているか確認し、応答があれば成功です。

```bash:pingでの疎通確認
# ping 198.18.7.1
PING 198.18.7.1 (198.18.7.1): 56 data bytes
64 bytes from 198.18.7.1: icmp_seq=0 ttl=64 time=16.919 ms
64 bytes from 198.18.7.1: icmp_seq=1 ttl=64 time=18.871 ms
64 bytes from 198.18.7.1: icmp_seq=2 ttl=64 time=13.147 ms
^C
--- 198.18.7.1 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 13.147/16.312/18.871/2.376 ms
```

## オンデマンド接続の有効化
自動接続を行わないようであれば以下の設定は不要です。

オンデマンド接続を行う場合、`MacOS`では「**システム設定**」→「**VPN**」から「**i**」ボタンを選択することで以下の画面が表示されるため、「**オンデマンド接続**」のトグルボタンを有効にすることでクライアント側設定を行った際のオンデマンド設定に従って自動接続されるようになります。

![Monosnap_20230827_094121.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/6d347674-7c0e-47fa-e1c0-3cf5c2a98313.png)

## QRコードでのクライアント設定
`WireGuard`はPC用のクライアントソフト以外にスマートフォン等でもクライアントソフトが公開されているため、上記と同様の設定を行えば設定出来ますが、スマートフォンで設定を行う場合、秘密鍵や公開鍵もスマートフォンで入力しないといけないので非常に設定に手間がかかります。

公開鍵・秘密鍵共に含めたクライアント用設定ファイルを予め作成し、ZIP形式のファイルでスマートフォンに渡して読み込むか、設定情報をQRコード化したものを`WireGuard`のスマートフォン用クライアントソフトで読み取ることが可能なのでスマートフォン用の設定を行う場合はZIP形式かQRコードの形式で設定するのが良いでしょう。

但し、この方法の場合、公開鍵・秘密鍵共に別端末（今回はQNAP NAS側）で作成することになるので、自己責任でお願いします。

- [スマートフォンへのWireGuardクライアントのインストール](#スマートフォンへのwireguardクライアントのインストール)
- [スマートフォン用鍵情報の生成](#スマートフォン用鍵情報の生成)
- [スマートフォン用クライアント設定ファイルの生成](#スマートフォン用クライアント設定ファイルの生成)
- [QRコードの生成](#qrコードの生成)

### スマートフォンへのWireGuardクライアントのインストール
接続に使用するスマートフォンに`AppStore`や`Google Play`等から`WireGuard`をインストールします。

設定は後ほどQRコードで取り込むため、インストールするだけでOKです。

### スマートフォン用鍵情報の生成
QNAP NASには操作に必要なコマンドがすでにインストールされているため、SSHでQNAP NASに接続して操作を行います。

スマートフォン側で使用する秘密鍵とQNAP NAS側で設定する公開鍵を生成するため、以下コマンドでファイルに書き出します。

```bash:秘密鍵と公開鍵の生成
wg genkey | tee privatekey | wg pubkey > publickey
cat privatekey
cat publickey
```

また、ついでにスマートフォンとの接続で使用する事前共有鍵も生成して控えておきます。

```bash:事前共有鍵の生成
wg genpsk
```

上記の鍵情報を使ってQNAP NAS側のPeer設定は先程と同様に設定を済ませておいてください。

### スマートフォン用クライアント設定ファイルの生成
先程PC用クライアントで設定した設定情報を元にスマートフォン用設定ファイルを作成します。

スマートフォンで使用するIPアドレスと各種鍵情報以外はPC用クライアントで設定した内容と同じなので、`vi`で以下のように設定してください。

なお、「**[Peer]**」の`PublicKey`はQNAP NAS側の公開鍵となるため、PC用クライアントで設定したものと同じとなるので注意してください。

```text:スマートフォン用設定ファイルの作成
[Interface]
PrivateKey = [先程生成したスマートフォン用プライベートキー]
Address = 198.18.7.3/32

[Peer]
PublicKey = [QNAP側のパブリックキー]
AllowedIPs = 198.18.7.1/32, 192.168.X.0/24
Endpoint = [DDNS名]:51820
PersistentKeepalive = 10
PresharedKey = [先程生成したスマートフォン用事前共有鍵]
```

### QRコードの生成
以下のコマンドを実行することでコマンドライン上にQRコードを表示することができるので、スマートフォンにインストールした`WireGuard`から「**QRコードから作成**」を選択し、表示されたQRコードを読み込んでください。

```bash:QRコードの生成
qrencode -t ansiutf8 < [作成したスマートフォン用設定ファイル名]
```

※コマンドラインにそのままQRコードが表示されるので結構面白いです（笑）

# コマンドでのWireGuard接続・切断
あまり使い所が無いかもしれませんが、コマンドラインで`WireGuard`を接続・切断するやり方も紹介しておきます。

## コマンドラインツールのインストール
今回は`MacOS`のクライアントで使う方法を紹介します。

`MacOS`で`wg`コマンド等の`WireGuard`のコマンドを使用するために、以下`brew`コマンドでインストールします。

```bash:コマンドラインツールのインストール
brew install wireguard-tools
```

## 接続設定ファイルの準備
設定ファイルはGUIで設定した内容と同一の設定ファイルを適当な場所に作成します。

ファイル名は今回は`wg0.conf`と言ったファイル名で作成した前提で進めます。

以下コンフィグ再掲。

```bash:クライアント側設定
[Interface]
PrivateKey = [プライベートキー]
Address = 198.18.7.2/32

[Peer]
PublicKey = [先程控えたQNAP側のパブリックキー]
AllowedIPs = 198.18.7.1/32, 192.168.X.0/24
Endpoint = [DDNS名]:51820
PersistentKeepalive = 10
PresharedKey = [先程控えた事前共有鍵]
```

## コマンドでの接続
コマンドで`WireGuard`を接続するためには、`wg-quick`コマンドで行います。

`wg-quick up [設定ファイル名]`の書式となり、設定ファイル名はフルパスで指定する必要があります。

以下ユーザのドキュメントディレクトリ配下にある設定ファイルを使って接続する例。

```bash:コマンドでのWireGuard接続
wg-quick up /Users/[ユーザ名]/Documents/wg0.conf
```

コマンド実行すると`sudo`権限で実行することになるため、ユーザのパスワードを入力して実行します。

正常に接続できた場合、`wg`コマンドを実行することで状態を確認することができます。

```bash:接続状態の確認
sudo wg
```

```bash:wgコマンド実行例
interface: utun3
  public key: [サーバ側公開鍵]
  private key: (hidden)
  listening port: 60196

peer: [クライアント側公開鍵]
  preshared key: (hidden)
  endpoint: X.X.X.X:51820
  allowed ips: 198.18.7.1/32, 192.168.X.0/24
  latest handshake: 27 seconds ago
  transfer: 124 B received, 244 B sent
  persistent keepalive: every 10 seconds
```

## コマンドでの切断
コマンドで`WireGuard`を切断するためには、`wg-quick down`コマンドで行います。

先程の接続コマンドの`up`を`down`と変更するだけとなり、設定ファイル名も指定する必要があります。

以下ユーザのドキュメントディレクトリ配下にある設定ファイルを使って接続する例。

```bash:コマンドでのWireGuard接続
wg-quick down /Users/[ユーザ名]/Documents/wg0.conf
```

接続時と同じく、パスワードが聞かれるので入力して実行すれば切断できます。

# おわりに
今まで使っていた`OpenVPN`はQNAP NASではGUIで設定できるので比較的簡単に導入できるようにはなっていますが、GUI上ではスプリットトンネルの設定を行うことが出来ないので、VPN接続時はすべての通信がVPNトンネルを通って自宅ネットワーク経由となってしまうのが難点でした。

`WireGuard`はGUI上からスプリットトンネルの設定を行えるので、通常のインターネット通信のパフォーマンスを落とすこともなく、特定の通信のみVPNトンネルを使用することができるため、簡単な設定で理想的な構成を組むことができました。

また、オンデマンド設定を行うことで接続を意識することが無くなったのは利用する上で便利でした。

一方でユーザ認証もなくリモートアクセス接続出来てしまうため、利用は個人用途にとどめておいたほうが良いと感じました。

ユーザ認証が行えない問題はありますが、アルゴリズムはIPsecよりも洗練されており改ざんや攻撃にも強く、接続も高速と良い点がたくさんあるので一度試してみるとIPsecのような手間がかかるVPNには戻れなくなるかもしれません。

以下の動画がわかりやすかったので詳しく知りたい方は以下を参照してみてください。

https://www.youtube.com/watch?v=grDEBt7oQho