HTTPS 通信のみ許可しているALB経由で、EC2上のWordPressにアクセスしたら、表示崩れした話。

記事タイトルとURLをコピーする

この記事は約6分で読めます。

初めに

皆さん、こんにちは。 24年度新卒人事部付け改め、サーバーワークスCS部CS2課の山﨑です。

振り返ればあっという間だった、1年間の新卒研修を終え無事配属先が決まりました。

今回は、新卒研修の集大成ともいえる模擬案件で、躓いたことについて知見を残すべくブログにしようと思います。

タイトルにもある通り、HTTPS 通信のみ許可している ALB 経由で、EC2 上の WordPress にアクセスしたところ、表示が崩れてしまい、それを直すのにとても時間がかかってしまいました。 今回はそのトラブルシューティングについての記事になります。
詳しい状況については、次項でまとめております。

前提(構成図)

【画像1】模擬案件で作成した構成図

別々のプライベートサブネットに構築した EC2 インスタンスと RDS を紐づけて、WordPress でwebサイトをホストします。 EC2 インスタンスはマルチ AZ 配置ではありませんが、 ALB 経由でのアクセスのみを許可するセキュリティグループを付けております。

起こったこと(表示崩れ)

ほとんどのリソースを AWS 環境上にお客様環境に構築し、EC2 インスタンス内に PHP と WordPress をインストール。 WordPress の Config ファイルに RDS のエンドポイント等を設定し、いざブラウザ上で WordPress にアクセスしたところ、画像のように表示崩れが起こってしまいました。

【画像2】WordPress 表示崩れ

分析

本番環境に構築する前に、別環境で検証していたので、まずは、その比較から行いました。

と、言うのも、検証環境では、以下のように成功しておりました。

【画像3】WordPress ログイン画面

大きく違っている点が一つありました。 それは、本番環境では ALB に AWS Certificate Manager (ACM) 証明書を付与し、クライアントから ALB に HTTPS 通信のみだけのアクセスを許可している一方で、 検証環境では、ACM 証明書を ALB に付与せず、クライアントから ALB まで HTTP 通信 でアクセスしておりました。

【画像4】HTTP 通信で WordPress にアクセス

「検証用アカウントでちゃんと検証していないじゃん!」というご指摘はごもっともです。。 大いに反省しております。

解決した方法

結論から述べると、WordPress の Config ファイルに以下の情報を書き加えることで表示崩れが治りました。

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

上記は、プロキシサーバーやロードバランサーを経由している場合に、リクエストが HTTPS で行われたかどうかを判定して、適切に処理を行うために使用されます。 次項にて詳しくこのコードが必要である理由をまとめたいと思います。

解説

今回表示崩れが起こった理由

一言でまとめると、

ホストした web サイトは、混在コンテンツとして、セキュリティ上に問題があり、ブラウザ上で CSS が読み込まれなくなり、表示崩れが発生してしまいました。

混在コンテンツとは

混在コンテンツ(Mixed Content)とは、ウェブページが HTTPS で提供されているにもかかわらず、一部のリソース(例えば、画像、動画、スタイルシート、スクリプトなど)が HTTP を通じて読み込まれている状態を指します。

本事案の場合【画像5】のように、クライアントから ALB までは、HTTPS 通信でアクセスし、VPC 内の ALB から web サーバーまでの通信が HTTP 通信となっていたため、混在コンテンツととして判断されブラウザ上ではじかれてしまったものと思われます。

【画像5】

コードについて

再度の説明になりますが、以下のコードを WordPress の Config ファイルに追記することでこの問題は解決されました。 追記することで、ALB と web サーバー間の通信が HTTP 通信であったとしても、 HTTPS 通信と認識させることができる力技になります。

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

上記のコードを解説します。

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])

クライアントとロードバランサーやプロキシ間の接続プロトコル( HTTP もしくは HTTPS )が存在するかどうかを確認しています。

&&

PHP における論理 AND 演算子です。 二つの条件が両方とも真(True)である場合にのみ、全体の条件を真と評価します。

$_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'

クライアントからロードバランサーやプロキシへの接続が HTTPS であったかどうかを確認

$_SERVER['HTTPS'] = 'on';

上記の条件が満たされる場合、すなわち、HTTP_X_FORWARDED_PROTOがセットされていて、値が https である場合、$_SERVER['HTTPS']'on'に設定しています。

このコードにより、ロードバランサーから web サーバーまでの通信が HTTPS 通信であると認識するようになります。

学んだこと

読み込まれるページが HTTPS プロトコルで読み込まれるかどうかを確認する WordPress の関数をis_ssl()関数といいます。

そして、この関数の性質によって、今回のような事案が発生してしまいました。

ロードバランサーが介在する環境では、SSL/TLS の終端(SSL Termination)をロードバランサーで行い、バックエンドのアプリケーションサーバーには HTTP でリクエストを送信することが一般的です。

このような設定では、直接的にアプリケーションサーバーに届くリクエストは HTTP となります。そのため、WordPressの is_ssl() 関数は通常のサーバー環境であれば正しくHTTPS 接続を判別できますが、ロードバランサーが介在していると、正しく HTTPS を検出できない場合があります。

その結果、既述したように混在コンテンツとして読み込まれ表示崩れが発生してしまうことがわかりました。

つまり、混在コンテンツとして認識されてしまったことが、本事案の原因であります。 そのため、検証用アカウントで綺麗に表示されたのは、 ALB までの通信と ALB からの通信が HTTP 通信に統一されていたため表示崩れが発生しなかったと言えます。

解決策としては、今回のように Config ファイルを編集するほかに、ロードバランサーから web サーバーまでの通信を HTTPS 通信にすることも解決策の一つといえるでしょう。

最後に

この記事が今後 AWS クラウド上に WordPress で web サイトをホストする人の出助けになることを願います。

最後まで読んでいただきありがとうございました。