HTTPS と認証機能を持たないコンテナ上の Web アプリをリバースプロキシ (Nginx Proxy Manager) 経由で比較的安全に公開する

# 要約
- 「 HTTPS と認証機能を持たないコンテナ上の Web アプリ」には今回 VSCode Server (code serve-web) を想定しているが HTTP でアクセスするものであれば他でもよい
  - (参考) [VSCode Serverがなくなって本体に統合されていた](https://qiita.com/ku_suke/items/07b67bd710b17a3a7cf3)
  - VSCode Server (code serve-web) をコンテナ上に構築する手順は次の記事で纏めたい
- HTTPS と Basic 認証機能を持つリバースプロキシを調べたところ GUI で設定できる Nginx Proxy Manager が一番お手軽そうだった
- Qiita でも Nginx Proxy Manager を扱っているものはあったが Basic 認証の設定方法や管理画面の HTTPS 化の手順をまとめた記事を見つけられなかったためここに残す
  - (参考) [【Nginx Proxy Manager】まだNginxやLet's Encryptの設定をCUIで頑張ってるの？](https://qiita.com/silane1001/items/e21257b35c8274c81be8)
- 環境は以下を用いた
  - [さくらのドメイン](https://domain.sakura.ad.jp/)
  - Azure Virtula machines (ubuntu 20.04)

# 手順
## VMの準備
- Azure 上に VM を作成する
  - Image は `Ubuntu Server 20.04 LTS - x64 Gen2` を選択した
  - Size は `Standard_B2als_v2` を選択したが他でも良い
- 作成した VM の IP を取得する
- 80, 81, 443 番ポートの Inbound を許可するよう Network を設定する
  - 80 を許可しないと HTTPS (Let's Encrypt) の有効化時にエラーになる

## ドメインの準備
- 管理画面も HTTPS 化するため VM の IP を指すサブドメインを 2 つ準備する
![sub-domain.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1060173/904e91bc-3af9-92d2-fb38-a7ee187617bd.png)

## Docker のインストール
- VM (ubuntu) に Docker をインストールする
  - production ではないため [convenience script](https://docs.docker.com/engine/install/ubuntu/#install-using-the-convenience-script) を用いてインストールした
```shell
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh ./get-docker.sh
```
- (オプション) sudo 無しで docker コマンドを実行できるようグループを設定する
```shell
sudo usermod -aG docker $USER
```

## Web アプリのイメージを作成
- 今回詳細は割愛するが適宜ビルドを行い Web アプリのイメージを準備する

## コンテナの起動
- [Quick Setup](https://nginxproxymanager.com/guide/#quick-setup) に従い `docker-compose.yml` を VM 適当なディレクトリに格納する

```yaml:docker-compose.yml
version: '3.8'
services:
  app:
    image: 'jc21/nginx-proxy-manager:latest'
    restart: unless-stopped
    ports:
      - '80:80'
      - '81:81'
      - '443:443'
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
# ここから Quick Setup に無い定義
    depends_on:
      - web
  web:
    image: 'my-vscode' # 前の手順で作成したイメージを指定
    restart: unless-stopped
```
- `docker-compose.yml` を格納したディレクトリで以下を実行する
```shell
docker compose up -d
```

## Nginx Proxy Manager の設定
### 初回アクセス
- 前の手順で準備したサブドメインを用いて管理画面 (:81) にアクセスする
  - http://admin.{自分のドメイン}:81
  - この時点では HTTPS は使用できない
- [Quick Setup](https://nginxproxymanager.com/guide/#quick-setup) に書かれているユーザーを用いてサインインする
- ユーザーやパスワードの変更を求められるので従う
  - HTTPS 化した後にパスワードを再度変更することが望ましい

### 管理画面の HTTPS 化
- [GitHub の Issue](https://github.com/NginxProxyManager/nginx-proxy-manager/issues/139) に従い設定する
- "Proxy Hosts" をクリックする
  - ![proxy-hosts.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1060173/b4a0100b-b11d-d56f-01a9-965e1776b952.png)
- "Add Proxy Host" をクリックする
- "New Proxy Host" の Details を以下のように設定する
  - "Websockets Support" は Websockets を使用している可能性を考慮して有効化する
  - ![details1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1060173/a4d9af24-d9a3-f900-3657-e04df58831e8.png)
- "New Proxy Host" の SSL を以下のように設定して Save をクリックする
  - ![ssl1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1060173/d6a99ccb-c662-f282-b6f2-3c0df383cc21.png)
- 以下のように正しく設定できたことを確認する
  - ![admin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1060173/a3ad8bf4-1d4f-52e1-31e3-298aaab62188.png)
- HTTPS でアクセスできることを確認する
  - https://admin.{自分のドメイン}
- HTTP のアクセスを不可にするため `docker-compose.yml` を修正する
```yaml:docker-compose.yml
...
    ports:
      - '80:80'
#      - '81:81'
      - '443:443'
...
```
- 再起動する
```shell
docker compose down
docker compose up -d
```

### Basic 認証の準備
- "Access Lists" をクリックする
  - ![access-lists.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1060173/60ba2761-ba2d-ab0b-1ba0-ba431f14b2a9.png)
- "Add Access List" をクリックする
- "New Proxy Host" の Name は後で分かる名前を適当に入力する
  - ![basic-auth1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1060173/bf6c3e2c-4b1e-b766-8a3f-18d153132bcc.png)
- "New Proxy Host" の "Authorization" に認証情報を入力する
  - ![basic-auth2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1060173/e69cf8c5-bda4-2f4b-9ab6-3df334b9dc00.png)
- "New Proxy Host" の "Access" には IP 制限をしない場合は `all` を入力してから "Save" をクリックする
  - ![basic-auth3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1060173/b1f61a2c-d0ce-f099-bd7d-4904982d05e8.png)

### Web アプリへのリバースプロキシを設定
- "Proxy Hosts" をクリックする
  - ![proxy-hosts.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1060173/5967f233-0e21-fe6e-38e1-7cbcc70ba6aa.png)
- "Add Proxy Host" をクリックする
- "New Proxy Host" の Details を以下のように設定する
  - "Websockets Support" は Websockets を使用している可能性を考慮して有効化する
  - "Forward Hostname" には 'docker-compose.yml' で定義した Forward 先のサービス名を入力する
  - "Forward Port" は公開する Web アプリの仕様に合わせて入力する
  - "Access List" には前の手順で作成した "Access List" の Name を選択する
  - ![details2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1060173/c6ac0caf-7b8f-834d-fb21-2a228f3835b0.png)
- "New Proxy Host" の SSL を管理画面の時と同様に設定する
- 以下のように正しく設定できたことを確認する
  - ![web.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1060173/d1337f21-ec7c-7ce9-217f-adefc7925cdd.png)
- Basic 認証が有効になっていることを確認する
  - https://web.{自分のドメイン}
- 以上です