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圧縮済みリソースもキャッシュしているからだ。
ここまで読んでいただいて大変恐縮だが、先に挙げた2例はいずれもW3TCのユーザーエージェントグループで指定したテーマで Vary:
,Accept-Encoding
User-Agent,Cookie;
というド派手なヘッダが出力されてしまう。この記事をここまで読まれた方ならこれは気になる点かもしれない。
あまりに長くなったし、このままお引き取り願うのも気の毒なので、少しだけお土産を置いておこう。
実は、W3TCのブラウザキャッシュ設定でbrotli圧縮をONにするには、PHP Extensionであるphp-ext-brotliの有効化が必須となる。勘の良いエンジニアはここで気づかなければならない。そう。W3TCはそれ自身で圧縮済みペイロードをキャッシュできるのだ。
ここまでの話でむしろ頭に疑問符が湧き出して止まらないエンジニアは将来有望だ。ぜひ、ドキュメントルート直下のW3TCが書き出したnginx.confを覗いてみると良い。W3TCがHTTPペイロード圧縮に関する興味深い設定を記述しているからだ。
これらを俯瞰できるようになれば、もう、HTTP圧縮絡みの最適な構成・設定は自ずと決まってこようというもの。
若干書きすぎた感もあるが、以上、何かしらの気付きが得られれば幸いだ。
こんな記事も読んでみませんか?
- 【PHP・WordPress】HTTPヘッダの削除・追加に便利なheader_register_callback()関数
- W3 Total Cache+AMPプラグインでnginxが起動しない件を対処【WordPress】
- 【WordPress】W3TCが原因で文字化けする場合の対処
- nginx用のログローテートを手動で設定する(ログのreopenについて)
- 【WordPress+W3TC】「設定変更後のオブジェクトのキャッシュを防止」機能が付加するクエリストリングの仕様は?
- 【WordPress】HTTP/3環境で「Undefined array key "HTTP_HOST"」エラーが出る場合の対応