nginx+W3 Total Cache+gzipでのVaryヘッダー嵌りどころメモ【WordPress・Brotli】
これまた、需要の少ない情報になるわけですが、自分用メモ。
nginx + PHP-FPM + WordPress + W3 Total Cache(以下、W3TC)環境下で、W3TC における gzip・Brotli の圧縮設定と Vary ヘッダ制御のベストプラクティス(言い過ぎ)について考察。
さぞかし分かりにくい題材であろうから、見出しのスクショ絡みの設定だよ、とだけ。ここまで聞いただけでピンと来る人向けの記事。
多分、検索でこの記事に辿りつけた人は、W3TC で SP・PC 版の HTML を出し分けまではしたものの、HTTP ヘッダに吐かれる Vary: Accept-Encoding;
をどうにかして Vary: Accept-Encoding,User-Agent;
に書き換えたいのであろうから、その前提にて。
答えの前に、前提知識を少し補足しておく。
W3TC でブラウザーキャッシュの gzip・Brotli 圧縮を有効化した場合、WordPress ルート上の nginx.conf には gzip on;
や brotli on;
など圧縮絡みの記述が出力される。
つまり、この構成において W3TC は nginx の gzip・Brotli 圧縮機能を当てにしており、出力される Vary: Accept-Encoding;
ヘッダは W3TC 由来の設定に基づき nginx が吐いている構図となる。
ここで重要なのは、当該ヘッダが PHP でなく直接的には nginx により出力されているヘッダである、という点。
だから、WordPress の functions.php で wp_headers
や send_headers
といったフィルターフックを駆使して
$headers['Vary'] = 'Accept-Encoding,User-Agent';
unset($headers['Vary']);
header('Vary: User-Agent');
と頑張ったところで、一生 HTTP ヘッダは編集できない。(この構成において低位レイヤーで Vary ヘッダが出力されていると、PHP から Vary ヘッダは触れない )
さらに悪いことに、nginx で gzip_vary on;
を指定すると、HTTPヘッダに Vary: Accept-Encoding;
が強制出力される仕様も、今回のような PHP での Vary ヘッダ制御問題に絡んでくる。
答えの1つにはなるのだけども、このケースでヘッダを上書きするには、nginx 拡張モジュール「headers-more-nginx-module」の more_set_headers
ディレクティブを使うこととなる。
(※余談にはなるが、nginx の gzip 関連ヘッダ周りの仕様に関しては、誤った設定をされないよう保守的になっているのかもしれない。Content-Encoding
ヘッダと圧縮済みペイロードを巡っては、ミドルボックスで酷い扱いを受けた歴史的経緯があるので。)
nginx で more_set_headers
が使える環境なら Vary ヘッダをお目当てどおりに書き換える手もあるが、そうでなければ、こうしてめでたく nginx でも PHP でも編集できない Vary ヘッダが出来上がるワケ。
で、ココからがようやく解決策。オプションは2つある。
1つ目は、Vary ヘッダを重複出力する方法。仕様上、Vary
ヘッダは複数吐き出しても問題ない(※カンマで繋いで正しい内容になるなら)ので、W3TC(nginx)が勝手に吐く Vary: Accept-Encoding;
はそのままに、nginx の追加設定で Vary: User-Agent;
を常時、あるいは必要な条件のときだけ出力する。
個人的にはこれが最もプレーンな解決策と思う。
単純に add_header
で追加出力するだけだと Vary: User-Agent;
が重複するなどして見栄えが悪くなるケースがある。でも、先の more_set_headers
で更新したり、W3TC の変数で分岐すれば体裁はそこそこ整えられる。
そして2つ目は、gzip 圧縮を nginx 側のみで完結し、W3TC の gzip・brotli 圧縮設定はすべて OFF にする方法。ちゃんと nginx 側で gzip_vary off;
にして Vary ヘッダが一切出力されない状態なら WordPress・PHP 側からでも Vary ヘッダを出力できる。もちろん、その状態で「1」同様に nginx 側から Vary ヘッダを出力する手もある。
どうしても WordPress 側だけで完結して Vary ヘッダを制御したいならこういう形態も取れなくもない。
ただしこの方法には欠点があり、恐らくはサーバーレスポンスへの悪影響がある。というのも、W3TC のページキャッシュや Minify が gzip・brotli 圧縮済みリソースもキャッシュしているからだ。
いずれの場合も、W3TC のユーザーエージェントグループで指定したテーマで Vary:
,Accept-Encoding
User-Agent,Cookie;
というド派手なヘッダが出力されるのは気になるかもですが。
さて、あまりに長くなったので、ここまで読んでいただいた方向けにお土産を置いておきましょう。
実は、W3TC のブラウザキャッシュ機能で brotli 圧縮設定を ON にするには、PHP Extension である php-ext-brotli が有効化されている必要があります。というあたりで勘の良いエンジニアならお気づきになるかと思いますが、W3TC はそれ自身で圧縮済みペイロードをキャッシュできるのです。
加えてドキュメントルート直下の nginx.conf に適切な HTTP 圧縮設定を自動出力までしてくれる。ということは、もう、HTTP 圧縮絡みの最適な構成・設定は自ずと決まってこようというものです。
若干書きすぎた感も無きにしもあらずですが、以上、何かしらの気付きが得られるキッカケになれば幸いです。