Nginx サーバーで HTTP キャッシュポリシーを設定することで、ウェブサイトのパフォーマンスを向上させます。このポリシーは、ブラウザやコンテンツデリバリーネットワーク (CDN) などの中間プロキシに対し、画像、CSS、JS ファイルなどの静的アセットをキャッシュするように指示します。アセットがキャッシュされると、ブラウザはサーバーにリクエストする代わりに、ローカルコピーから直接読み込むことができます。このアプローチにより、ページの読み込み時間が短縮され、帯域幅の使用量が削減され、サーバーの負荷が軽減されます。
一般的なキャッシュポリシーの例
このセクションでは、さまざまなユースケース向けに Nginx 設定ファイルに追加できる一般的なキャッシュ構成について説明します。すべての例では、304 Not Modified を含むすべての応答にキャッシュヘッダーが確実に追加されるように、add_header ... always; を使用しています。
ユースケース 1:静的リソースの長期キャッシュ設定
# 静的リソースの長期キャッシュを設定
# - コンテンツハッシュを含むファイル名 (例: main.a1b2c3d4.js) の場合、1年間のキャッシュと immutable の使用を推奨します。
location ~* "\.[a-f0-9]{8,}\.(css|js|png|jpg|jpeg|gif|svg|webp|ico|woff|woff2)$" {
# ビルドツールで生成されたハッシュを持つリソースの場合:1年間キャッシュし、ブラウザは再検証を行いません。
add_header Cache-Control "public, max-age=31536003, immutable" always;
access_log off;
}
# - ファイル名が固定で変更が稀な場合 (例: logo.png) は、30日間のキャッシュを使用します。
location ~* \.(css|js|png|jpg|jpeg|gif|svg|webp|ico|woff|woff2)$ {
# ハッシュのない一般的な静的リソースの場合:30日間キャッシュし、CDN とブラウザのキャッシュを許可します。
add_header Cache-Control "public, max-age=2592000" always;
access_log off;
}ユースケース 2:HTML ドキュメントまたはシングルページアプリケーション (SPA) のエントリポイントに対するキャッシュポリシーの設定
HTML ページ、特に index.html のような SPA のエントリーファイルは、新しいデプロイメントでコンテンツが変更されるため、長期キャッシュを設定しないでください。ただし、パフォーマンスのバランスを取るために、ブラウザにファイルをキャッシュさせ、使用するたびにサーバーで再検証を要求することができます。
# 直接リクエストされた HTML ファイルの場合
location ~* \.html$ {
# ブラウザのキャッシュを許可しますが、使用するたびにサーバーでの再検証が必要です。
# 'private' は中間プロキシ (CDN など) がこの応答をキャッシュするのを防ぎます。
# サーバーは検証をサポートするために ETag または Last-Modified ヘッダーを提供する必要があります。
add_header Cache-Control "private, no-cache, must-revalidate" always;
}このポリシーは、ブラウザが条件付きリクエストを行えるように、サーバーが
ETagまたはLast-Modified応答ヘッダーを返すことを前提としています。Nginx は、デフォルトで静的ファイルに対してこれらのヘッダーを提供するため、追加の構成は必要ありません。CDN のような中間プロキシが HTML コンテンツをキャッシュするのを防ぐには、
privateディレクティブを使用します。これにより、エンドユーザーのブラウザのみが応答をキャッシュできるようになります。
ユースケース 3:動的コンテンツまたは機密情報のキャッシュ無効化
API エンドポイント、ユーザープロファイルページ、支払いページなど、動的に生成されるコンテンツや機密データを含むコンテンツについては、キャッシュを無効にする必要があります。これはブラウザおよび CDN や共有キャッシュなどすべての中間プロキシに適用されます。キャッシュを無効にすることで、情報漏洩やデータの不整合を防ぎます。
# 例:動的な PHP スクリプトの場合 (パスは必要に応じて調整してください)
location ~ \.php$ {
# ... その他の PHP-FPM 設定 ...
# すべてのキャッシュを無効化:ブラウザ、プロキシ、CDN は応答を保存してはなりません。
# 'no-store' は最も厳格なキャッシュコントロールディレクティブです。
add_header Cache-Control "no-store" always;
}クライアントサイドのキャッシュ設定 (ブラウザの制御)
ユーザーのブラウザのキャッシュ動作は、HTTP 応答に Cache-Control および Expires ヘッダーを追加することで制御できます。この方法は、ネットワークリクエストを削減し、エンドユーザーのアクセスを高速化します。
主要なディレクティブ
expiresディレクティブ:ExpiresヘッダーとCache-Controlヘッダーのmax-ageの両方を設定します。構文:
expires [time|epoch|max|off];例:
expires 30d;は 30 日間キャッシュします。expires -1;は、クライアントにキャッシュされたバージョンを使用する前にサーバーでリソースを再検証させます。これはCache-Control: no-cacheと同等ですが、キャッシュにリソースを保存することは許可します。注:
add_headerディレクティブはより詳細な制御を提供するため、推奨される設定方法です。
add_headerディレクティブ:指定された HTTP ヘッダーを応答に追加します。構文:
add_header <name> <value> [always];alwaysパラメーターの説明
- デフォルトでは、add_headerは 2xx および 3xx 応答にのみ適用されます。 -304 Not Modified応答の場合、Nginx はカスタムヘッダーを自動的に追加しません。ブラウザは最初の 200 応答のキャッシュポリシーを使用しますが、キャッシュコントロールヘッダーにalwaysパラメーターを追加する必要があります。これにより、すべての応答ステータスコードにヘッダーが適用され、明確性と互換性が確保されます。
Cache-Control のキーと値の説明
public:応答は、ブラウザ、CDN、プロキシサーバーなど、あらゆるキャッシュに保存できます。private:エンドユーザーのブラウザのみが応答をキャッシュできます。CDN などの共有キャッシュは禁止されます。これは、ユーザー固有の情報を含むコンテンツに適しています。no-cache:クライアントは、キャッシュコピーを使用するたびにサーバーに検証リクエストを送信する必要があります。リソースが変更されていない場合、サーバーは304 Not Modifiedを返し、クライアントはローカルキャッシュを使用します。これにより帯域幅が節約されます。no-store:ブラウザとプロキシサーバーが応答のいかなる部分も保存することを禁止します。これは、機密性の高いデータに適しています。max-age=<seconds>:キャッシュの有効期間を秒単位で設定します。immutable:リソースのコンテンツがその鮮度寿命の間に変更されないことをブラウザに伝えます。これにより、ユーザーが完全なページリフレッシュを行った場合でも、ブラウザはこのリソースの検証リクエストをスキップできます。これは、ファイル名にバージョンハッシュが含まれるファイルに最適です。
デプロイと検証
設定の編集
サイトのserverブロックにlocationブロックを追加します。設定ファイルは通常、/etc/nginx/conf.d/または/etc/nginx/sites-enabled/にあります。設定の再読み込み
sudo nginx -t && sudo nginx -s reload応答ヘッダーの検証
curlを使用して、キャッシュヘッダーがアクティブかどうかを確認します。この方法はブラウザキャッシュの影響を受けません。curl -I http://your-domain.com/path/to/file.js出力には、
Cache-Control: public, max-age=31536000のような期待されるヘッダーが含まれているはずです。304 動作の検証 (ETag または no-cache が設定されている場合)
検証ヘッダーを手動で送信してテストします:ETAG=$(curl -I http://example.com/file.js 2>/dev/null | grep -i etag | cut -d' ' -f2 | tr -d '\r') curl -H "If-None-Match: $ETAG" -I http://example.com/file.js # 304 応答が期待されますブラウザでの検証
開発者ツール → [ネットワーク] パネルに移動します。
[キャッシュを無効化] チェックボックスをオンにして初回ロードを確認します (ステータスは
200 OKになるはずです)。チェックボックスをオフにしてページを更新します:
リクエストが表示されない、または
from cacheと表示される場合。これは強力なキャッシュヒットを示します。304が表示される場合。これは条件付きキャッシュヒットを示します。
よくある質問
Nginx の構成を再読み込みしても、Cache-Control の変更が反映されないのはなぜですか?
これは通常、古い応答がキャッシュから提供されていたり、Nginx が新しい構成 (sudo nginx -s reload) を実際に再読み込みしていなかったり、あるいは別の location ブロックが優先されていたりすることが原因です。
この問題をトラブルシューティングするには、次の手順に従ってください:
サーバーのライブ応答を検証します。
curlを使用して、ブラウザ、 CDN 、またはプロキシのキャッシュをバイパスし、サーバーから直接送信されるヘッダーを確認します。curl -I http://your-urlこれにより、サーバーが実際にどの
Cache-Controlヘッダーを送信しているかが表示されます。Nginx 構成が正常に再読み込みされたことを確認します。 変更を適用するには、
sudo nginx -s reloadを実行する必要があります。確認:
locationブロックの一致の優先順位。 Nginx は、特定の順序でlocationブロックを処理します。リクエストが、予期せずにより一般的なルールに一致する可能性があります。正規表現による一致 (~* \.(css|js)$のような) は、プレフィックスによる一致 (location /static/のような) よりも優先順位が高いことに注意してください。構成に正規表現ルールがある場合、/static/app.jsへのリクエストがそのルールによって誤って処理される可能性があります。
静的アセットのルールに一致する動的な API エンドポイントが Nginx によってキャッシュされるのを防ぐにはどうすればよいですか?
これは、~* \.js$ のような静的アセット用の広範な正規表現が、/api/user.js のような動的な API パスにも一致してしまう場合に発生します。
これを修正するには、location ルールをより具体的にしてください。
パスを制限する:
location ~* ^/static/.*\.(css|js)$/api/や\.php$などの動的インターフェイス用のlocationブロックは、一致の優先度を高くするか、明示的にキャッシュを除外するようにしてください。
ファイルの種類ごとに異なる Cache-Control ポリシーを、location ブロックの競合を発生させずに設定する正しい方法は何ですか?
複数の location ブロックを使用して異なるファイルタイプのキャッシュポリシーを設定すると、Nginx の location マッチング優先順位が原因で競合が発生する可能性があります。よりクリーンで堅牢なソリューションは、応答の Content-Type に基づいて map を使用してキャッシュロジックを定義することです。
解決策: ポリシーをマージします。map を使用して、コンテンツタイプに基づいてキャッシュを動的に設定できます:
# http ブロック内
map $sent_http_content_type $cache_control {
~^image/ "public, max-age=2592000";
text/css "public, max-age=2592000";
application/javascript "public, max-age=2592000";
default "no-cache";
}
# server ブロック内
add_header Cache-Control $cache_control always;