WireGuard で VPS 経由で家庭内に入る

→[続きを書きました](https://qiita.com/false-git@github/items/1a2d99b0bc348fa97b3c)

# 前書き

今まで家庭内にある http サーバを外部に公開するために、固定IPのプロバイダを使っていたのだが、サーバマシンが壊れたのを契機に VPS に移行することにした。
ついでに、ネットワークが遅い問題を解決するのと、IPv6 が使えるようにしたかったので、IPoE のプロバイダに乗り換えることにした。
IPoE で IPv4 を使うためには、いろいろな方式があるが、最近の流行りは DS-LITE か MAP-E らしい。
当初、DS-LITE のプロバイダをお試ししてみたのだが、時間帯によって非常に遅く、今までのプロバイダよりも遅い始末で、すぐに解約した。(が、解約が有効になるのが月末と言う罠があり、翌月まで次のプロバイダが試せなかった)
次に試したのが MAP-E のプロバイダで、こちらは混雑している時間帯でも 200Mpbs 以上の速度が出た。
また、これらを試すために、フレッツ貸し出しのルータの代わりに、 YAMAHA の NVR510 と言うルータを購入した。これは、 GUI だけでなくコマンドを使って細かい設定ができるのがウリである。

## 良くなったこと

* 速くなった
* IPv6 が使えるようになった
* 外部向けのサービスを VPS に移行したことで、家庭内にサーバを置かなくて良くなった。

## 悪くなったこと

* MAP-E なので、外から家にアクセスする方法がなくなった。(厳密には、指定されたポートを foraward すればできないことはないらしい)
* NVR510 は光電話のクライアントになれるが、SIPサーバになれないので、光電話の子機として iPhone を使うことや、asterisk に留守番電話をさせることができなくなった。

## 対策案

NVR510 には IPsec/L2TP の VPN の機能があるので、当初固定IPのプロバイダの契約を残したまま、そこをエンドポイントにして VPN を張ることを考えた。
しかし、iPhone からの VPN の接続はうまくいくものの、FreeBSD の VPS からの接続がどうしてもうまくいかない。
OpenVPN は iPhone も FreeBSD もうまく行くことがわかっていたが、NVR510 が対応していない。
そんなとき、WireGuard の存在を知った。

# WireGuard

* 職場の slack で以下の記事を知った。  
[第614回　WireGuardでVPNサーバーを構築する：Ubuntu Weekly Recipe｜gihyo.jp … 技術評論社](https://gihyo.jp/admin/serial/01/ubuntu-recipe/0614)
* 公式サイトは https://www.wireguard.com/

いろいろ試行錯誤をしたのだが、最終形態だけ書くことにする。

![wireguard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3357/c9447fa5-dc05-fc1f-69fd-2749feffe796.png)

黒が実際の接続、青がVPNとなっている。

## VPS(FreeBSD) の設定

今回の構成の中で、このマシンだけが外向きの固定IPを持っているので、これをサーバとする。

* wireguard は、ports/pkg にあるので、そこからインストールする。
* 設定ファイルは /usr/local/etc/wireguard/ に置く。
* 当初、wg0一つだけで実現しようとしたのだが、iPhoneと家庭内で通信ができず、wg0とwg1の二つのインターフェイスを使うことに。
    * 同様の問題は [Connection between two clients](https://lists.zx2c4.com/pipermail/wireguard/2018-August/003245.html) にあったが、解決したか不明だった。
    * 二つのインターフェイスを使う方法は、[Routing between wg interfaces with WireGuard &#8211; JRS Systems: the blog](https://jrs-s.net/2018/08/05/routing-between-wg-interfaces-with-wireguard/) を参考にした。
* 鍵の生成方法については、公式含めいろいろなところに書いてあるので省略する。

```/usr/local/etc/wireguard/wg0.conf
[Interface]
Address = 192.168.1.1
ListenPort = 51820
PrivateKey = <private key of server>

[Peer]
PublicKey = <public key of raspberry pi>
AllowedIPs = 192.168.1.2/32, 192.168.0.0/24
```
```/usr/local/etc/wireguard/wg1.conf
[Interface]
Address = 192.168.2.1
ListenPort = 51821
PrivateKey = <private key of server>

[Peer]
# iphone
PublicKey = <public key of iphone>
AllowedIPs = 192.168.2.2/32
```
```/etc/rc.conf(差分)
gateway_enable="YES"
wireguard_enable="YES"
wireguard_interfaces="wg0 wg1"
```

他のやってみた系の記事では、サーバ側に NAT の設定があるが、このVPNの目的は出先のFreeWiFi等からの通信を全てVPNを通すことではなく、出先から家庭内LANにアクセスすることなので、サーバ側にはNATの設定はない。
肝は、wg0.conf の AllowedIPs に家庭内LANの192.168.0.0/24 が書いてあること。
上記設定でOS起動時に起動するが、手動で起動する場合は以下のようにする。

```shell-session
# service routing start
# service wireguard start
```

## Rasipberry PI の設定

* Raspberry PI は家庭内にあり、Raspbian buster がインストールされている。
* `sudo apt install wireguard` でインストール
* 設定ファイルは /etc/wireguard に置く。

```wg0.conf
[Interface]
PrivateKey = <private key of raspberry pi>
Address = 192.168.1.2
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT

[Peer]
PublicKey = <public key of server>
EndPoint = <host name or ip address of server>:51820
AllowedIPs = 192.168.1.0/24, 192.168.2.0/24
PersistentKeepalive = 25
```

`PersistentKeepalive = 25`は、NATの内側にある場合は必須だそうで、これがないとサーバ→Raspberry PIの通信ができなかった。
肝は、AllowedIPsにiPhoneに割り当てる 192.168.2.0/24 が書いてあること。
参考にしたサイトでは、PostUpに`route add -net 192.168.2.0/24 gw 192.168.1.1 ; ping -c1 192.168.1.1`的なことを書けと書いてあったが、なくても問題なかった。
また、VPSはこのルートを使ってインターネットに出る必要はないので、他のサイトに書いてあった`iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE`も削除した。

* `sudo systemctl enable wg-quick@wg0`でsystemctlに登録。
* `sudo systemctl start wg-quick@wg0`で手動起動。

## iPhoneの設定

* iPhone の WireGuard は AppStore にある。
* 設定はGUIから行うが、スクリーンショット1枚に収まらないのでwg0.conf形式で書く

```wg0.conf
[Interface]
PrivateKey = <private key of iphone>
Address = 192.168.2.2

[Peer]
PublicKey = <public key of server>
EndPoint = <host name or ip address of server>:51821
AllowedIPs = 192.168.2.0/24, 192.168.1.0/24 192.168.0.0/24
PersistentKeepalive = 25
```

肝は、AllowedIPsに家庭内LANの192.168.0.0/24 と、Raspberry PI に割り当てる 192.168.1.0/24 が書いてあること。

## NVR510 の設定

家庭内LAN上のマシンから、VPN 経由で VPS に通信が行くように、静的ルーティングを追加する。

```
ip route 192.168.1.0/24 gateway 192.168.0.2
ip route 192.168.2.0/24 gateway 192.168.0.2
```

## 動作確認

お互いに ping を打ってみたり、traceroute してみたりすると良いと思うよ。

## 雑多なこと

VPN に割り当てる IP アドレスは、[プライベートネットワーク](https://ja.wikipedia.org/wiki/プライベートネットワーク)のアドレスを使う。
上記では、192.168.1.0/24 と 192.168.2.0/24 を使ったが、これが iPhone が所属する WiFi のネットワークと被るとうまく通信ができないと思われる。3オクテット目は、0, 1, 2, 10, 100あたりは避けろとどこかで読んだ気がする。

ここには書かなかったが、Macのクライアントは homebrew等で入れるオリジナルと、Mac AppStore で入るGUI版がある。
GUI版は簡単に使えるが、PostUp 等が使えないので、手動でルーティングテーブルを追加したいときなどは微妙である。

また、WireGuard自体は IPv6 に対応しているので、v6 を使ってもいろいろできるが、ここでは割愛した。

IPsec/L2TP は FreeBSD でどう頑張っても接続できなかったのだが、WireGuard は設定が非常にシンプルで、OpenVPNより速いと言う噂(試してない)なので、今後に期待。
ただし、鍵の長さが寂しいように感じるのだが、これはこう言うものなのだろうか？