プライベートIPアドレスしか割り当てられていないRaspberry PiサーバをVPS(Lightsail)とVPN(WireGuard)を使って公開する

## 概要
この記事は、プライベートIPアドレスしか割り当てられていないRaspberry PiサーバをVPS(Lightsail)とVPN(WireGuard)を使って公開する手順を紹介します。

## 背景
集合住宅や学内ネットワークなど、プライベートIPアドレスしか割り当てられていない環境下（上流に自分で管理できないNATがある環境下）において、Raspberry Pi上で稼働するサーバをグローバルなインターネット上に公開し、誰でも自由にアクセスできるようにしたい。

## 課題
上記の背景により、グローバルIPアドレスが割り当てられないので、グローバルなインターネット上にRaspberry Pi上で稼働するサーバを公開できない。


## 解決策
VPSとRaspberry PiをVPNで接続し、VPSにポートフォワーディングを設定することによって、グローバルIPアドレスを持つVPS宛に来たリクエストをRaspberry Piが受け取り、Raspberry Piが返したレスポンスをVPSがリクエスト元に返すことが出来るようにする。

これにより、あたかもRaspberry PiにグローバルIPアドレスが割り当てられているかのようなネットワークを構築することが出来る。

## 環境
- VPS: Amazon Lightsail (Ubuntu 22.04 LTS)
- VPNソフトウェア: WireGuard (v1.0.20210914)
- Raspberry PiのOS: Raspberry Pi OS Lite (64-bit) リリース日時: 2023-10-10

## 手順

### WireGuardのインストール
Lightsail・Raspberry Pi共にWireGuardをインストール
```bash
sudo apt install -y wireguard
```

### 秘密鍵・公開鍵の生成
Lightsail・Raspberry Pi共に秘密鍵と公開鍵を生成
```bash
wg genkey > private
cat private
<秘密鍵が表示される>
wg pubkey < private
<公開鍵が表示される>
```
### コンフィグファイル作成
※ 鍵の文字列両端に`"`は必要ありません
#### Lightsail側
```bash
sudo vim /etc/wireguard/wg0.conf
```
今回は、**VPSの80番ポート**を**Raspberry Piの80番ポート**にフォワーディングする設定にします。
```conf:/etc/wireguard/wg0.conf
[Interface]
PrivateKey = <VPNサーバの秘密鍵>
Address = 10.0.0.1/32
ListenPort = 51820
PostUp = iptables -t nat -A PREROUTING -i ens5 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.2:80; iptables -t nat -A POSTROUTING -o wg0 -p tcp --dport 80 -d 10.0.0.2 -j MASQUERADE
PostDown = iptables -t nat -D PREROUTING -i ens5 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.2:80; iptables -t nat -D POSTROUTING -o wg0 -p tcp --dport 80 -d 10.0.0.2 -j MASQUERADE

[Peer]
PublicKey = <VPNクライアントの公開鍵>
AllowedIPs = 10.0.0.2/32
```

#### Raspberry Pi側
```bash
sudo vi /etc/wireguard/wg0.conf
```
```conf:/etc/wireguard/wg0.conf
[Interface]
PrivateKey = <VPNクライアントの秘密鍵>
Address = 10.0.0.2/32

[Peer]
PublicKey = <VPNサーバの公開鍵>
Endpoint = <LightsailのグローバルIPアドレス>:51820
AllowedIPs = 10.0.0.1/32
PersistentKeepalive = 25
```

### LightsailのUDP51820番ポートを開ける
Lightsailのインスタンス管理コンソールの[ネットワーキング]タブからIPv4ファイアウォールの[+ルールを追加]で以下のルールを追加します。

- アプリケーション: カスタム
- プロトコル: UDP
- ポートまたは範囲: 51820

![スクリーンショット 2023-12-09 154640.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2705635/6b0eb044-0406-7b7c-0dd5-87fc14c57779.png)


### Lightsail側でポートフォワーディング有効化
```bash
sudo vim /etc/sysctl.conf
```
「net.ipv4.ip_forward=1」のコメントアウトを解除してください
```diff_conf:/etc/sysctl.conf
- #net.ipv4.ip_forward=1
+ net.ipv4.ip_forward=1
```
変更を反映します
```bash
sudo sysctl -p
```

### 自動起動設定
Lightsail・Raspberry Pi共に設定します
```bash
sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0
```

以上で完了です。

Raspberry PiでWebサーバを立ち上げ、LightsailのグローバルIPアドレスにHTTPアクセスするとレスポンスが返ってくることを確認してみてください。

## まとめ
このように、VPSとRaspberry PiをVPNで繋ぎ、VPSにポートフォワーディングを設定することによって、あたかもRaspberry PiにグローバルIPアドレスが割り当てられているかのようなネットワークを構築することが出来ます。

## 参考

https://ohayoyogi.hatenablog.com/entry/2021/03/18/145754

https://gihyo.jp/admin/serial/01/ubuntu-recipe/0614

https://zenn.dev/motisan/articles/20230121_wireguard03

https://www.wireguard.com/quickstart/

https://wiki.archlinux.jp/index.php/WireGuard

## 謝辞
この記事を書くにあたり、大変お世話になった参考記事の著者の皆さんとツール提供元の皆さんに心より感謝します。