![[自サーバでNext.jsアプリを動かす#3]Nginxのキャッシュゾーン設定](/_next/image?url=%2Farticles%2Fnext-js%2Fnginx-cache%2Fhero.jpg&w=3840&q=75)
自サーバでNext.jsアプリを動かす#3Nginxのキャッシュゾーン設定
キャッシュゾーンを利用してサーバ負荷を軽減しながらNext.jsで構築したWebアプリケーションを運用
初回公開日
最終更新日
「自サーバでNext.jsアプリを動かす」の第3回はNginxのキャッシュゾーンの設定を行います。
Next.jsはWebアプリケーションが構築しやすい反面、SSR(サーバーサイドレンダリング)や
revalidate
などを利用するISR(インクリメンタルスタティックリジェネレーション)など、動的・静的なコンテンツが混在する構成をとっており、以下のような課題もあります。- 同じページが頻繁に再生成されてサーバ負荷が高くなる
- 海外からのボットアクセスがSSRエンドポイントを攻撃してくる
- パフォーマンス改善が必要(TTFB短縮)
この課題解決として、Nginxのキャッシュゾーンを使うことで、再生成済みのレスポンスをNginxが保持して高速に返せるようになります。
example.com
というサイトを例に設定作業を進めていきます。1.キャッシュ用ディレクトリの作成
まずはキャッシュファイルを保存するディレクトリを作成します。
bash
1sudo mkdir -p /var/cache/nginx/example_com
2sudo chown -R nginx:nginx /var/cache/nginx
Nginxが使用するのでパーミッションを
nginx
にしておきます。2.nginx.conf にproxy_cache_pathを設定
nginx.conf
にキャッシュバスとキャッシュキーの設定を追記します。bash
1sudo vi /etc/nginx/nginx.conf
diff : nginx.conf
1http {
2 include /etc/nginx/mime.types;
3 default_type application/octet-stream;
4
5+ proxy_cache_path /var/cache/nginx/example_com levels=1:2 keys_zone=example_com_cache:50m inactive=1h use_temp_path=off;
6+ proxy_cache_key "$scheme$request_method$host$request_uri";
7
8 log_format main '$remote_addr - $remote_user [$time_local] "$request" '
9 '$status $body_bytes_sent "$http_referer" '
10 '"$http_user_agent" "$http_x_forwarded_for"';
proxy_cache_pathの各パラメータの意味
パラメータ | 意味・役割 |
---|---|
/var/cache/nginx/example_com | Nginxがキャッシュファイルを保存する物理パス。ディレクトリは事前に作成して権限設定しておく必要あり |
levels=1:2 | キャッシュファイルを分散して保存するディレクトリ構造の深さ。: で何階層構造にするかを決めている。数値部分は何文字のディレクトリ名にするかを指定していて、ディレクトリ名はキャッシュキーのハッシュの先頭から自動で拾う。例えばキャッシュキーのハッシュが a1b2c3d4e5f6... だと、/a/1b/ 以下にキャッシュファイルが保存されるようになる。これにより大量のファイルが1ディレクトリに偏らず、ファイルシステムのパフォーマンスが落ちない |
keys_zone=example_com_cache:50m | 名前付きキャッシュゾーンを定義。50m はメモリ上に保持されるキー情報の容量(あくまでキー情報だけをメモリ上に保存してキャッシュデータそのものはディスク)。ゾーン名(ここでは example_com_cache)は proxy_cache で参照 |
inactive=1h | 1時間アクセスがなければ対象のキャッシュを削除。ただし、削除は即時ではなくガベージコレクション時に行われる |
use_temp_path=off | 一時ファイルを /var/cache/nginx/... に直接書き込む。デフォルトでは /var/lib/nginx/tmp/ に書かれるが、同じパスにした方がI/O効率がよくなることが多い |
proxy_cache_keyの変数の意味
この設定は、キャッシュの一意性を決定するキーをどう構成するかを決めています。
変数 | 説明 |
---|---|
$scheme | http か https。スキームが違えば別のキャッシュとして扱われる |
$request_method | GET, POST, HEAD など。通常は GET だけキャッシュするが、違うメソッドは別キャッシュになる |
$host | ホスト名(例: example.com)。同じIPで複数ドメイン運用時に有効 |
$request_uri | パスとクエリ文字列(例: /blog?page=2)。クエリ違いも別キャッシュとして扱う |
3.各サイトのserverブロックでキャッシュを利用
次に、各サイトのNginx設定にキャッシュ利用の設定を追加していきます。
bash
1sudo vi /etc/nginx/conf.d/example.com.conf
sshのseverブロックの
location /
ディレクティブへ追記します。diff : example.com.conf
1server {
2 listen 443 ssl default_server;
3 listen [::]:443 ssl default_server;
4 http2 on;
5 listen 443 quic reuseport;
6 listen [::]:443 quic reuseport;
7・・省略・・
8location / {
9 proxy_pass http://localhost:3000;
10 proxy_http_version 1.1;
11 proxy_set_header Upgrade $http_upgrade;
12 proxy_set_header Connection 'upgrade';
13 proxy_set_header Host $host;
14 proxy_set_header X-Real-IP $remote_addr;
15 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
16 proxy_set_header X-Forwarded-Proto $scheme;
17 proxy_cache_bypass $http_upgrade;
18
19# ここからキャッシュ設定
20+ proxy_cache example_com_cache;
21+ proxy_cache_valid 200 302 1h;
22+ proxy_cache_valid 404 1m;
23+ add_header X-Cache-Status $upstream_cache_status;
24+ add_header X-Cache-Key $scheme$request_method$host$request_uri;
25
26 }
severブロック内のキャッシュ設定の意味
パラメータ | 説明 |
---|---|
proxy_cache | * どのキャッシュゾーンを使うか指定 * proxy_cache_path で定義した keys_zone=delogs_jp_cache:50m に紐づくゾーンを使う |
proxy_cache_valid | * HTTPレスポンスコード 200 と 302 を受け取ったレスポンスは、1時間キャッシュ * 404 Not Found も1分間キャッシュして、同じリクエストが短期間に繰り返されるのを防止 |
add_header X-Cache-Status | * キャッシュされたかどうかをレスポンスヘッダに追加 * $upstream_cache_status の値は次のいずれかになる HIT:キャッシュから返された MISS:バックエンドに問い合わせた(キャッシュされてなかった) BYPASS:キャッシュバイパス条件にマッチ(例: Cookieなど) EXPIRED:キャッシュは存在したが有効期限切れ、再取得後更新 |
add_header X-Cache-Key | * 実際に使われたキャッシュキー(文字列)をヘッダとして返す * $scheme$request_method$host$request_uri は、どのURL+メソッドがキャッシュ対象になったかを表す(例:httpsGETexample.com/blog?page=2) |
少しわかりづらいのが、
nginx.conf
で設定したinactive=1h
とproxy_cache_valid
の違いです。- proxy_cache_valid と inactive の違いを再確認
設定項目 | 意味 | 例 |
---|---|---|
proxy_cache_valid 1h | キャッシュの「有効期間」。1時間後に期限切れ(再取得される) | 新しいページを定期的に反映したいときに使う |
inactive=1h | アクセスがないと削除される「保管期限」。1時間アクセスされなければ削除される | 過去に生成されたけど誰も見ないページを掃除するため |
inactive
は該当ページが誰にもアクセスされない時に削除されるまでの時間を指定している感じです。4.各種設定の目安
設定方法やパラメータの内容は把握できても、実際どんな値にすればいいのか、私自身は結構悩みました。
そこで、
そこで、
ChatGPT
に相談して目安を弾き出してもらいました。その内容を共有しておきます。keys_zone=...:50m の箇所の目安について
このサイズは「メモリに保持するキャッシュキーのインデックス情報だけ」の容量なので、私は50MBにしましたが、現状の当サイトの規模を考えるとこれでも少し多めかなと思っています。目安は下記のようです。
keys_zone | 想定されるキャッシュ件数 |
---|---|
10m ~ 20m | 数千~1万件程度 |
30m ~ 50m(今の設定) | 数万~10万件 |
100m 以上 | 数十万以上 |
私の場合、
inactive=1h
としたので、この1時間の間にどれくらいのアクセスがあるかによるのですが、サイトのページ数(パラメータごとに一意として)にもよるので運用しながら調整する必要はありそうです。levels=1:2 の箇所の目安について
1ディレクトリ内に数万ファイルがあると、UNIX系ファイルシステムは遅くなるということで、負荷分散するための設定ですが、これを第二階層までいいのか、もう少し階層を増やした方がいいのか、悩みました。
ChatGPT
による目安は下記のようになりました。規模 | 推奨Levels |
---|---|
小〜中規模(数千〜数万件) | 1:2(今回の構成) |
中〜大規模(数十万件〜) | 2:2 または 1:2:1 |
超大規模(100万件〜) | 1:2:2 や 2:2:2 |
規模のカッコ内はキャッシュ件数になります。
inactive=1h
としているので1時間のユニークキャッシュの件数ということになります。たとえば…
- サイトが毎分100リクエストある
- そのうち一意のURLが半分だと仮定(50件/分)
- → 1時間で最大 50 × 60 = 3,000 件のキャッシュキー この場合、3000件のキャッシュファイルが1時間以内に生成され、存在する可能性がある。
→ levels=1:2 で最大4096ディレクトリ分散なので、ファイルシステム的に余裕があるという計算になります。
正直、当サイト的には毎分100リクエストというのもかなり多めですが、Webプロモーションをガンガンやるサイトですと小中規模でもあり得る数値ですので、この辺も運用しながら調整していく必要がありそうです。
5. 運用時に各種数値の適正値を見極めるために
各種数値を運用しながらチェックして修正するためにはログにキャッシュの使用状況を分かりやすく出力して、それをチェックする方法も確立しておく必要があります。
ログ出力内容へ追加
再度
nginx.conf
を編集して、ログ出力に$upstream_cache_status
と$scheme$request_method$host$request_uri
を追加します。bash
1sudo vi /etc/nginx/nginx.conf
bash : nginx.conf
1log_format main '$remote_addr - $remote_user [$time_local] "$request" '
2 '$status $body_bytes_sent "$http_referer" '
3 '"$http_user_agent" "$http_x_forwarded_for"'
4 'cache_status=$upstream_cache_status cache_key="$scheme$request_method$host$request_uri"';
これにより:
- cache_status=HIT や MISS, BYPASS, EXPIRED などがログに記録される
- cache_key="httpsGETdelogs.jp/blog?page=2" のように、実際に使われたキャッシュキーも記録される
ログの確認方法
あとは
grep
でaccess.logから情報を抽出して確認するればOKです。bash
1# ヒット件数集計
2sudo grep 'cache_status=HIT' /var/log/nginx/access.log | wc -l
3
4# 未キャッシュの確認
5sudo grep 'cache_status=MISS' /var/log/nginx/access.log | wc -l
6
7# 一意キー数の確認
8sudo grep 'cache_key=' /var/log/nginx/access.log | sort | uniq
6. 最後にnginxの再読み込み
bash
1sudo nginx -t && sudo systemctl reload nginx
この構成により、不要なキャッシュヒットや誤キャッシュを防ぎ、ページ単位・パラメータ単位で正確にキャッシュされるようになります。次回はセキュリティヘッダと静的アセットのキャッシュ期間の設定です。自サーバでNext.jsアプリを動かすところまで、あと一歩です。
次回はこちら...
前回の確認はこちら...
この記事の執筆・編集担当
DE
松本 孝太郎
DELOGs編集部/中年新米プログラマー
ここ数年はReact&MUIのフロントエンドエンジニアって感じでしたが、Next.jsを学んで少しずつできることが広がりつつあります。その実践記録をできるだけ共有していければと思っています。
▼ 関連記事
[自サーバでNext.jsアプリを動かす#2]PM2を利用して、快適にNext.jsアプリを動かす
Next.jsで作成したWebサイト・アプリを自サーバで運用するために「PM2」というミドルウェアを利用して、快適に運用して方法のまとめ
2025/6/20公開
![[自サーバでNext.jsアプリを動かす#2]PM2を利用して、快適にNext.jsアプリを動かすのイメージ](/_next/image?url=%2Farticles%2Fnext-js%2Fpm2%2Fhero-thumbnail.jpg&w=1200&q=75)
[自サーバでNext.jsアプリを動かす#1]Node.jsインストール+Nginx設定+デプロイ
Next.jsで作成したWebサイト・アプリを自サーバのNginxで動かすための設定とデプロイ作業の整理
2025/6/20公開
![[自サーバでNext.jsアプリを動かす#1]Node.jsインストール+Nginx設定+デプロイのイメージ](/_next/image?url=%2Farticles%2Fnext-js%2Fnginx-setting%2Fhero-thumbnail.jpg&w=1200&q=75)
[自サーバでNext.jsアプリを動かす#4]セキュリティヘッダと静的アセットのキャッシュ期間の設定
Next.jsで作成したWebサイト・アプリケーションを自サーバで運用するためのNginxのセキュリティヘッダと静的アセットのキャッシュ期間設定を実施
2025/6/20公開
![[自サーバでNext.jsアプリを動かす#4]セキュリティヘッダと静的アセットのキャッシュ期間の設定のイメージ](/_next/image?url=%2Farticles%2Fnext-js%2Fnginx-header%2Fhero-thumbnail.jpg&w=1200&q=75)
[自サーバでNext.jsアプリを動かす#5]リードレプリカ(スレーブ)DBの利用
SELECT系専用のリードレプリカ(スレーブ)DBとマスタDBへの接続を同居させる方法
2025/6/20公開
![[自サーバでNext.jsアプリを動かす#5]リードレプリカ(スレーブ)DBの利用のイメージ](/_next/image?url=%2Farticles%2Fserver%2Fdb-replica%2Fhero-thumbnail.jpg&w=1200&q=75)