オレオレCD(N)を作る

:::note info
この記事は [エンジニア学生団体IDEA Advent Calendar 2023](https://qiita.com/advent-calendar/2023/idea) の12/19分になります
:::

cloudflared経由でm3u8など大量のデータを流すとキャッシュの上限を突破して同一ドメインを使用しているサイトすべてが死んでしまうので代替としてCD(N)を自作しました


# 材料
- VPS(必要に応じてn個)
    - 個人的にはXserverが一番オススメです
      各VPSのCPU、DiskIOの比較を別記事で出しているので詳細はそちらを参照してみてください
      https://zenn.dev/xpadev/articles/f70b67d51c9d75
- インターネットにアクセスできるオリジンサーバー
- ドメイン

# 手順
## 1. VPSをセットアップする
### a. OSのインストール
linux系なら何でも良いです(多分)
この記事では ubuntu-server を想定しています

### b. NGINXのインストール
```shell
apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
apt update
apt install nginx
systemctl enable --now nginx
```

## 2. オリジンサーバーをセットアップする
### a. sshの公開鍵認証を設定する
適宜やってください
オリジン、VPS共に専用ユーザーを作成することをおすすめします

### b. systemdのサービスを作成する
各VPSへ向けてsshを用いたトンネルを作成する
```conf
[Unit]
Description=Setup a secure tunnel to remote server
After=network.target

[Service]
ExecStart=/usr/bin/ssh -NT -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -R <remote-port>:localhost:<local-port> <remote-server>

RestartSec=5
Restart=always

User=<username>

[Install]
WantedBy=multi-user.target
```
作成後適宜起動・有効化してください

## 3. キャッシュ&リバプロを設定する
### a. ssl証明書の取得
適宜letsencryptなどを用いて取得してください
この記事ではcertbotで証明書を取得した場合を想定しています
### b. キャッシュ場所の設定
`/etc/nginx/nginx.conf`のhttpブロック内に以下の内容を追記します
```conf
proxy_cache_path /var/cache/nginx keys_zone=zone1:1024m max_size=30g inactive=24h;
proxy_temp_path  /var/cache/nginx_tmp;
```
### c. コンフィグファイルの作成
`/etc/nginx/conf.d/`に以下のファイルを作成します
```conf
server {
    listen       443 ssl;
    listen  [::]:443 ssl;
    server_name  <hostname>;

    ssl_certificate /etc/letsencrypt/live/<hostname>/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<hostname>/privkey.pem;

    location / { #キャッシュしてほしいディレクトリ
        proxy_pass http://localhost:<remote-port>/;
        proxy_set_header    Host <hostname>;
        proxy_set_header    X-Real-IP    $remote_addr;   
        proxy_set_header    X-Forwarded-For    $proxy_add_x_forwarded_for;

        proxy_buffering on;
        proxy_cache_valid 200 302 1y;
        proxy_cache_valid 404 10m;
        proxy_cache zone1;
        add_header X-Nginx-Cache $upstream_cache_status;
    }
    
    location /hoge { #キャッシュしてほしくないディレクトリ、認証エンドポイントとか
        proxy_pass http://localhost:<remote-port>;
        proxy_set_header    Host <hostname>;
        proxy_set_header    X-Real-IP    $remote_addr;
        proxy_set_header    X-Forwarded-For    $proxy_add_x_forwarded_for;

        proxy_buffering on;
        proxy_no_cache 1;
        proxy_cache_bypass 1;
    }

    location /huga { #別途認証をかけたいディレクトリ
        auth_request /<path-to-auth>; #認証エンドポイントにリクエストが飛び、200を返すと表示される 
        proxy_pass http://localhost:<remote-port>;
        proxy_set_header    Host <hostname>;
        proxy_set_header    X-Real-IP    $remote_addr;
        proxy_set_header    X-Forwarded-For    $proxy_add_x_forwarded_for;

        proxy_hide_header Cookie;
        proxy_set_header  Cookie "";

        proxy_buffering on;
        proxy_cache_valid 200 302 1y;
        proxy_cache_valid 404 10m;
        proxy_cache zone1;
        add_header X-Nginx-Cache $upstream_cache_status;
        add_header Cache-Control "no-cache";
    }
}
```
### d. コンフィグの確認・反映
```shell
nginx -t
```
でコンフィグの確認を行います
問題なさそうであればnginxを再起動してコンフィグを反映します
```shell
systemctl restart nginx
```

## 4. ドメインの設定
セットアップした各VPSのIP宛にAレコードを貼れば完了です

# おまけ
実際に運用しているドメインを掲載しておくので煮るなり焼くなりご自由にどうぞ
※パブリックなリソースは一切ないので403しか返ってこないと思いますが

[https://cdn.xpa.dev/](https://cdn.xpa.dev/)

以前公開した [nginx-vod-moduleでon-the-flyなhls配信環境を作る](https://qiita.com/xpadev-net/items/714eddf2ceb3d0ef78a7) の前段に置いてあります

# 余談
実際のCDNではロケーションに応じて適切なサーバーが選択されるようになっていますが、やってられないので正直1台あれば十分だと思います
(そもそもオリジンへのリクエストによる負荷を減らしたいだけなので)