厄介な「常にMISS」問題
proxy_cache_pathを設定し、ゾーンのマッピングも完了しました。curlコマンドを実行して5msという超高速なレスポンスを期待したものの、ヘッダーには頑なにMISSと表示されます。10回リロードしても、ディスク上のキャッシュディレクトリは空のままで、バックエンドのTTFB(Time to First Byte)は200ms以上の低速な状態が続いています。
X-Cache-Status: MISS
これは、Nginxがデフォルトで「安全」を優先するように設計されているためです。ユーザーのプライベートなセッションデータを誤って他の訪問者に提供してしまうくらいなら、サイトの速度を落とす方を選択するのです。
根本原因:Nginxの過度な警戒
NginxはHTTPキャッシュ標準に厳格に従います。バックエンド(Node.js、Laravel、Djangoなど)が固有のセッションを示唆するヘッダーを送信した場合、Nginxはそのレスポンスの保存を拒否します。主な原因は次の3つです:
- Set-Cookie: アプリが
PHPSESSIDやconnect.sidを送信すると、Nginxはそのページがパーソナライズされていると判断します。 - Authorization: リクエストにBearerトークンやBasic認証が含まれている場合、Nginxはそのレスポンスをプライベートなものとして扱います。
- Cache-Control:
no-cache、no-store、privateなどのヘッダーは、明示的にNginxにキャッシュしないよう指示します。
Nginxはこれらを検出すると、機密データの漏洩を防ぐためにデフォルトでMISSを選択します。これを修正するには、どのヘッダーを無視するかをNginxに明示的に指示する必要があります。
修正方法:デフォルトのヘッダーロジックを上書きする
ここで主要なツールとなるのがproxy_ignore_headersディレクティブです。これにより、バックエンドからの特定の指示を無視してコンテンツをキャッシュするようにNginxに伝えます。
ステップ1:Nginx設定の更新
サイトの設定ファイル(通常は /etc/nginx/sites-available/ 内)を開き、locationブロックを修正します。以下の行を追加することで、Cookieが存在する場合でもNginxにキャッシュを強制させることができます:
location / {
proxy_pass http://backend_upstream;
proxy_cache my_cache_zone;
# バックエンドからのこれらのヘッダーを無視するようNginxに指示
proxy_ignore_headers Set-Cookie Cache-Control Expires;
# セッションの混入を防ぐため、エンドユーザーからSet-Cookieヘッダーを隠す
proxy_hide_header Set-Cookie;
# 200レスポンスに成功したものを60分間キャッシュする
proxy_cache_valid 200 60m;
# デバッグ用ヘッダー
add_header X-Cache-Status $upstream_cache_status;
}
ステップ2:認証済みリクエストの処理
APIがAuthorizationヘッダーを使用しているものの、誰に対しても同じデータ(公開されている商品リストなど)を返す場合、Nginxは依然としてキャッシュをスキップします。これを回避するには、proxy_cache_allow_authenticationを有効にします。
location /api/public {
proxy_cache my_cache_zone;
proxy_cache_allow_authentication on;
proxy_ignore_headers Cache-Control;
proxy_cache_valid 200 10m;
}
ステップ3:テストとリロード
変更を適用する前に、構文を確認してください。セミコロンが1つ抜けているだけで、Webサーバーがクラッシュする可能性があります。
sudo nginx -t
sudo systemctl reload nginx
検証:HITの確認
curlを使用してヘッダーを検査します。最初の回はNginxがデータを取得してディスクに書き込むため、おそらくMISSになります。2回目のリクエストはHITになるはずです。
curl -I https://yourdomain.com/api/data
以下の特定の行を探してください:
HTTP/1.1 200 OK
...
X-Cache-Status: HIT
...
依然としてMISSが表示される場合は、proxy_cache_pathディレクトリがwww-dataまたはnginxユーザーによって書き込み可能であることを確認してください。ls -ld /var/cache/nginxで確認できます。
安全第一:ベストプラクティス
キャッシュを強制することは強力ですが、リスクも伴います。誤った相手にプライベートなデータを提供しないよう、以下のルールに従ってください:
- 機密性の高いパスを分離する:
/admin、/checkout、/settingsなどでは決してproxy_ignore_headers Set-Cookieを使用しないでください。 - キャッシュバイパスを使用する:
proxy_cache_bypass $cookie_nocacheを実装します。これにより、ゲストにはキャッシュされたコンテンツを提供しつつ、ログインユーザーには最新のパーソナライズされたデータを提供できます。 - Cookieを削除する: Cookieを無視する場合は、必ず
proxy_hide_header Set-Cookieを使用して、クライアントがキャッシュからの古いセッションIDを保存しないようにしてください。

