キャッシュさせないCloudFrontディストリビューションを設定してみた(CloudFormationテンプレート付)

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは植木和樹@上越妙高オフィスです。今回は題名通り「キャッシュしない」CloudFront設定を行ってみました。

CDN(Contents Delivery Network)であるCloudFrontにキャッシュさせないのって意味があるの?と思われるかもしれませんが、理由は色々あります。

  • 基本キャッシュしてほしくないけど、一部のパス(CSSとか画像とか)は同じドメインでキャッシュさせたい
  • LINEやTwitterでの告知するページだけキャッシュさせたいので、事前にCloudFrontは準備しておきたい
  • パス毎にオリジンを変えたい(L7ロード・バランシングしたい)
  • Amazon WAF使いたいけどキャッシュはしたくない(私の今回の目的です)

ネットで調べると同じ思いの方は結構いらっしゃるようですね。

一撃設定CloudFormation

キャッシュさせないCloudFrontを一発で作るCloudFormationテンプレートを作ったので、興味がある方はご利用ください。

キャッシュしないCloudFrontを設定する

AWSマネージメントコンソールにログインした状態で、上のボタンをクリックするとNoCachedCloudFrontという名前でCloudFormationスタックを作成する画面が開きます。パラメーターとしてOriginの入力が求められるので、オリジンサーバーのホスト名を入力してからスタックを作成してください。(10分くらいかかります)

設定の概要

広く知られている設定をまとめています。

  • Allowed HTTP Methodsをすべてに(GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE)
  • Forward HeadersをAllに
  • Object CachingでMinimum TTL, Maximum TTL, Default TTLをすべて0(秒)に
  • Forward CookiesをAllに
  • Forward Query StringsをYesに
  • Error Pagesで主要HTTP Error CodeのTTLを1(秒)に

検証

(検証1) Cookie(PHPSESSID)が有効なこと

PHPで作成したカウンターページです。ページをリロードする度にカウントアップすれば成功です。

test_cookie.php

<?php
session_start();
if (!isset($_SESSION['count'])) {
  $_SESSION['count'] = 0;
} else {
  $_SESSION['count']++;
}
echo $_SESSION['count'];
?>

(検証2) クエリーパラメータを通すこと、HTTPステータスコード 302(リダイレクト)がキャッシュされないこと

クリックするたびにファイルのロック/アンロックが切り替われば成功です。

test_302.php

<?php
function h($str) {
  echo htmlspecialchars($str);
}

$filename = "/tmp/mylock";
file_exists($filename) or touch($filename);
$state = file_get_contents ($filename);

if(isset($_GET["action"])){
  $state = ($state xor 1);
  file_put_contents($filename, $state);
  $redirect = $_SERVER['REQUEST_SCHEME']."://".$_SERVER['SERVER_NAME'].$_SERVER['PHP_SELF'];
  header("Location: $redirect", true, '302');
  exit;
}

$link = $_SERVER['PHP_SELF'];
$link .= '?action=';
$link .= $state ? 'unlock' : 'lock';
?>
<html>
<body>
State: <?php h($state ? "locked" : "unlocked") ?><br/>
<a href="<?php h($link) ?>">
<?php h($state ? "unlock" : "lock") ?>
</a>
</body>
</html>

(検証3) POSTされたページはキャッシュされないこと

test_post.php

テキストフィールドに名前を入力した名前が表示されれば成功です。毎回違う名前を入力してキャッシュされないことを確認してみてください。

<?php
function h($str) {
  echo htmlspecialchars($str);
}

$name = !empty($_POST["name"]) ? $_POST["name"] : "no-name";
?>
<html>
<body>
<form method="POST">
<input type="text" name="name">
<button type="submit">Send</button>
</form>
<?php h($name) ?>
</body>
</html>

検証足りないよ! キャッシュされちゃうよ! という方いらっしゃいましたらご指摘ください。

まとめ

Webシステムを利用される方は、まずは前段にCloudFrontを利用されることを検討した方が良いでしょう。リリースした後にCloudFrontを組み込むと、思いがけずキャッシュされたり、キャッシュ要否を制御しやすいパス構成になっていなかったりと苦労することが多いようです。最初にCloudFrontだけでも設定しておけば、一部のパスから徐々に導入もできますのでオススメです。

「AWSを使う時はまずCloudFront」ぜひご検討ください。

  • howanhowan

    いつも参考させてもらっています。
    test_cookie.phpについてですが、カウントが0のままのBehaviorに配置しても、カウントが上がっていくBehaviorに配置しても、CloudFront Popular Objects Reportから見たHits/Missesの値がいつもMissesに入ってしまいます。
    これはどう考えたらよいでしょうか?
    Behaviorの設定がおかしい/このphpはキャッシュできない/それ以外のいずれでしょうか?

  • 植木和樹

    カウントが上がっていくBehaiviorでMissesになるのは期待通りの挙動になります。
    カウントが0のままでMissesになっているのは
    ・Object CachingでMinimum TTL, Maximum TTL, Default TTLをすべて0(秒)になっている(のでキャッシュされずMissesになる)
    ・Forward CookiesをAllになっていない(Cookieが送られないのでカウントが加算されない)
    あたりの設定を見直してみてはいかがでしょうか?

    設定を見直してもまだ挙動がおかしいようなら
    ・CloudFrontのログを確認する
    ・バックエンド(Apache)のログを確認する
    ・test_cookie.phpに phpinfo() を出力してみてCookieが送られているか確認する
    ・curl -I http://example.com/test_cookie.php でHTTPレスポンスヘッダーを確認し “Cache-Control” や “Expires” の値を確認する
    あたりで調査してみるのが良いかと思います。

  • howanhowan

    ご返信ありがとうございます。

    Apacheログやブラウザの拡張機能などでリクエスト/レスポンスを確認したところ、以下サイトにあるとおりオリジン側のphp.iniのsession.cache_limiterの値がデフォルトのnocacheのままで、session_startしているため、Object Cachingにno cache,no storeが入っていることが原因だとわかりました(考えております)。
     # CloudFront側のObject CachingはUse Origin Cache Headersにしております。

    オリジンのphp.iniのsession.cache_limiterやtest_cookie.phpでsession_cache_limiterから値をpublicに変更したところ、カウントは0のままHitするようになりました。
     # なお、HTTPのStatusが304になってしまうのですが。。。

    ほかに検討すべきことなどありましたら、ご教示お願いいたします。

  • 植木和樹

    PHPの設定で直ったようで良かったです :)

    >  # なお、HttpのStatusが304になってしまうのですが。。。

    動作としては問題ありません。
    これはコンテンツが変更されていないとApacheに判断されたためです。
    304 Not Modified
    ◎HTTPステータスコード – Wikipedia
    https://ja.wikipedia.org/wiki/HTTP%E3%82%B9%E3%83%86%E3%83%BC%E3%82%BF%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89#3xx_Redirection_.E3.83.AA.E3.83.80.E3.82.A4.E3.83.AC.E3.82.AF.E3.82.B7.E3.83.A7.E3.83.B3

    一般的にはコンテンツが変更されていないためブラウザはローカルキャッシュを使います。これによりネットワークを流れるデータを削減する+キャッシュから読むのでページ表示も早くなるという効果があります。

  • howanhowan

    ご返信ありがとうございます。
    ステータスが304の件は問題無いとのこと、承知いたしました。
     # 正直、ちゃんとステータスと振る舞い自体がわかっていないので引き続き勉強いたします。。。

    相談に乗っていただきありがとうございました。
    また機会がありましたらよろしくお願いいたします。