情報科学屋さんを目指す人のメモ

方法・手順・解説を書き残すブログ。私と同じことを繰り返さずに済むように。

Google Analyticsに古いページタイトルからのアクセスが多かった原因と対策(Cloudflare / Nginx / Apache / WordPress)

Apache (7) CloudFlare (4) Nginx (14) WordPress (77)

Google Analyticsのリアルタイム解析を見ていたところ、頻繁にページタイトルを更新していたページに対して、古いページタイトルでのアクセスが多数行われていることに気が付きました。

そのページは、同じ人が何度も確認するタイプのページであったため、もしかして、古いページがブラウザにキャッシュされてしまっており、もう一度開いた際に古いページをそのまま閲覧されてしまっているのではないか、と考え調査してみることにしました。

以前から、iPhone Safariでアクセスすると、リロードしても古いトップページが表示される、という話があったのですが、放置したままだったので、かなり怪しい感じがしました。

構成

現在このブログの構成は、まず最前面にCDN「Cloudflare」があり、その裏に、リバースプロキシとして「Nginx」、そしてそのさらに裏側に、「Apache」上で動く「WordPress」がありました。

ヘッダを確認してみる

WordPressからログアウトした状態で、実際にページにアクセスして、レスポンスヘッダを確認してみると、「Cache-Control: max-age=1209600」というヘッダが付けられていることが分かりました。

1209600秒でキャッシュがタイムアウトする設定なので、これはつまり14日間(2週間)のタイムアウト設定であることを意味します。

これでは、古いページが表示され続けても当然です

CloudFlareを疑う

さっぱり記憶にないので、まず最前面の、CloudflareのCache-Controlヘッダについての記述を探しました。

ここに、Cloudflare公式による、cacheの設定に関する記述がありました:「How Do I Tell Cloudflare What to Cache? – Cloudflare Support

この中に、ちょうど「Cache-Control」ヘッダの設定についてのデフォルトに関する記述があるのですが、1209600秒の原因となりそうな設定は全く見当たりませんでした。

ただし、その中に次の記述がありました。

The second way to alter what Cloudflare will cache is through caching headers sent from the origin. Cloudflare will respect these settings, but you can also override them by specifying an Edge Cache TTL. Here are the caching headers we consider:

If the Cache-Control header is set to "private", "no-store", "no-cache",  or "max-age=0", or if there is a cookie in the response, then Cloudflare will not cache the resource.
Otherwise, if the Cache-Control header is set to "public" and the "max-age" is greater than 0, or if the Expires headers are set any time in the future, we will cache the resource.
Note: As per RFC rules, "Cache-Control: max-age" trumps "Expires" headers. If we see both and they do not agree, max-age wins. 引用元

origin側から指定されたCache-Controlヘッダの設定値がCloudflareのキャッシュに影響を与えるようなので、そこからさらに、クライアント側にそのヘッダが送られているのかな、つまり、Cloudflareの裏側のNginxの設定を見た方が良さそう、となりました。

Nginxを疑う

そこでさらにNginxの自分で書いた設定に目を通してみたのですが、キャッシュ関連の設定で、2週間キャッシュするヘッダを生成しそうな設定は見当たりませんでした。

となると、さらに裏側のApacheや、WordPressのプラグインなどが原因として考えられました。

.htaccessを見てみると

そこでまず.htaccessを見てみると、気になる設定を発見してしまいました。

## BEGIN Expires Caching (Leverage Browser Caching) ##
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access 2 week"
ExpiresByType image/jpeg "access 2 week"
ExpiresByType image/gif "access 2 week"
ExpiresByType image/png "access 2 week"
ExpiresByType text/css "access 2 week"
ExpiresByType application/pdf "access 2 week"
ExpiresByType text/x-javascript "access 2 week"
ExpiresByType application/x-shockwave-flash "access 2 week"
ExpiresByType image/x-icon "access 2 week"
ExpiresDefault "access 2 week"
</IfModule>
## END Expires Caching (Leverage Browser Caching) ##

# END WP Performance Score Booster Settings

このあたりの記述、ひとまずもはや由来は思い出せなかったわけですが、明らかに「2 week」という記述が、いかにも関連していそうな雰囲気で、そして、「ExpiresDefault "access 2 week"」となっていました。これが原因のようです。

対策

かなり昔、Nginxを前面に立てる前に書いた設定が残ってしまっていたのか何なのか、背景は分かりませんが、ここで「access 2 week」となっていたのを、「access 1 seconds」と書き換えてみました(Apacheをしたことで再起動して反映)。

すると、クライアント側が受け取るCache-Controlヘッダはmax-age=1となり、無事、ブラウザにキャッシュされすぎる問題は回避できました。

ただ、これだけではCloudflare上に1秒間保持されてしまい、1秒以内に同じページに訪れた複数アクセスのうちの最初の1つ以外がCloudflareで止まってしまい、Nginxにまで届いてくれない、意図しない挙動になりかねないので、「access 0 seconds」と設定したところ、ちゃんとクライアント側には「Cache-Control: max-age=0」が届いてくれました。これなら大丈夫そうです。

ひとこと

GoogleのPageSpeedに、2週間以上のブラウザキャッシュを指定しろ、と指摘されて、まとめてそのあたりに設定したような記憶がぼんやり蘇ってきました。。。

コメント(0)

新しいコメントを投稿