【WireGuard】集合住宅で自宅サーバー＆外出先からVPN接続

最近引っ越した先の集合住宅は各部屋にグローバルIPを当ててくれない系の家だった。そこでVPSを借りて自宅ネットワークと常時VPNで接続し、かつ外出先からVPS経由で自宅ネットワークにVPN接続できるようにした。

最終的に構築したネットワークを図にしたものが以下。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2354612/f218f68f-b4ba-53be-2686-de9f05148c91.png)

# 技術選定
## VPS ⇔ 外出先
VPSと外出先の端末を繋ぐVPNにはIKEv2によるリモートアクセスVPNを採用した。外に持ち歩く端末はスマホやノートパソコンなど複数あるがそれぞれに専用のVPNソフトを入れるのがイケてないと思っているからである。例えばOpenVPNだと各端末にOpenVPNのソフトをインストールする必要があるが、IKEv2によるVPNは多くのデスクトップ及びモバイルOSで標準装備されており追加のソフトのインストールが必要ない。標準機能でできることは標準機能でやるべきという思想に基づいている。

## VPS ⇔ 自宅
VPSと自宅のネットワークを繋ぐVPNには[WireGuard](https://www.wireguard.com/)を採用した。セットアップが簡単で高速だと言われているからである。まずVPSと自宅内のゲートウェイサーバーは両方ともLinuxサーバーであり、外出先との場合のように標準機能として使えるVPN機能があるわけではない。またこれらの2地点の端末は外出先の端末とは異なり固定されていて変わることもない。であれば単純に性能がよいVPNを使おうということでWireGuardとした。[WireGuardは他に比べてパフォーマンスが高い](https://www.wireguard.com/performance/)と言われているし、セットアップもOpenVPNと比べても本当に簡単である。

# VPN構築方法
## VPS ⇔ 外出先
VPSにIKEv2のVPNサーバーを立てる。サーバー立てには[docker-ipsec-vpn-server](https://github.com/hwdsl2/docker-ipsec-vpn-server)を用いる。この構成ではDockerネットワークを挟むことでNATが入るのでVPSまたは自宅側から外出先端末側に接続することはできない。が、リモートアクセスVPNとして使うならそれで問題ないので Docker による利便性の方を取る。

サーバーを立てるには基本的には以下のような `compose.yaml` ファイルを作って `$ docker compose up` するだけで良い。クライアント端末の認証は証明書で行うことになる。クライアント端末の設定方法等の詳しい説明は公式のドキュメントを読むか[私の別の記事](https://qiita.com/silane1001/items/a96ce9300ed502954d07)を読んでほしい。

https://github.com/hwdsl2/docker-ipsec-vpn-server

https://qiita.com/silane1001/items/a96ce9300ed502954d07

```yaml:compose.yaml
services:
  vpnserver:
    image: hwdsl2/ipsec-vpn-server
    ports:
      - 500:500/udp
      - 4500:4500/udp
    volumes:
      - ./ikev2-vpn-data:/etc/ipsec.d
      - /lib/modules:/lib/modules:ro
    privileged: true
    environment:
      - VPN_IKEV2_ONLY=yes
      - VPN_XAUTH_NET=192.168.43.0/24
      - VPN_XAUTH_POOL=192.168.43.10-192.168.43.250
    restart: unless-stopped
```

## VPS ⇔ 自宅
### VPNトンネル作成
VPSと自宅側のゲートウェイとなるサーバー（`192.168.10.14`）のそれぞれにWireGuardをインストールする（Debianなら`$ apt install wireguard-tools`だった）。それぞれに以下の設定ファイルをrootユーザーとして作成する。ただし鍵の値（`A_PRIVATE`、`A_PUBLIC`、`B_PRIVATE`、`B_PUBLIC`）は後述の値に置き換える。

```ini:VPSの/etc/wireguard/wg0.conf
[Interface]
PrivateKey = A_PRIVATE
Address = 10.8.0.1/24
ListenPort = 51820

[Peer]
PublicKey = B_PUBLIC
AllowedIPs = 10.8.0.0/24, 192.168.10.0/24
```

```ini:自宅ネットワーク内のサーバーの/etc/wireguard/wg0.conf
[Interface]
PrivateKey = B_PRIVATE
Address = 10.8.0.2/24
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT;iptables -A FORWARD -o wg0 -j ACCEPT;
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT;iptables -D FORWARD -o wg0 -j ACCEPT;

[Peer]
PublicKey = A_PUBLIC
EndPoint = x.x.x.x:51820
AllowedIPs = 10.8.0.0/24
PersistentKeepalive = 25
```

鍵は以下で生成する。作成されるファイルの中身を上の設定ファイルの設定値にコピペする。鍵の生成はVPSと自宅内サーバーの両側で行い、互いの公開鍵を交換する形になる。

```
$ umask 077
$ wg genkey | tee privatekey | wg pubkey > publickey
```


双方で `$ wg-quick up wg0` とすることで接続を確立する。また再起動後も再接続されるように `$ systemctl enable wg-quick@wg0` としておく。

### ルーティングテーブル設定
VPSから自宅ネットワークへのルーティングテーブル（以下の図の`Routing Table 1`）はトンネルが作成されるときにWireGuardが自動で追加してくれる。

自宅ネットワークからVPSへのルーティングテーブル（以下の図の`Routing Table 2`）は自分で設定する必要がある。ここでは自宅ネットワークのデフォルトルートになっているルーターに経路情報を追加している。うちのルーターはBuffaloの一般家庭向けWifiルーターだが経路情報を追加することができた。経路情報を設定できないものもあると思うので要確認。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2354612/f218f68f-b4ba-53be-2686-de9f05148c91.png)

## 疎通確認
正しく構成できていれば以下が疎通できるはず。

### 外出先端末から

```console
$ ping 10.8.0.1 # VPS
$ ping 192.168.10.10 # 自宅ネットワーク
```

### VPSから
```console
$ ping 192.168.10.10 # 自宅ネットワーク
```

### 自宅ネットワークから
```console
$ ping 10.8.0.1 # VPS
```