NginxでNext.jsにリバースプロキシする【Art Navi開発記録 #6】
はじめに
こんにちは。
なかのひとカンパニーの archer です。
美術展検索サービス Art Navi の開発内容を、備忘録も兼ねて記事にしています。
- サービスURL: https://art-weekend.jp/
前回は、Docker ComposeでNext.jsを本番起動する構成について書きました。
今回は、Next.jsの前段に Nginx を置いて、リバースプロキシする構成についてまとめます。
今回やりたいこと
Art Naviでは、Next.jsアプリをDockerコンテナで起動しています。
ただし、外部から直接Next.jsへアクセスさせるのではなく、前段にNginxを置く構成にしています。
今回の目的は以下です。
- Nginxコンテナを用意する
- NginxからNext.jsへプロキシする
- Docker Compose内でコンテナ同士を通信させる
- 外部公開はNginx側に集約する
ざっくりした構成は以下です。
ユーザー
↓
Cloudflare
↓
Nginx
↓
Next.js
今回は、このうち以下の部分を扱います。
Nginx
↓
Next.js
なぜNginxを前段に置くか
Next.jsは単体でも起動できます。
ただ、本番環境ではNginxを前段に置くことで、構成を整理しやすくなります。
Nginxを使う理由は以下です。
- 外部公開する入口をNginxに集約できる
- Next.jsコンテナを直接公開しなくてよい
- 将来的に複数サービスを切り替えやすい
- 静的ファイルやヘルスチェックの制御を追加しやすい
- Cloudflare Tunnelとの接続先をNginxにまとめやすい
Art Naviでは、今後ほかのサービスも同じサーバー上で動かす可能性があるため、Nginxを前段に置く構成にしました。
Docker Composeの構成
Next.jsとNginxを同じDocker Compose内で起動します。
例としては以下のような構成です。
services:
nextjs:
build:
context: .
dockerfile: Dockerfile
container_name: art-navi-nextjs
environment:
NODE_ENV: production
SITE_URL: https://art-weekend.jp
expose:
- "3000"
restart: unless-stopped
nginx:
image: nginx:1.27-alpine
container_name: art-navi-nginx
depends_on:
- nextjs
ports:
- "80:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
restart: unless-stopped
ポイントは、Next.js側を ports ではなく expose にしていることです。
expose:
- "3000"
Next.jsは外部に直接公開せず、Nginxからだけアクセスする想定です。
Nginxの設定ファイル
Nginxの設定ファイルは、以下のように配置します。
nginx/
default.conf
default.conf の例です。
server {
listen 80;
server_name _;
location / {
proxy_pass http://nextjs:3000;
proxy_http_version 1.1;
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;
}
}
この設定で、Nginxに来たリクエストをNext.jsコンテナへ転送できます。
Nginx
↓
http://nextjs:3000
Docker Compose内では、サービス名 nextjs をホスト名として使えます。
proxy_passの指定
今回のポイントはここです。
proxy_pass http://nextjs:3000;
localhost:3000 ではなく、nextjs:3000 を指定します。
Dockerコンテナ内で localhost と書くと、そのコンテナ自身を指します。
NginxコンテナからNext.jsコンテナへアクセスしたい場合は、Docker Composeのサービス名を使います。
localhost:3000
Nginxコンテナ自身を見に行く
nextjs:3000
Next.jsコンテナを見に行く
ここは最初に混乱しやすいポイントでした。
ヘッダー設定
NginxからNext.jsへリクエストを渡すときに、いくつかヘッダーを設定しています。
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;
それぞれの意味はざっくり以下です。
Host
元のホスト名を渡す
X-Real-IP
クライアントのIPを渡す
X-Forwarded-For
経由したプロキシ情報を含めてIPを渡す
X-Forwarded-Proto
http / https の情報を渡す
Next.js側でURL生成やログ確認をするときに、元のリクエスト情報が分かるようにするためです。
起動手順
設定ができたら、Docker Composeで起動します。
docker compose up -d --build
コンテナを確認します。
docker compose ps
Nginxのログを確認します。
docker compose logs -f nginx
Next.js側のログを確認します。
docker compose logs -f nextjs
動作確認
Nginxが80番ポートで公開されている場合、以下で確認できます。
curl -I http://localhost
レスポンスが返ってくれば、Nginx経由でNext.jsへアクセスできています。
別PCから確認する場合は、サーバーのIPアドレスを使います。
curl -I http://192.168.x.x
ブラウザでも同じように確認できます。
http://192.168.x.x
よく使うコマンド
設定変更後に再起動します。
docker compose restart nginx
設定を反映して作り直します。
docker compose up -d --build
ログを確認します。
docker compose logs -f nginx
Nginxコンテナに入ります。
docker compose exec nginx sh
Nginx設定をテストします。
docker compose exec nginx nginx -t
nginx -t は設定ミスを確認できるので、かなり便利です。
詰まりやすいポイント
今回の構成で詰まりやすいのは、以下のあたりです。
-
proxy_passにlocalhost:3000と書いてしまう - Next.js側を
exposeではなくportsで直接公開してしまう - Nginx設定変更後にコンテナを再起動していない
-
default.confのマウント先を間違える - Next.jsコンテナが起動していない
- Docker Composeのサービス名とNginx設定の名前が一致していない
特に、proxy_pass http://nextjs:3000; の nextjs は、Docker Composeのサービス名と合わせる必要があります。
services:
nextjs:
この名前と一致していないと、Nginxから接続できません。
今回の構成でよかった点
Nginxを前段に置いたことで、以下のメリットがありました。
- 外部公開の入口を整理できた
- Next.jsを直接公開しなくてよくなった
- Cloudflare Tunnelの接続先をNginxにできた
- 将来的に複数サービスを扱いやすくなった
- 本番環境らしい構成に近づいた
個人開発でも、Nginxを入れておくと後から構成を拡張しやすいと感じました。
まとめ
今回は、NginxでNext.jsにリバースプロキシする構成についてまとめました。
今回のポイントは以下です。
- Next.jsはDockerコンテナで3000番ポート起動する
- 外部公開はNginxに任せる
- NginxからNext.jsへ
proxy_passする - Docker Compose内ではサービス名で通信する
-
localhostではなくnextjsを使う - 設定確認には
nginx -tが便利
次回は、Cloudflare Tunnelで自宅サーバーを公開する構成について書く予定です。