Amazon CloudFront + ALB の WordPress 環境で起きたリダイレクトループの原因と対処について

AWS

2022.6.6

Topics

はじめに

この記事は AWS上に WordPress を構築したところ、リダイレクトループ ( ERR_TOO_MANY_REDIRECTS ) に遭遇したため、その時調査してわかった原因と解決方法についてご紹介していきます。

要点まとめ

WordPress ではクライアントのプロトコルを判別していますが、判別用のヘッダーがないため HTTPS を HTTPS へとリダイレクトしようとしてループが起きています。

WordPress の wp-config.php に以下のような設定をすることで解決します。

 /* Add any custom values between this line and the "stop editing" line. */

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] = 'on';
} elseif (isset( $_SERVER['HTTP_CLOUDFRONT_FORWARDED_PROTO']) && $_SERVER['HTTP_CLOUDFRONT_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] ='on';
}

 /* That's all, stop editing! Happy publishing. */

 

更に原因の解説や恒久的な解決方法もご紹介していきます!

今回のアーキテクチャ

まず、構成について紹介します。
下の図をご覧ください。

CloudFront, Application ロードバランサ, EC2があるWordPress環境です

図1. WordPress 環境構成図

とてもシンプルな構成で、代表的な構成パターンだと思います。
こちらの構成でいったい何が起きるのか見ていきましょう。

WordPress の動作

 

リダイレクトループの様子

図2. リダイレクトループ発生の様子

閲覧すら不可能な状態です。
また、今回の場合 「 ERR_TOO_MANY_REDIRECTS 」 というエラーは特別な設定なく発生します。

リダイレクトループは設定ミスによって起きるケースがほとんどのため、原因究明まで時間を要してしまうような事象です。
また、CloudFront や Chrome のキャッシュを削除しても状況は変わりません…。

CloudFront では 「 Redirect HTTP to HTTPS 」 を有効にしていますが、この問題に関係あるのでしょうか。

続いて調査してわかった原因をご紹介します。

原因について

リダイレクトループが発生するまで原因は 2つ あるので、それぞれ確認していきます。

サービス間でのプロトコルの違い

CloudFront 上ではプロトコルをリダイレクトしているので、一度各サービス間でプロトコルがどのような様子になっているのか確認してみます。

サービスで使用されているプロトコルの様子です

図3. 各サービス間のプロトコル

図3 の通り、CloudFront から ユーザ へは 「 HTTPS 」 を使用してコンテンツが配信されますが、CloudFront から EC2 ( WordPress ) へは 「 HTTP 」 を使用していることが見てわかると思います。

WordPress 上での処理

WordPressでアドレスを設定する画面

図4. WordPress サイトアドレスの設定項目

WordPress では 図4 の通り設定項目があり、ここで 「 http://example.jp 」等の指定をしてサイトを立ち上げることができます。

「WordPress アドレス (URL)」設定は、WordPress のコアファイルを配置する場所のアドレスです。

「サイトアドレス (URL)」設定は、WordPress サイトに読者がアクセスするために使うアドレスです。

WordPress – サイト URL の変更

ここの処理で WordPress は、暗黙的にプロトコルが「 HTTP 」 か 「 HTTPS 」なのかを PHP で処理して判断しています。
ここの処理について とても詳しく ご説明されている記事があるので、ご興味あれば下の記事をご覧ください。

PHP の $_SERVER[‘HTTPS’] が on になる流れ 〜Apache mod_php 編〜

通常 WordPress は 「 X-Forwarded-Proto 」というヘッダーを見てその判別をしています。
しかし、CloudFront を使用した環境では、「 X-Forwarded-Proto 」を削除後に「 CloudFront_Forwarded_Proto 」というヘッダーを使用するため、結果的にプロトコルを判別できなくなってしまいます。

X-Forwarded-Proto CloudFront はヘッダーを削除します。

HTTP リクエストヘッダーと CloudFront の動作 (カスタムオリジンおよび Amazon S3 オリジン)

そのため、ユーザには 「 HTTPS 」 でコンテンツが届けられていても、WordPress では CloudFront からの 「 HTTP 」 がユーザのプロトコルと勘違いしてしまい、WordPress が 「 HTTPS 」 にリダイレクトすることで、ループが発生してしまいます。

原因まとめ

リダイレクトループ発生までの流れをまとめると、下のようになっています。

  1. ユーザが HTTP でウェブサイトにアクセスし、CloudFront によって HTTPS にリダイレクトされる
  2.  ユーザが HTTPS でウェブサイトに再アクセス後、WordPress は CloudFront 及び ALB からの 「 HTTP 」 を 「HTTPS」 へリダイレクトする
  3. 2 と同じように WordPress は CloudFront 及び ALB からの 「 HTTP 」 を 「 HTTPS 」 へリダイレクトする
  4.  リダイレクトループになり、ユーザにエラー画面が表示される

リダイレクトループが発生する原理はこうなっていました。
CloudFront の 「 Redirect HTTP to HTTPS 」 は関係ないとはいえないですが、HTTPS でアクセスするとリダイレクトループになるので状況は変わらなそうです。

想定通りに動かないと、どこか間違えたと不安になってしまうので嫌ですね…。
それでは、続いてこの問題を解決するための対処を紹介していきます。

対処 ( 解決法 )

次に挙げるような対処をすることで、通常通り動作するようになります。

  • 【 WordPress 】
    1. 独自ヘッダーに対応させる
    2. CloudFront に対応したSSL化プラグインを導入する

まずリダイレクトループをしないように、設定を投入していきます。
その後、SSL化プラグインを使用して HTTPS が正常に動作するようにします。

  • 【 Apache 】
    1. ヘッダーを基に HTTPS にするよう設定

Apache については設定せずとも動作するようになりますが、
もし改善されない場合の選択肢として残しています。

WordPress への対処

ステップ 1 – 独自ヘッダーに対応させる

こちらの設定は WordPress が入っているディレクトリで行います。
変更を加えるので、任意でバックアップを作成してから作業を進めます。

  • wp-config.php へと設定を投入する

まず、WordPress環境内にある 「 wp-config.php 」 を直接変更していきます。
お好みのテキストエディタで開いてください。

実行例)


vi /var/www/wordpress/wp-config.php

開いて一番下辺りに次のような記述があると思います。

【日本語】

/* カスタム値は、この行と「編集が必要なのはここまでです」の行の間に追加してください。 */

/* 編集が必要なのはここまでです ! WordPress でのパブリッシングをお楽しみください。 */

【英語】

/* Add any custom values between this line and the "stop editing" line. */

/* That's all, stop editing! Happy publishing. */

このコメントの間に設定を入れます。

設定例は以下の通りです。

/* Add any custom values between this line and the "stop editing" line. */

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] = 'on';
} elseif (isset( $_SERVER['HTTP_CLOUDFRONT_FORWARDED_PROTO']) && $_SERVER['HTTP_CLOUDFRONT_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] ='on';
}

/* That's all, stop editing! Happy publishing. */

この設定によって ヘッダー から直接 WordPress がプロトコルを判断できるようになります。

$_SERVER につきましては下の公式ドキュメントをご覧ください。
php – $_SERVER

  • 動作確認

編集し終えたら保存して動作を確認してみましょう。

リダイレクトループが直っているはずですが、ここでまだ何も変わらなければ
一度下のコマンドを使用してリロードすると変化することがあります。

systemctl reload php-fpm.service 
systemctl reload php74-php-fpm.service

無事動作すれば問題ないので、次に進みます。

ステップ 2 – CloudFront に対応した SSL化

SSL化については WordPress 管理画面から行います。
表示崩れやリダイレクトループが起きていればこちらで解決します。

  • プラグインの導入及び有効化

まず、WordPress 管理画面 サイドメニューから
プラグイン にカーソルを合わせ、新規追加をクリックします。

その後 プラグインを追加 という画面が出ると思うので、
SSL Insecure Content Fixer 」と検索します。

※ 表示崩れが起きている場合、下にスクロールすると検索欄があります。

プラグインを追加する画面で対処するためのプラグインが表示されたところ

図5. プラグインを追加 – SSL Insecure Content Fixer

対象のプラグインが表示されていると思うので、
プラグインをインストールし、完了次第 「有効化」 します。

有効化できたら、次に 「SSL Insecure Content Fixer」 の設定をしていきます。

下にスクロールしていくと、「 HTTPS の検出方法 」という項目があるので、
「 HTTP_CLOUDFRONT_FORWARDED_PROTO 」 をクリックして「変更を保存」します。

※クリックした時点で設定が適用されます

HTTPS検出方法にCloudFrontの独自ヘッダーを指定

図6. HTTPSの検出方法に CloudFront の独自ヘッダーを指定

適用後、正常にサイト閲覧ができれば一通りの対処は完了です。
更に Apache についても設定を加えていきます。

Apache への対処

ステップ1 – ヘッダーを基に HTTPS にするよう設定

こちらの作業は設定ファイルを追加し適用をします。

  • 設定ファイルの追加

お好みのテキストエディタで新しい設定ファイルを追加します。

実行例)


vi /etc/httpd/conf.d/wordpress-alb.conf

開いたまま、下の設定を追加して保存します。

SetEnvIf X-Forwarded-Proto https|HTTPS HTTPS=on
SetEnvIf HTTP_X-FORWARDED_PROTO https|HTTPS HTTPS=on
SetEnvIf HTTP_CLOUDFRONT_FORWARDED_PROTO https|HTTPS HTTPS=on

適用は下のコマンドを実行して完了です。

# シンタックスチェック
httpd -t
# ステータス確認
systemctl status httpd
# リロード & ステータス確認
systemctl reload httpd
systemctl status httpd

まとめ

以上で必要な処置は完了です!お疲れ様でした!
今回の事象はインストール後に起きるのでトラブルシューティングがなかなか大変だと思います。
WordPress はデータベースやディレクトリと紐づいていてかなり奥深いので、事象解決も含め今後関連する記事等出していきます!

とても勉強になった参考記事

今回リダイレクトループを扱いましたが、CloudFront と WordPress にはまだ問題があります。
以下の記事を参考にしていただくと解決するかもしれません。

事象解決系の記事

■ Apache

■ Nginx

PHP の処理について

公式情報

テックブログ新着情報のほか、AWSやGoogle Cloudに関するお役立ち情報を配信中!

Recommends

こちらもおすすめ

Special Topics

注目記事はこちら