Next.jsでSpotifyAPIを使用したWebアプリをvpsに公開するまで

## 概要
アプリケーションを公開するには、VPS（仮想プライベートサーバー）を使用して、アプリを動作させる環境を構築します。前回の記事は[こちら](https://qiita.com/g-o/items/02a93b352bd336091a73)です。DockerをVPSにインストールし、アプリをデプロイする基本手順を説明します。さくらVPSの基本設定やドメイン取得は設定済としています。

## さくらVPSにDockerをインストール
さくらVPSにSSH接続し、Dockerの設定をします。
```bash
sudo yum remove -y docker
                  docker-client
                  docker-client-latest
                  docker-common
                  docker-latest
                  docker-latest-logrotate
                  docker-logrotate
                  docker-engine
```
```bash
sudo yum install -y yum-utils
                   device-mapper-persistent-data
                   lvm2
```
```bash
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker $USER
newgrp docker
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
```

サーバーの管理画面でパケットフィルターでポート3000を開放します（通常のポート80を使用中のため）。

## アプリをDockerコンテナ化
Next.jsとPostgreSQLを一体化したコンテナを作成するために`docker-compose.prod.yml`を作成します。
```yml:docker-compose.prod.yml
version: "3.9"
services:
  postgres:
    image: postgres:15
    container_name: postgres_container
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: always
    env_file:
      - .env.production

  nextjs:
    build: .
    container_name: nextjs-app
    ports:
      - "3000:3000"
      # - "80:3000" # apacheで使用中のため使用できない 
    env_file:
      - .env.production
    depends_on:
      - postgres
    restart: always
    command: ["sh", "-c", "npx prisma migrate deploy && npm run start"]

volumes:
  postgres_data:
```

Next.jsプロジェクト単体をコンテナ化するために`Dockerfile`を作成します。
```Dockerfile:Dockerfile
# ベースイメージとしてNode.jsを使用
FROM node:18 AS builder

# 作業ディレクトリの設定
WORKDIR /app

# 必要なファイルをコンテナにコピー
COPY package.json package-lock.json ./

# 依存関係をインストール
RUN npm install

# 必要なファイルをコピー 
COPY . .

# Prisma Client の生成
RUN npx prisma generate

# Next.jsアプリケーションのビルド
RUN npm run build

# 実行環境用のイメージ
FROM node:18

WORKDIR /app

# 依存関係のみコピー
COPY --from=builder /app/package.json /app/package-lock.json ./
RUN npm install --production

# ビルド済みファイルをコピー
COPY --from=builder /app ./

# 環境変数を明示的に設定
ENV NODE_ENV=production

# 必要なポートを公開
EXPOSE 3000

# Next.jsアプリケーションを起動
CMD ["npm", "start"]
```

公開用に環境変数を修正した`.env.production`を設定します。
```.env.production
DATABASE_URL="postgresql://my_user:my_password@postgres:5432/my_database?schema=public"

POSTGRES_USER=
POSTGRES_PASSWORD=
POSTGRES_DB=

SPOTIFY_CLIENT_ID=
SPOTIFY_CLIENT_SECRET=

NEXTAUTH_SECRET=
NEXTAUTH_URL=http://tunetrek.iut-b.site:3000
```

サーバーへファイルを保存します。次のファイル`.next`、`node_modules`、 `.gitignore`、`.env`、`docker-compose.yml`はローカル用のため不要です。

```plaintext
project/
├── .next/                        
├── node_modules/                 
├── prisma/                       
│   ├── migrations/
│   └── schema.prisma             # データベース関係設定
├── public/                       
│   └── assets/                   # Bootstrapのテンプレートファイル
├── src/                          
│   ├── app/
│   │   ├── api/                  # バックエンドのAPIを作成
│   │   ├── components/           # 再利用するコンポーネントを作成
│   │   ├── favorites/            # お気に入りのページを作成
│   │   ├── fonts/
│   │   ├── playlists/            # プレイリストのページを作成
│   │   ├── top-tracks/           # トップトラックのページを作成
│   │   ├── global.css            
│   │   ├── layout.tsx            # アプリ全体のレイアウトを設定
│   │   ├── next.auth.d.ts        # NextAuth.jsで使用する型定義
│   │   └── page.tsx              # トップページ
│   ├── lib/                      # ユーティリティ関数を作成
│   └── types/                    # TypeScriptの型定義
├── .dockerignore                 # Dockerで無視するファイルリスト
├── .env                          # 環境変数ファイル（ローカル環境用）
├── .env.production               # 環境変数ファイル（本番環境用）
├── .eslintrc.json               
├── docker-compose.prod.yml       # 本番環境用のDocker Compose設定
├── docker-compose.yml            # Docker Compose設定
├── Dockerfile                    # Dockerイメージ構築用設定
├── next-env.d.ts                
├── next.config.js                # Next.js設定ファイル
├── package-lock.json             
├── package.json                  
├── postcss.config.mjs            
├── README.md                     
├── tailwind.config.ts            
└── tsconfig.json                 
```

Dockerのコンテナを作成し起動します。
```bash
docker-compose -f docker-compose.prod.yml up --build -d
```

エラーが発生した場合は、以下のようなコマンドで状態を確認します。
```bash
docker ps
docker logs <コンテナ名>
docker logs postgres_container
docker exec -it nextjs-app printenv
```

Dockerのコンテナを停止します。
```bash
docker-compose -f docker-compose.prod.yml down
```

以下のサイトで確認します。

http://tunetrek.iut-b.site:3000/