2025.03.25

コーディング

環境構築

Dockerを使用したNginxリバースプロキシによる Next.js環境構築

Vue(Nuxt.js)・React(Next.js)などを使用した開発時に1つの課題があります。
標準の開発環境では常にlocalhost:3000でアクセスすることになるため、実際の本番環境で使用するドメイン名でのテストができないという点です。

ドメインが異なる場合に良く起きがちな問題として以下のようなパターンがあると思います。

  • Cookieの設定がドメイン依存の場合
  • OAuth認証やSSOなど、特定のドメインにリダイレクトする認証フローをテストする場合
  • CORS(オリジン間リソース共有)の設定をテストする場合
  • サードパーティAPIが特定のドメインからのリクエストのみを許可している場合

今回は、Nginxをリバースプロキシとして使用し、任意のドメイン名でNext.jsアプリケーションにアクセスできるようにするDockerベースのセットアップを紹介します。
この方法は、クライアントサイドレンダリングだけでなく、サーバーサイドレンダリング(SSR)を活用したアプリケーションにも活用できますので、その方法についても解説させていただきます。

Nginxを使用する理由

Next.jsの開発サーバーは便利ではありますが、本番環境では通常NginxやApacheなどのウェブサーバーを使用します。(vercelなどを使用する場合を除く)
ローカル開発環境でも同様の構成を使用することで、以下のようなメリットがあります。

  • 実際のドメイン名での開発: example.comなどの実際のドメイン名を使用して開発できるため、ドメイン依存の機能(Cookie、認証フロー、CORS)を正確にテストできます
  • SSLの設定: HTTPS設定をローカルで行えます
  • 複雑なルーティングの設定: Nginxの設定でURLリライトや複雑なルーティングを実装できます

プロジェクト構成の概要

今回のセットアップでは、Docker-Composeを使用して以下の2つのサービスを起動します。
Next.js:Next.jsアプリケーション
Nginxサーバー:Next.jsアプリケーションへのリクエストをプロキシするウェブサーバー

プロジェクトの構成は以下のとおりです


プロジェクトルート/
├── docker-compose.yml    # Docker Compose 設定
├── nextjs/               # Next.js アプリケーション
│   ├── Dockerfile        # Next.js の Docker 設定
│   └── application/      # Next.js のコード
└── nginx/                # Nginx 設定
    ├── Dockerfile        # Nginx の Docker 設定
    ├── default.conf      # Nginx の設定ファイル
    └── html/             # 静的ファイル用ディレクトリ

docker-compose.ymlの設定


version: '3'

services:
  nextjs:
    build:
      context: ./nextjs
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    volumes:
      - ./nextjs/application:/application
    environment:
      - NODE_ENV=development

  nginx:
    container_name: nginx
    build: ./nginx
    hostname: docker-spa-proxy.com
    ports:
    - 80:80
    volumes:
    - ./nginx/default.conf:/etc/nginx/conf.d/default.conf

nextjs

Next.jsアプリケーションを実行し、3000ポートで公開されるようにしています。
これはNext.jsで立ち上げるサーバーのデフォルトポートをしようしています。
このnextjsコンテナはNext.jsでSSRを使用する場合にのみ使用するので不要な場合は削除しても大丈夫です。

nginx

Nginxサーバーを実行し、80ポートで公開しています。SSLの設定もするのであれば443ポートも公開します。

Next.jsのDockerfile


FROM node:20.9.0-alpine

WORKDIR /application

COPY ./application .

RUN npm install

EXPOSE 3000

CMD ["npm", "run", "start"]

nextjsコンテナのDockerfileは非常にシンプルです。
開発時に使用しているNode.jsのバージョンと同様のNode.jsイメージでコンテナを作成し、Next.jsアプリケーションコードをコンテナにコピーするだけの設定です。
ローカルで開発するときはnpm run devでサーバーを起動するため、このコンテナは使うことはありません。

Nginxのdefault.conf


server {
  listen 80;

  server_name docker-spa-proxy.com;

  root /var/www/html;
  index index.html;

  location / {
    proxy_pass http://host.docker.internal:3000;
    # proxy_pass http://nextjs:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
  }

  client_max_body_size 20M;
}

server_name

server_nameには使用するドメインを設定してください。今回は例としてdocker-spa-proxy.comにしています。
開発時はhostsファイルに以下を設定することでhttp://docker-spa-proxy.comで開発することができます。

127.0.0.1   docker-spa-proxy.com

プロキシ設定

proxy_pass http://host.docker.internal:3000;で開発時にnpm run devで立ち上げてるサーバーを転送します。
もしも本番環境でSSRを使用する場合は、host.docker.internal:3000の部分をhttp://nextjs:3000に書き換えてください。nextjsコンテナで立ち上げたサーバーを転送するようになります。

  • ※ host.docker.internal:3000: ホストマシン(localhost)の3000ポートを転送する
  • ※ nextjs:3000: nextjsコンテナの3000ポートを転送する(Docker Compose のサービス名を使用)

ローカル環境での実行方法


docker-compose up -d nginx

nginxコンテナを立ち上げます。
hostsに設定したドメインにアクセスして以下が表示されれば正常にnginxが起動できています。

Next.jsのローカル環境を起動


# Next.jsアプリケーションのディレクトリへ移動
cd docker-spa-proxy/nextjs/application

# パッケージのインストール
npm install

# サーバー立ち上げ
npm run dev

これで以下のように表示が変わればNext.jsのサーバーをプロキシできています。

本番環境の設定(SSG)

サーバーサイドレンダリングを行う場合は対象外です。本番環境の設定(SSR)まで飛ばしてください。

next.config.mjs変更


/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: false,
  trailingSlash: true,
  distDir: '../../nginx/html',
  output: 'export',
  images: {
    unoptimized: true,
  }
};

export default nextConfig;

docker-spa-proxy/nextjs/application/next.config.mjsの内容を変更してnpm run buildしてください。
docker-spa-proxy/nginx/html/にビルドされたファイルが生成されます。

default.conf変更


server {
  listen 80;

  server_name docker-spa-proxy.com;

  root /var/www/html;
  index index.html;

  client_max_body_size 20M;
 }

プロキシの設定をまるまる削除します。
ローカルと本番でdefault.confの内容が変わるので環境変数を使って、読み込むconfファイルを出し分けるとよいかと思います。


# 立ち上げてるnginxコンテナを落とす
docker-compose down

# default.confを変更したのでコンテナを再度ビルドする
docker-compose build

# 再度nginxコンテナを立ち上げる
docker-compose up -d nginx

http://docker-spa-proxy.comにアクセスしたらビルドしたファイルが表示されるようになっていると思います。

本番環境の設定(SSR)

つづいて、サーバーサイドレンダリングの場合の設定です。
こちらは冒頭にも記載してましたが、default.confのproxy_passとnextjsコンテナを立ち上げるだけです。

もしコンテナを立ち上げてる場合は停止させておいてください。

docker-compose down

default.conf

以下を書き換えてください。


proxy_pass http://host.docker.internal:3000;
↓以下に変更
proxy_pass http://nextjs:3000;

コンテナの立ち上げ

今まではnginxのコンテナしか使用していなかったのでdocker-compose up -d nginxでnginxだけ立ち上げてましたが、両方立ち上げるようにします。


# nextjsとnginxコンテナをビルド
docker-compose build

# nextjsとnginxコンテナを起動
docker-compose up -d

まとめ

Docker、Nginx、Next.jsを組み合わせることで、開発から本番環境まで一貫したウェブアプリケーション環境を構築することができます。
また、PHPなどでNext.jsからデータを取得するAPIを用意する場合は、PHPのコンテナを用意してdefault.confで特定のディレクトリだけPHPを扱えるようにしてあげればOKです。

ちょっと手間ではありますが、環境の差異をできるだけ無くして開発することはセキュアな実装をする上で必要なことだと考え、この方法で実装しております。

今回使用したコードはこちら

この記事を気に入ったら

柄本 広樹

美しい景色、人、食べ物、そんな当たり前の日常に彩るすべてに感謝し、 今も映像を作り続ける。

この人が書いた記事を見る >>