ViteをDocker + Nginxで開発しようとしたら表示できなかった

## はじめに

社内のFEエンジニア向けにプロジェクト構成の考え方を教える勉強会を企画しています。この勉強会では、あるアプリケーションを作成することをベースに、プロジェクトの考え方や構成方法を具体的に解説していくことを想定しています。参加者はFEエンジニアで、FE領域に専門知識を持つ人たちです。しかし、今回のプロジェクトでは専用のバックエンドも必要となるため、事前にFEとBEの基本部分を作成し、Gitを通じて配布することにしました。FE側のテンプレートにはViteを採用し、Dockerで簡単に起動できるようにします。また、エンドポイントの振り分けにはNginxを使用する予定です。
よしこれでいこう！とこの初期状態のプロジェクトの作成をし始めたところ、DockerでViteとNginxを起動してルーティングするところまではいけたのですがなぜか502エラーでFEにアクセスできないという問題に直面しました。問題の解決の方法自体は簡単でしたが、その答えにたどり着くまでに時間がかかったため、今回はその解決策を忘備録としてまとめることにしました。

## 前提条件

- Dockerを使っています
- この記事ではBEには触れません
- FEのテンプレートはViteなので、Viteの場合の解決策になります
- NginxやDockerの設定は自分の知識の中からやっています、最適な設定ではない可能性があります
- 今回はあくまでDocker起動して、Nginxを通してViteで起動してるFEを閲覧できるようにするまでです。Nginxの説明やViteの詳細には入りません

## まずは起動を試みる

`Vite` + `Docker` + `Nginx`は初めてだったので、色々調べながら、とりあえず起動までは漕ぎ着けます。
### Nginxの設定

まずはNginxの設定から。今回は`Dockerfile.dev`と`default.conf`だけ設定します。

```Dockerfile.dev
FROM nginx
COPY ./default.conf /etc/nginx/conf.d/default.conf
```

```default.conf
upstream frontend {
    # "client"の部分がFEのためのDockerサービス名
    server client:5173;
}

server {
    listen 80;
    server_name localhost;

    location / {
        # "frontend"の部分がupstreamを指している
        proxy_pass http://frontend/;

        # 下の設定はFEのコードがHot Reloadされるために設定している
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
```

### Viteの設定

Viteはただ`pnpm create vite`を実行して作成されたファイルと、`Dockerfile.dev`です。

```dash
.
├── Dockerfile.dev
├── README.md
├── index.html
├── node_modules
├── package.json
├── pnpm-lock.yaml
├── public
│   └── vite.svg
├── src
│   ├── App.css
│   ├── App.tsx
│   ├── assets
│   │   └── react.svg
│   ├── index.css
│   ├── main.tsx
│   └── vite-env.d.ts
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
```

`Dockerfile.dev`の中身は以下です。

```Dockerfile.dev
FROM node:20-alpine

WORKDIR /app

COPY package.json ./
RUN npm install -g pnpm

RUN pnpm install

COPY ./ ./

CMD ["pnpm", "run", "dev"]
```

### docker-compose.ymlの設定

今回は背景がDockerで起動できるようにして受講者にはFEだけに集中できるようにすることなので、docker composeを起動できるように`docker-compose.yml`を作成します。

```yml:docker-compose.yml
version: "3"

networks:
  dev:
    driver: bridge

services:
  nginx:
    restart: always
    build:
      dockerfile: Dockerfile.dev
      context: ./nginx
    ports:
      - 5176:80
    volumes:
      - ./nginx:/etc/nginx/conf.d/
    depends_on:
      - client
  client:
    build:
      dockerfile: Dockerfile.dev
      context: ./frontend
    volumes:
      - /app/node_modules # container内のnode_modulesを使用
      - ./frontend:/app
    expose:
      - 5173
    stdin_open: true
```

中身はそんなにないです、docker composeを使って`nginx`ディレクトリにある`Dockerfile.dev`と`frontend`ディレクトリにある`Dockerfile.dev`を使ってDockerを起動できるようにします。

特筆すべき点は、nginxはport 5176を聞いてそれをport 80に流すようにしていて、FEはport 5173を解放していることです。`default.conf`内を見てもらうと、`nginx`自体はport 80を聞いていて、それを最終的にport 5173にマッピングしています。これは学習用のアプリケーションのため、あざとマッピングがあっちこっちいくようにしています。


### 起動

ここまできたら、起動させましょう。プロジェクトのルートでコンソールを開いて、`docker compose up -d --build`を実行します。

```bash
筆者PC @~/dev/vite-with-nginx: docker compose up -d --build
~~ビルド情報~~
[+] Running 2/3
 ⠧ Network vite-with-nginx_default     Created                 0.7s 
 ✔ Container vite-with-nginx-client-1  Started                 0.6s 
 ✔ Container vite-with-nginx-nginx-1   Started                 0.2s 
筆者PC @~/dev/vite-with-nginx: 
```

最終的に上記の表示になっていれば問題なしです。

ブラウザを開いてlocalhost:5176を開く。

![スクリーンショット 2024-04-07 23.21.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147238/23295ab1-8698-c8b8-ecee-4a832535e042.png)
※localhostのportが5176

__なんで？:rage:__

設定的には、portも開いてるはずだし5176もアクセスできているし....502ということはnginxにはちゃんとアクセスできている。

さらに、別のコンソールを開いて`pnpm run dev`をすると普通にViteのプロジェクトを開ける。

![スクリーンショット 2024-04-07 23.21.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147238/309a51be-8e26-6f1b-5dce-5eab8c723061.png)
※localhostのportが5173

ということは、何かでnginxからViteにアクセスできていないことになる。


## 結論

かなり調査をして、原因がわかった。
どうやら、Dockerを使ってるためかViteのhostを晒してあげる必要があるらしい。

設定はとても簡単で、`vite.config.ts`を開いて、`server.host`をt`true`にするだけ。

```ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";

// https://vitejs.dev/config/
export default defineConfig({
  server: {
    host: true,
  },
  plugins: [react()],
});
```

![スクリーンショット 2024-04-07 23.24.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147238/ec3f96bb-c93c-cde5-0d0e-d189c0343fbf.png)
※localhostのportが5176

開けた....
これを見つけるのに3時間くらい無駄にしました。

最初は、nginxが悪いのかとその辺りを調べていました。ローカルでViteを起動する分にはちゃんとアクセスできてたので、Viteは問題ないはず！と思い込んでViteが問題だとは思っていませんでした。

## あとがき

皆さんも、ここは問題ないはず！という思い込みはやめましょう。