すべてのプロダクト
Search
ドキュメントセンター

CDN:Nginx HTTP キャッシュポリシー

最終更新日:Sep 04, 2026

Nginx サーバーに HTTP キャッシュポリシーを設定することで、ブラウザや CDN などの中間プロキシに対し、画像、CSS、JS ファイルなどの静的アセットをキャッシュするよう指示できます。有効期間内であれば、キャッシュされたアセットはローカルのコピーから直接読み込まれるため、サーバーへのリクエストが不要になります。これにより、Web サイトの読み込み速度が向上し、サーバーの帯域幅が削減され、サーバー負荷が軽減されます。

一般的なキャッシュポリシーの例

このセクションでは、Nginx の設定ファイルに直接適用できる一般的なキャッシュ設定を紹介します。すべての例では、add_header ... always; ディレクティブを使用して、304 Not Modified レスポンスステータスコードを含むすべてのレスポンスにキャッシュヘッダーを追加します。

ユースケース 1:静的アセットの長期間キャッシュ

# 静的アセットの長期間キャッシュを設定
# - コンテンツハッシュを含むファイル名 (例:main.a1b2c3d4.js) の場合、'immutable' を指定した 1 年間のキャッシュを推奨します。
location ~* "\.[a-f0-9]{8,}\.(css|js|png|jpg|jpeg|gif|svg|webp|ico|woff|woff2)$" {
    # ビルドツールによって生成されたハッシュを持つアセット:1 年間キャッシュし、ブラウザに再検証しないよう指示します。
    add_header Cache-Control "public, max-age=31536000, 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>:キャッシュの生存期間 (TTL) を秒単位で設定します。

  • immutable:アセットのコンテンツがキャッシュされている間は変更されないことをブラウザに伝えます。ファイル名にコンテンツハッシュが含まれるファイルに最適です。

デプロイと検証

  1. 設定の編集
    サイトの server ブロックに location ブロックを追加します。設定ファイルは通常、/etc/nginx/conf.d/ または /etc/nginx/sites-enabled/ にあります。

  2. 設定のリロード

    sudo nginx -t && sudo nginx -s reload
  3. レスポンスヘッダーの検証
    curl を使用してキャッシュヘッダーを確認します。この方法では、ブラウザのキャッシュをバイパスできます。

    curl -I http://your-domain.com/path/to/file.js

    レスポンスには、Cache-Control: public, max-age=31536000 のような期待されるヘッダーが含まれているはずです。

  4. 304 の動作を検証 (no-cache または ETag ベースのポリシーの場合)
    検証ヘッダーを使用してテストします:

    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 レスポンスが期待されます
  5. ブラウザでの検証

    1. デベロッパー ツールを開き、[ネットワーク] パネルに移動します。

    2. 初回ロードを確認するには、[キャッシュを無効にする] チェックボックスを選択します。ステータスは 200 OK になります。

    3. チェックボックスの選択を解除してページを更新します:

      1. リクエストが行われない、または (from cache) と表示される → 強力なキャッシュヒット

      2. 304 が返される → 条件付きキャッシュヒット

よくある質問

変更が反映されない

原因:

  1. sudo nginx -s reload コマンドが実行されていない。

  2. ブラウザ、CDN、またはプロキシサーバーが古いレスポンスを提供している。

  3. location ブロックのマッチング優先順位が正しくない。

解決策:

  1. curl -I http://your-url を使用して、サーバーから直接レスポンスヘッダーを確認します。

  2. location ブロックの順序を確認します。正規表現マッチ (~* \.(css|js)$ など) は、プレフィックスマッチ (/static/ など) よりも優先されます。このため、リクエストが誤ったルールで処理されることがあります。

動的コンテンツが誤ってキャッシュされる

原因:静的アセットの正規表現が広すぎる (例:~* \.js$ が /api/user.js にマッチする)。

解決策:

  1. パスを制限する:location ~* ^/static/.*\.(css|js)$

  2. /api/ や \.php$ などの動的インターフェースに一致する location が優先的に一致するか、キャッシュから明示的に除外されていることを確認してください。

キャッシュポリシーの競合

  • 原因:複数の location ブロックが同じリクエストに一致するが、最初の 1 つしか有効にならない。

  • 解決策: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;