Azure App Service on LinuxでWebサーバ/アプリを運用していて、コンテンツのキャッシュ期間などを設定したいと思ったことはないだろうか? Front Doorなど有料のクラウドサービスを追加することなく、App Service単体でキャッシュを制御するレスポンスヘッダを追加する方法を紹介する。
対象:Azure App Service on Linux
Azureの「App Service」でWebサイト/アプリを構築した場合、デフォルトではWebブラウザやキャッシュサーバ(リバースプロキシやロードバランサー)のキャッシュ機能を制御するためのレスポンスヘッダが付加されない。
しかし、クライアントでの性能を高めつつ、Webサーバ側の負荷を軽減するには、可能な限りキャッシュ期間を設定したいところだ。
Azureの場合、「Front Door」というリバースプロキシ/キャッシュサーバのサービスを使うと、キャッシュ制御のレスポンスヘッダを付加できる。しかし、それにはApp Serviceとは別に追加コストが必要になってしまう。
そこで本Tech TIPSでは、App Service内蔵のNGINXの設定を変更することで、コンテンツのキャッシュ期間などを設定する方法を紹介しよう。App Serviceの機能なので追加コストは不要だ。また、PHPなどでは面倒な画像などの静的ファイルに対する設定もNGINXなら可能だ。
App Service内蔵のNGINXの設定変更については、「【Azure】App ServiceのWebサーバ『NGINX』をカスタマイズする方法」を前提としているので、以下を読み進める前に参照していただきたい。また、「【Azure】App Service on LinuxでディレクトリごとにクライアントIP制限を実装する方法と注意点」も参考になるだろう。
NGINXでコンテンツのキャッシュ期限を設定するには、「expires」ディレクティブを用いる。
expires <キャッシュ期間(秒)>s;
expires <キャッシュ期間(分)>m;
expires <キャッシュ期間(時)>h;
expires <キャッシュ期間(日)>d;
expires <キャッシュ期間(週)>w;
expires <キャッシュ期間(年)>y;
App Serviceの場合、これを[nginx/sites-available/default]ファイルの「server」または「location」コンテキスト内に記述する。
例えば、キャッシュ期限をHTTPレスポンス生成の2週間後とするには、以下のように記述すればよい。
expires 2w;
するとレスポンスには、以下のヘッダが追加される。
Cache-Control: max-age=1209600 ← 1209600秒=2週間のキャッシュ期間
Date: Mon, 24 Mar 2025 01:58:24 GMT ← レスポンス生成時刻(デフォルトで出力)
Expires: Mon, 07 Apr 2025 01:58:24 GMT ← キャッシュ期限はレスポンス生成より2週間後
「Cache-Control」「Expires」は、ともにキャッシュを制御するためのレスポンスヘッダである。執筆時点で主に使われているのはCache-Controlヘッダの方で、これが指定されていると通常、Expiresヘッダは無視される。Cache-Controlヘッダに対応していない古いWebブラウザやキャッシュサーバでは、Expiresヘッダがキャッシュ制御に用いられる。
コンテンツによっては、常にオリジンサーバ(コンテンツを生成するサーバ。App Serviceでは内蔵のNGINXによるWebサーバ)から最新のコンテンツを提供したい、ということもよくある。その場合は、expiresディレクティブに「epoch」というパラメーターを指定する。
expires epoch;
するとCache-Control/Expiresレスポンスヘッダは以下のように出力される。
Cache-Control: no-cache ← 最新のコンテンツを利用させる
Expires: Thu, 01 Jan 1970 00:00:01 GMT ← 過去の日時=キャッシュ内のコンテンツを再利用させない
この場合、Webブラウザや経路途中のキャッシュサーバ(リバースプロキシやロードバランサーなど)は、キャッシュに対象コンテンツが保存されていた場合、それが最新かどうかをオリジンサーバに問い合わせて検証し、最新ならそれを再利用する。逆に古かったらオリジンサーバから取得し直す。つまり、キャッシュにある古いコンテンツは用いられず、常に最新版が利用されることになる。
少し注意が必要なのは、コンテンツをキャッシュに保存すること自体は禁止していない点だ。保存を禁止するには、Cache-Controlヘッダに「no-store」という値を指定する必要がある(詳細はすぐ後で説明)。
前述のように「expires epoch;」と指定しただけだと、Webブラウザやキャッシュサーバにコンテンツの保存を禁止させることはできない。
キャッシュへの保存も禁止したい場合は、以下のようにexpiresディレクティブと「add_header」ディレクティブを併用する。
expires epoch;
add_header Cache-Control "no-store";
するとCache-Control/Expiresヘッダは以下のように出力される。
Cache-Control: no-cache ← 無視される。「no-store」も指定されているため
Cache-Control: no-store ← コンテンツをキャッシュに保存することを禁止
Expires: Thu, 01 Jan 1970 00:00:01 GMT ← 過去の日時=キャッシュ内のコンテンツを再利用させない
Cache-Controlヘッダが複数指定されていた場合、それぞれの値を単一のCache-Controlヘッダにコンマ区切りで記述したのと同じに見なされる。そのため、上記の場合は「no-cache」「no-store」の両方を指定したことになる。ただし「no-cache」は「no-store」に含まれるため、「no-store」のみ指定したのと同じ、つまりキャッシュ保存禁止になる。
認証を伴うサイトで、ユーザーごとに保護すべき(漏えいから守るべき)コンテンツについては、経路途中のキャッシュサーバがキャッシュに保存するのを禁止して、不特定多数のユーザー間で共有されないようにする必要がある。それには、Cache-Controlヘッダに「private」という値を付ける。
expires 2w; # 2週間のキャッシュ期間
add_header Cache-Control "private"; # キャッシュサーバでは保存禁止
NGINXの設定ファイルで上記のように記述すると、対象コンテンツのレスポンスには以下のようなヘッダが付加される。
Cache-Control: max-age=1209600 ← 1209600秒=2週間のキャッシュ期間
Cache-Control: private ← キャッシュサーバでは保存禁止
Date: Mon, 24 Mar 2025 02:04:16 GMT ← レスポンス生成時刻
Expires: Mon, 07 Apr 2025 02:04:16 GMT ← キャッシュ期限は2週間後
この場合、Webブラウザのローカルキャッシュでは2週間、コンテンツ(レスポンス)の再利用が可能な一方で、キャッシュサーバでは保存が禁止され、再利用もできない。
Tech TIPS「【Azure】App Service on LinuxにBASIC認証を実装する方法と注意点」で説明している方法でBASIC認証を有効にしているコンテンツは通常、キャッシュサーバに保存されない(Webブラウザのローカルキャッシュには保存される)。
しかし、画像やスタイルシート、JavaScriptなどユーザーごとに内容が変わることがなく、個人情報も含まれないコンテンツについては、キャッシュサーバでキャッシュに保存してもよい。それならばキャッシュにヒットするようにして性能を高めたいところだ。
そのような場合は、Cache-Controlヘッダに「public」という値を付ける。
expires 2w; # 2週間のキャッシュ期間
add_header Cache-Control "public"; # キャッシュサーバに保存可能
NGINXの設定ファイルで上記のように記述すると、対象コンテンツのレスポンスには以下のようなヘッダが付加される。
Cache-Control: max-age=1209600 ← 1209600秒=2週間のキャッシュ期間
Cache-Control: public ← キャッシュサーバで保存可能
Date: Mon, 24 Mar 2025 02:04:16 GMT ← レスポンス生成時刻
Expires: Mon, 07 Apr 2025 02:04:16 GMT ← キャッシュ期限は2週間後
この場合、Webブラウザでもキャッシュサーバでも2週間、コンテンツ(レスポンス)の再利用が可能になる。
デフォルトで何らかのCache-Control/Expiresヘッダを出力しているサイトでは、コンテンツによって、これらのヘッダをNGINX側で付けてほしくない場合もあるだろう。
そのような時には、対象のlocationコンテキスト内で「expires off;」と記述すればよい。
server {
<前略>
# 以下のキャッシュ期限の設定は、このserverコンテキスト全体で追加(継承)される
expires 1w;
# [/dir1]ディレクトリ以下に限定
location ~ ^/dir1/ {
# serverコンテキストで設定されたCache-Control/Expiresヘッダの出力を取り消す
expires off;
# 必要なら、ここにその他のディレクティブを記述
}
<後略>
}
上記の場合、NGINXは[/dir1]ディレクトリ以下のコンテンツをリクエストされたとき、Cache-Control/Expiresヘッダを付けないでレスポンスを返す(その他のディレクトリでは付ける)。これにより、例えば[/dir1]以下にあるPHPなどのプログラムコード側で、最適な値を設定したCache-Control/Expiresヘッダを出力する、といったことが可能になる。
■関連リンク
Copyright© Digital Advantage Corp. All Rights Reserved.
Windows Server Insider 記事ランキング