menu
デジタルファームは、札幌・東京・大阪を拠点に、Web戦略の立案からシステム開発、ホームページ制作、SNS運用、運用改善まで一貫支援。Web活用によるビジネス課題解決をサポートします。

CloudFront 経由の WordPress で特定機能だけ 502 になる問題を解消した話

シェア
ツイート
シェア
ブックマーク
タイトルとURLをコピー
CloudFront 経由の WordPress で特定機能だけ 502 になる問題を解消した話

最終更新日:2026/08/08   公開日:2026/06/03

はじめに

CloudFront をフロントに置いた WordPress サイトで、ある管理画面の機能を使ったときだけ 502 Bad Gateway が発生する、という現象に遭遇しました。通常のページ閲覧や他の更新操作はまったく問題なく、特定の機能の保存処理を行ったときだけブラウザに以下のような 502 エラーページが表示されます。

502 Bad Gateway ERROR

The request could not be satisfied.

We can’t connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.

Generated by cloudfront (CloudFront) HTTP3 Server

Request ID: *********************

構成はシンプルで、CloudFront → EC2(nginx + httpd (php/wordpress)) という経路です。WAF は OFF、キャッシュは無効、オリジンリクエストポリシーは AllViewer という、比較的素直なセットアップです。

この記事では、この 502 の原因にたどり着くまでの調査手順と、最終的な対処をまとめます。

切り分けの前提

まず押さえておきたいのが、CloudFront の 502 には大きく2種類あるという点です。

  • CloudFront が自分で生成する 502
  • オリジンが返した 502 をそのまま中継したもの

今回、ウェブサーバーのアクセスログを見ると、該当リクエストに対してサーバー自身は POST を受け取り 302 を正常に返していました。これはタイムアウトや PHP が処理途中で落ちたというわけではなく、オリジンは正常に処理を行っているのに CloudFront が 502 を生成してユーザーに返している、という状況です。

今回は 302 レスポンス(=通常 body を持たないレスポンス)に対してエラーが発生しているため、その原因は 302 レスポンスのヘッダにほぼ絞ることができます。

調査

方針: オリジンの生レスポンスを CloudFront の手前で見る

ブラウザの開発者ツールで見えるのは、あくまで CloudFront が返したもの(=差し替え後の 502)です。原因を握っているオリジンの生の 302 レスポンスは、CloudFront を通さずに直接確認する必要があります。

今回はウェブアプリケーションが動作している EC2 の上で curl を使って該当機能を直接叩き、返ってくるレスポンスヘッダをそのまま観察することにしました。

ログイン Cookie と POST データをブラウザから取得する

今回問題になっていたのは WordPress の管理画面の機能なので、認証済みのセッションと、CSRF 対策の nonce を含む POST データを忠実に再現する必要があります。手で組み立てるのは現実的でないので、ブラウザの開発者ツールから実際のリクエスト情報を吸い出してファイルに落としました。

認証に必要な Cookie は次の2つです。

  • wordpress_logged_in_<hash> … ログイン中であることを示す本体。サイト全体で送られます。
  • wordpress_sec_<hash> … 管理画面(/wp-admin)向けの認証 Cookie。HTTPS(FORCE_SSL_ADMIN)環境ではこちらが検証されます。Secure 属性付きです。

<hash> はサイト URL から導出される値(COOKIEHASH)で、両者で共通です。それ以外の Cookie (wp-settings-* など)は認証には不要でした。

これらを Cookie: ヘッダ1行の形にして cookie.txt へ、POST 本体を post.txt へ保存します。curl-H @ファイル名–data-binary @ファイル名 でそれぞれファイルから読み込めます。–data-binary を使うのは、–data 系がファイル内の改行を勝手に除去してしまい、本体が変わってしまうのを避けるためです。

実行したコマンド

実際に使ったコマンドは次のようなものです(ドメインや認証情報は置き換えています)。

curl -X POST \
  -H "Host: example.com" \
  -v \
  -u USER:PASSWORD \
  -H @cookie.txt \
  --data-binary @post.txt \
  "http://localhost/wp-admin/<該当機能URL>" \
  >> output.txt 2>&1

 

ポイントは次のとおりです。

  • ローカル(オリジン)へ直接つなぎつつ、Host ヘッダには本番ドメインを指定しています。 これを指定しないと WordPress が別の挙動(siteurl へのリダイレクトなど)をしてしまうためです。 
  • -u USER:PASSWORD は、サイトに Basic 認証をかけている場合の指定です。不要なら省けます。
  • -v でリクエスト・レスポンス双方のヘッダを表示し、output.txt に丸ごと保存しています。

観察結果

返ってきたレスポンスを見て、原因が一目で分かりました。302 Found 自体は正常で、LocationSet-Cookie も問題ありません。ところが、X-QM-* というヘッダが大量に付与されていました。

< HTTP/1.1 302 Found
< Server: nginx
< Content-Length: 0
< Set-Cookie: PHPSESSID=...; path=/
< ...
< X-QM-overview-time-taken: 0.7817
< X-QM-overview-memory: 34.5 MB
< X-QM-php_errors-count: 20
< X-QM-php_errors-error-1: {"level":"deprecated","message":"..."}
< X-QM-php_errors-error-2: {"level":"deprecated","message":"...","stack":[...]}
< ...(中略:error-20 まで続く)...
< X-QM-php_errors-error-20: {"level":"deprecated","message":"...","stack":[...]}
< X-Redirect-By: WordPress
< Location: /wp-admin/<該当機能URL>

 

この X-QM-* は、プラグイン Query Monitor が付与しているヘッダです。今回の環境では PHP のバージョンに対してプラグイン群が古く、deprecated(非推奨)警告が大量に出ていました。Query Monitor はその警告を1件ずつ X-QM-php_errors-error-N という個別ヘッダに格納し、しかも各値にスタックトレースの JSON を丸ごと載せます。

結果として、1ヘッダあたり数百〜千バイト級のものが20本以上連なり、レスポンスのヘッダ部だけで非常に大きなサイズになっていました。ボディは空(Content-Length: 0)の 302 なのに、ヘッダだけが肥大化していたわけです。

「ある機能のときだけ」落ちるのもこれが理由です。 その処理の実行結果として deprecated 警告が大量に積み上がってレスポンスヘッダに書き込まれ、その場合にだけ X-QM-* が膨らんでいたためです。

原因: CloudFront のヘッダサイズ上限

CloudFront には、扱えるヘッダ部分のサイズに上限があります。これを超えると、ボディが空のリダイレクトであっても CloudFront はレスポンスを処理できず、自前で 502 を生成します。

重要なのは、この上限がリクエストだけでなくオリジンからのレスポンスにも適用されるという点です。CloudFront のクォータには、次の項目が明記されています。

Maximum length of a request or an origin response, including headers and query strings, but not including the body content (ヘッダーとクエリ文字列は含むが、本文のコンテンツは含まないリクエストやオリジンレスポンスの最大長) … 32,768 バイト (32KB)

出典 – https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html

つまり、ヘッダーとクエリ文字列の合計(本文は除く)が 32,768 バイトを超えると、リクエストでもオリジンレスポンスでもエラーになるわけです。今回はまさに、肥大化したレスポンスヘッダがこの上限を超えていました。X-QM-php_errors-error-N が20本以上あり、各値に JSON のスタックトレースが丸ごと入っていたことを思えば、32KB の超過は十分に起こり得ます。ボディは空(Content-Length: 0)でも、ボディは上限の対象外なので関係ありません。

また、このサイズ上限は引き上げ申請ができるクォータではないため、対処は「上限を上げる」ではなく「ヘッダを減らす」方向になります。

対処

1. Query Monitor を本番で無効化する

そもそも Query Monitor は管理者向けの開発支援機能プラグインなので、不要な状況では無効化するのが本来の姿です。これだけでヘッダ量は大幅に減ります。 ただし、こちらは Query Monitor が全く使えなくなってしまうので、単に無効化するだけでは問題の解決とはなりません。

2. アプリケーションを修正して deprecated 警告をなくす

本筋はこちらであり、プログラムの修正、error_reporting から E_DEPRECATED を外す、プラグインの更新などを行い deprecated 警告そのものを減らすのが最善の解決策です。 Query Monitor が拾う件数が減れば、X-QM-php_errors-error-N の数も連動して減ります。

3. nginx でデバッグヘッダを落とす(今回採用 / Amazon Linux 2023)

一方、修正や更新などには時間がかかるので、一時的にでもすぐに問題を解決したい場合があります。 その方法として nginx 側で X-QM-* ヘッダを削除することができるので、今回はこの手段を採用しました。 CloudFront に渡る前にこれらのヘッダを消せれば、ヘッダ合計サイズが一気に減り、CloudFront での 502 は解消します。

ワイルドカードでヘッダを削除するには headers_more モジュールが必要です。Amazon Linux 2023 では公式リポジトリからパッケージで導入できます。

# nginx 本体とバージョンの揃った headers-more モジュールを導入
sudo dnf install nginx-mod-headers-more

そのうえで、http または server ブロックに次の1行を追加します。more_clear_headers はワイルドカードに対応しているので、これだけで X-QM- から始まる全てのヘッダをまとめて削除できます。 

more_clear_headers 'X-QM-*';

 

設定を記載後、テストして実際に反映します。

sudo /usr/sbin/nginx -t
sudo systemctl reload nginx

 

nginx -tunknown directive “more_clear_headers” で失敗する場合は、モジュールがロードできていないサインなので load_module の指定を見直してください。

この設定の後、CloudFront 経由で再度アクセスを行うと、正常に動作することが確認できました。

まとめ

今回は CloudFront 経由のサイトで特定機能だけ 502 になるという理由が分かりにくい現象でしたが、整理すると次のような話でした。

  • ウェブサーバー自身は 302 を正常に返しており、502 は CloudFront が受け取ったレスポンスが制約違反(ヘッダ上限超過)のために生成したものだった。
  • 原因は、デバッグプラグイン Query Monitor が付与する X-QM-* ヘッダが、古い PHP 環境での大量の deprecated 警告によって肥大化し、CloudFront が扱えるレスポンスヘッダのサイズ上限を超えていたこと。
  • CloudFront のクォータでは「ヘッダーとクエリ文字列を含み本文を含まない、リクエストやオリジンレスポンスの最大長」が 32,768 バイト と定められており、レスポンスも明示的に対象。これを超えると 502 になる。
  • このサイズの緩和手段は提供されていないので、対処には「ヘッダの容量を減らす」必要がある。アプリの修正が本筋で、暫定対応としては Query Monitor の無効化、nginx の headers_more(Amazon Linux 2023 ではパッケージで導入可能)で該当ヘッダを削除することで対応できる。

今回対象となったシステムはバージョンアップのために別の環境のものをコピーして再現したものであり、これまで ALB 経由でのアクセスだったものを CloudFront 経由にしたことで初めてこの問題が表面化しました。 

CloudFront のこの仕様を知らなかったために今回の調査に時間がかかりましたが、この問題の具体例がトラブルシューティングの助けとなればと思います。