ポート開放なしで自宅のサーバに固定IPでアクセスする

# 動機
- 自宅にインターネットは引けているものの、自宅の回線が「無料インターネット物件」や「ホームルーター」「DS-Lite方式のIPv6プロバイダ」などのため、自宅回線に付与されるIPv4アドレスに対してポートを開放できない
- このような環境下でも、自宅のサーバに何らかの手段でアクセスできるようにしたい

# 方向性
自宅のゲートウェイサーバと適当なIPを持ってるサーバでP2P型のVPNを張れば、流入経路が確保できるのでは？ということで

1. IPとそれなりの回線だけ持ってるプロキシサーバ
1. VPNを張るソフトウェア

があればなんとかなりそう

## 1. IPとそれなりの回線だけ持ってるプロキシサーバ
一旦AWSで検討、下記の構成で行けそう。セキュリティグループ諸々は省略。

| 構成要素     | 名前             | 月額(円) | 備考                                                                                                               |
| ------------ | ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------ |
| インスタンス | EC2 : t3.nano    | 720      | t3だと最大5Gbpsなので、ネットワークとしては申し分なさそう。<br>要件としてはメモリもCPUもほぼ不要なので、nanoで十分 |
| ストレージ   | EBS : 8GiB(gp3 ) | 110      | EBSの下限で作成                                                                                                    |
| IP           | EIP              | 540        | 問答無用で有料化してしまった(24.2~)。高い...                                                                               |

https://calculator.aws/#/createCalculator/EBS

https://aws.amazon.com/jp/ec2/pricing/on-demand/

https://aws.amazon.com/jp/blogs/news/new-aws-public-ipv4-address-charge-public-ip-insights/

## 2. VPNを張るソフトウェア

Hamachi, SoftEther, ZeroTier, tailscaleあたりが該当しそう。Zerotier試したらすぐつながったので、一旦Zerotierを選定。

https://qiita.com/yosuke@github/items/d3274ce7f7129894713a

https://qiita.com/RE-yura/items/3b750188e3cff05c55b9

https://my.zerotier.com/

### 【追記】VPNソフト選定

TailScaleのほうがping気持ち低く出る(0.5~1msくらい)ので、tailscaleのほうが良いかも


# 構成イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017662/add9ec27-5666-9532-837c-5d4fdc038329.png)




# セットアップ

## AWSインスタンスを起動

- クイックスタート：AmazonLinux 2023 AMI ami-0b193da66bc27147b
    - Amazon Linux 2023 AMI 2023.3.20240131.0 x86_64 HVM kernel-6.1
- インスタンスタイプ：t3.nano 2vCPU 0.5GiB 
- ネットワーク設定：一式デフォルト
- ボリューム：8GiB

※ インスタンス作成後、貫通対象のポートは開けておく。
（ 該当インスタンス->セキュリティ->セキュリティグループ->インバウンドのルール ）

## ZeroTier セットアップ

### アカウント、VPN作成

https://my.zerotier.com/

- アカウント作成してログイン(Googleアカウントでログインしました)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017662/6fd50f88-e27d-1f0b-7781-2ad8b3b000d6.png)

- "Create A Network"でネットワークを作成(デフォルトのやつ使ってもよさそう)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017662/5465b38c-0a09-03c7-6040-22f0988eb614.png)



- ネットワーク選択後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017662/816acdf6-5195-c037-5ae9-0ce30e67987a.png)
    - Members
        - 無料枠はメンバー25台まで
        - 後述の"zerotier-cli join"してきたサーバに対して、"Auth?"のチェックを有効化して参加
        - "Managed IPs"に適当なIPを付与。これをnginxのconfigに設定(後述)。
        


### 本体インストール
下記手順で接続。CentOSとAmazonLinuxは以下で行けるっぽい。

```bash
# ZeroTierインストール
$ curl -s https://install.zerotier.com | sudo bash

# ZeroTier自動起動の有効化
$ sudo systemctl enable zerotier-one

# ZeroTier接続 ※ これが成功するとMembersの一覧に表示される
$ sudo zerotier-cli join [network_id]
```



## EC2 : nginx セットアップ

### 本体インストール

```bash
[ec2-user ]$ sudo yum install nginx
[ec2-user ]$ sudo yum install nginx-mod-stream
```
streamディレクティブで流し込むので、mod-streamも必要

### 設定：/etc/nginx/nginx.conf
最後尾に以下を設定
```nginx
stream {
        server {
                error_log /var/log/nginx/443.log info;
                listen          443;
                proxy_pass      <GW ServerのManaged IP>:443;
        }
        server {
                error_log /var/log/nginx/8211.log info;
                listen          8211 udp;
                proxy_pass      <GW ServerのManaged IP>:8211;
        }
        .....
}
```


## 【追記】 EC2：NAT セットアップ 

nginx経由するとめちゃくちゃラグくなったので下記を参考に修正

https://qiita.com/nomatawan/items/67fb4704e093ea8d4820

https://sokuniv.com/palworld-dedicated-server/

### /root/pal-udp-8211.sh
```bash
#!/bin/sh

/usr/bin/socat UDP-LISTEN:8211,reuseaddr,fork UDP:<GW ServerのManaged IP>:8211 </dev/null &

echo $! >/var/run/pal-udp-8211.pid
```

### /etc/systemd/system/pal-udp-8211.service
```bash
[Unit]
Description = socat proxy udp 8211
After=syslog.target network.target remote-fs.target nss-lookup.target
ConditionPathExists=/root

[Service]
Type=forking
PIDFile=/var/run/pal-udp-8211.pid
ExecStart=/root/pal-udp-8211.sh
ExecStop=/bin/kill -s QUIT $MAINPID

[Install]
WantedBy = multi-user.target
```

### 準備作業
```bash
# 実行権限つける
chmod 0755 /root/pal-udp-33333.sh

# Serviceリロード・有効化して起動する
systemctl daemon-reload
systemctl enable pal-udp-8211
systemctl start pal-udp-8211
```