AWS 上で構築した WordPress サイトを HTTPS 化するために Amazon CloudFront を導入する

本記事のゴール

本記事では、AWS 上で構築した WordPress サイトを HTTPS 化します。HTTPS 化の手順の中で、Amazon CloudFront の導入が必要になります。Amazon CloudFront (CloudFront) はそもそもコンテンツ配信ネットワークのサービスで、なぜ HTTPS 化にあたり必要になってくるか等、説明します。
WordPress on AWS に CloudFront を追加し HTTPS 対応

おそらく (AWS 上で構築していなくても) WordPress サイトの HTTPS 化はハマりどころが多いです。たとえば

  • なぜか 403 エラーになる
  • トップページにはアクセスできるが、他のページに遷移するとドメイン名がおかしくなる
  • 表示崩れを起こしている (明らかに CSS が正しく読み込めていない)
  • WordPress の管理画面にログインできない、ログインメニューが表示されなくなる
  • リダイレクトループを起こし、ERR_TOO_MANY_REDIRECTS エラーが起きる
  • 投稿や固定ページを編集する際のビジュアルエディター (ブロックエディター) が起動しない

などなど。一方で、これらの事象を回避するために、CloudFront のキャッシュを一律使わない設定を入れるとそれはそれでキャッシュの効果が活用できず (コストやサーバーのパフォーマンス的な観点で) もったいないので、本記事では、これらを回避しつつ CloudFront のキャッシュを活かせるよう設定していければと考えています。

なぜ HTTPS 化が必要なのか

まず、 SSL を活用して通信網を暗号化することに意味があります。すなわち、サイト訪問者とサイトとのやりとりが暗号化されることで、悪意のある第3者からの盗聴が困難になります。

さらに、SSL 証明書によって、ドメイン、サイトの実在がその証明書を発行する機関によって証明されます。そのため、サイト訪問者にとってある程度の安心を得ることができます。特に、Chrome では 2018 年 7 月にリリースされたバージョン 68 以降、すべての HTTP サイトに「Not Secure(セキュアでない)」と表示するよう変更されています (詳細はこちら)。

このように、HTTPS 化はサイト訪問者からの安心、信頼を勝ち取るための必要条件 (十分条件ではない!) になってきます。したがって、HTTPS 化が必要になってくる、というわけです。

AWS Certificate Manager (ACM) を使いたかった

これまで純粋 AWS でサイトを構築してきましたので、証明書の取得先も AWS の証明書発行サービス、 AWS Certificate Manager (ACM) を使いたいと思います。

ただし、ACM を使うとなると、Elastic Load Balancing (ELB) もしくは CloudFront の導入が必要になるのですが、現状 WordPress が動いているサーバーは 1 台なので ELB のようなロードバランサーは有用ではありません。そこでキャッシュも設定できる CloudFront を導入した、ということになります。

結果、ハマりまくりました。その原因のほとんどは、「WordPress がデフォルトでは HTTPS に対応していない」「CloudFront が思わぬ挙動をする (特にヘッダー部分)」の 2 点につきますね。全てのハマりポイントをお伝えすることはできないかもしれませんが、本記事では特に HTTPS + CloudFront + WordPress に焦点を絞ってハマりポイントとその対策をお伝えできればと思います。

ACM で SSL 証明書を取得

ACM のダッシュボードのページに行きます。こちらによると、ACM で Amazon CloudFront 証明書を使用する場合、 米国東部(バージニア北部) リージョンで証明書をリクエストする必要があるとのこと。ですので、リージョンを切り換えていきます。
ACM のコンソール上でリージョンを切り換え

それでは、証明書を取得していきます。「証明書のプロビジョニング」とあるところの、「今すぐ始める」ボタンを押します。
ACM で証明書取得を開始

「パブリック証明書のリクエスト」を選択し、「証明書のリクエスト」ボタンをクリック。
ACM でパブリック証明書をリクエスト

まずはドメイン名を設定します。
ACM で作成する証明書にドメイン名を追加

検証方法は今回、ドメイン自体は Amazon Route 53 (Route 53) のホストゾーンで管理されている前提ですので、「DNS の検証」で OK かと思います。
ACM で作成した証明書の検証

タグの追加はいったん不要で飛ばしていただいて、確定とリクエストを押してください。

重要なのは次の検証ステップですね。ドメインの DNS 設定に次の CNAME レコードを追加せよ、とありますが、これまでの手順を経ていると「Route 53 でのレコード作成」というボタンが表示されているはずです。こちらを押していきます。
ACM で作成した証明書の DNS 検証

Route 53のレコード作成の画面に遷移しますので、そのままレコードを作成いただければ、検証は完了です。証明書の状況が「検証保留中」から「発行済み」に変われば、証明書の取得は完了、となります。

CloudFront ディストリビューションを作成

さきほど ACM で HTTPS 接続のための SSL 証明書は取得しましたが、このままでは作成した WordPress サイトに HTTPS 接続できません。HTTPS 接続は、前述のとおり CloudFront で実現します。 それでは CloudFront のダッシュボードを開き、「Create Distribution」でディストリビューションを作成していきましょう。
CloudFront でディストリビューションの作成を開始

次の画面は CloudFront ディストリビューションがどんなことに使えるかの画面であまり意味はないので、「Get Started」で次に進みます。

はい。CloudFront ディストリビューションの設定画面に来ました。ここの設定をミスると WordPress がうまく動作しない原因になるので、丁寧にいきましょう。

まずは Origin Settings です。Origin Domain Name に、WordPress をインストールした EC2 の「パブリック IPv4 DNS」を設定する、がここでは正解です。まずは EC2 のダッシュボードに行ってみましょう。「パブリック IPv4 DNS」のコピーボタンがあるので、押します。
EC2 インスタンス詳細でパブリック IPv4 DNS を取得

コピーした「パブリック IPv4 DNS」を、CloudFrontの「Origin Domain Name」に設定します。すると、「Origin Settings」の項目が増えるはずです。ただ、この設定値は CloudFront が 設定のオリジンを EC2 にする場合のおすすめの設定値なので、特にさわりません。なので以下のような設定になるでしょう (Origin Protocol Policy については、ここはあくまで CloudFront と EC2、厳密には InternetGateway 間の通信ですので「HTTP Only」のままであることが正しいのに注意です、ここを「HTTPS Only」としてしまうと 403 エラーになります):
CloudFront のディストリビューションのオリジンの設定

次に、Cache Behavior Settings を設定していきます。この Behaviors の設定が本記事で最も重要なポイントです。適切に設定しないと、CloudFront が適切に動作しないことで WordPress サイトの挙動もおかしくなってしまいます。ディストリビューションを作成する段階では、デフォルトを決めていく形になります。本記事では、CloudFront を導入するメリットを活かして、デフォルトはキャッシュを利かせる設定とします。
CloudFront ディストリビューションのデフォルト Behavior の設定

上記の赤枠の箇所だけ変更を加えます。それぞれ解説します。

まずは Viewer Protocol Policy ですが、「Redirect HTTP to HTTPS」の設定とします。つまり、HTTP (暗号化なし通信) によるリクエストがあった場合もとりあえず受け付けて、HTTPS (暗号化ありの通信) にリダイレクトする、という設定です。HTTP から HTTPS に移行する作業の手順の中で、どうしても WordPress が HTTP で通信しようとする箇所が残るはずなので、この設定です。

次に、Allowed HTTP Methods です。CloudFront を導入して特に影響を受けるのは実は記事を見せる画面ではなく記事を投稿したり、管理したりと CMS 側の機能だったりします。記事の投稿等は POST で行われるため、「GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE」とサーバーに変更を要求する類のメソッドの HTTP 通信を許可します (HTTPS にリダイレクトされるので安心です)。

Cache and origin request settings については「Use legacy cache settings」を使用します。これは、cache settings について WordPress をうまく動作させるために Cookie 周りの設定を細かく行う必要があるためです。

Minimum TTL/Maximum TTL/Default TTL、つまりキャッシュの有効期限に関する設定はここでは一律 300 秒 (5 分) としています。ここで全てを 0 とすると、いわゆるキャッシュを使用しない設定になります。キャッシュはメリットもデメリットもあります。まずメリットとしては、サーバーの負荷やデータ通信を抑えることができる点にあります。今後 WordPress サイトが人気になって多くのユーザからアクセスが集中した際に、サーバー 1 台では受け止めきれずサーバーが停止してしまうことがあります。ここで 5 分間キャッシュが効くというのは、5 分に 1 度しかもとのサーバーにリクエストが行かない、ということになります。一方デメリットもあります。サイトの情報を更新したときに、最大 5 分間はその設定が反映されないように見える、ということです。サイトの更新頻度を考えると、TTL の値を長くしすぎるのも考えもの、ということになります。

最後に、Forward Cookies を「All」に、Query String Forward and Caching を「Forward all, cache based on all」とします。これは、WordPress (の特に管理画面)でクライアント側の状態 (たとえば編集中の記事の内容) を Cookie に記憶させる挙動になるのですが、Cookie はすべてオリジンに転送しないと、WordPress の管理画面にログインする際、ログイン情報がサイトに転送されず、何度も再ログインを求められる、「もっと高いレベルの権限が必要です。」と警告が表示される等の事象が生じます。

Distribution Settings の設定を行います。あと一息で「Create Distribution」ボタンが押せそうです。
CloudFront ディストリビューションの Distribution Settings

まず Price Class ですが、こちらは端的に言いますと価格とパフォーマンスのトレードオフを決めよ、ということです。パフォーマンスについては、WordPress で配信するのはテキスト+画像ベースの軽いサイトかと思いますので、最も安い「Use Only U.S., Canada and Europe」を選択しています。

今回は CloudFront のデフォルトのドメイン名 (****.cloudfront.net) ではなく Amazon Route 53 (Route 53) で取得したドメインでの接続がゴールかと思いますので、Alternate Domain Names (CNAMEs) と SSL Certificate の設定を変更していきます。前者は既にこれまでの手順で取得したドメイン名を設定し、後者は「Custom SSL Certificate」を選択の上、「Request or Import a Certificate with ACM」ボタンを押して既に取得済みの ACM 証明書をインポートします。

「Create Distribution」ボタンを押して、CloudFront ディストリビューションを作成します。

CloudFront ディストリビューションに WordPress 管理画面用の Behavior を追加

ここで、さらに CloudFront ディストリビューションに WordPress 管理画面用の Behavior の設定を追加します。これまでの設定で、CloudFront ディストリビューションのキャッシュを 5 分間効かせる設定をデフォルトとしてきましたが、管理画面に対してはヘッダも含めてキャッシュを効かせると動作がおかしくなるため、キャッシュを有効にしない設定としていきます。

まず、作成した CloudFront ディストリビューションを選択した状態にした上で、「Distribution Settings」ボタンを押します。
CloudFront ディストリビューションに WordPress 管理画面用の Behavior を追加

「Behaviors」タブで、「Create Behavior」ボタンを押してBehaviorを追加します。
CloudFront ディストリビューションに Behavior を追加する方法

以下のように設定を加えていきます。
CloudFront ディストリビューションに追加する WordPress 管理画面用の Behavior の設定
Path Pattern には、WordPress 管理画面の URL相当を入れていきます。ここまでの手順を同様に踏まえて実施しているとここでのパスは「/wp-admin/*」となるはずですが、ここはご自身の WordPress 環境に合わせて修正してください。

Viewer Protocol Policy、Allowed HTTP Methods はそれぞれデフォルトの Behavior と同じく「Redirect HTTP to HTTPS」、「GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE」 としてください。

また、Cache and origin request settings についても同様、「Use legacy cache settings」を選んでいくのですが、ここで次の Cache Based on Selected Request Headers を「All」にするようご注意ください。このように設定せず、ヘッダーの管理を CloudFront に任せてしまうと、1. CloudFront がリクエスト元の X-Forwarded-Proto ヘッダーを削除して WordPress の管理画面が制御できなくなり ERR_TOO_MANY_REDIRECTS エラーが発生する、2. CloudFront が User-Agent ヘッダーを置き換えてしまい、WordPress 側で User-Agent ヘッダーが参照できずビジュアルエディター (ブロックエディター) を起動しなくなる、等の事象が発生します。

Forward Cookies、Query String Forward and Caching についてはデフォルトの Behavior と同様に、それぞれ「All」、「Forward all, cache based on all」とします。

ここで「Create」ボタンを押し、WordPress 管理画面用の Behavior を追加します。

Route 53 のホストゾーンを変更

HTTPS でアクセスする際は、さきほど設定した CloudFront 経由でサイトにアクセスすることになるので、Route 53 内のホストゾーンのレコードを変更する必要があります。

現状、レコード名「${ドメイン名}」でタイプ「A」のレコードがあり、その「値/トラフィックのルーティング先」が「${グローバル IP}」となっているかと思いますが、こちらを「${CloudFront ディストリビューションの DNS}」に変更します。

まずは Route 53 のホストゾーンに遷移し、該当のレコードを選択の上、「レコードを編集」ボタンを押します。
CloudFront 導入に際し Route 53 のホストゾーンを編集

値の近くにある「エイリアス」のトグルスイッチをオンにします。そうすると、値が「トラフィックのルーティング先」となるかと思います。その後、「エンドポイントを選択」セレクトボックスの値を「CloudFront ディストリビューションへのエイリアス」に選択し、出てきた「ディストリビューションを選択」テキストボックスをクリックすると先程作成した CloudFront ディストリビューションの DNS が出てくるかと思いますので、そちらを選択します。
Route 53 の A レコードを CloudFront に向けるよう編集

その後、「保存」ボタンを押せば Route 53 のホストゾーンの設定変更は完了です。

MySQL にアクセスし WordPress アドレスとサイトアドレスを更新

以降は、作成した WordPress サイトに対しては HTTPS でアクセスすることになります。現状、WordPress アドレスおよびサイトアドレスが HTTP のままになっているかと思います。これらの値を、HTTPS に更新していきます。

HTTP から HTTPS に変更したことで、この段階では確実に WordPress 管理画面が適正な動作をするとは言えない状態になっている可能性があります。そこで、今回は MySQL に直接アクセスし、保存されている WordPress アドレスおよび サイトアドレスの値を更新します。

EC2 サーバーに SSH でログインします。

その後、WordPress のデータベースに mysql クライアントで接続します。

# mysql -u ${MySQL ユーザ名} -p ${データベース名}

パスワードを入力して接続できましたら、以下のクエリを実行して WordPress アドレスとサイトアドレスを更新してください。

mysql> UPDATE wp_options SET option_value = 'https://${ドメイン名}' where option_name IN ('home', 'siteurl');

このとき、${ドメイン名} には末尾に '/' (スラッシュ) を入れないように、お願いします。

wp-config.php を編集して強制的に WordPress (PHP) に HTTPS を認識させる

ただここまで設定しても、ERR_TOO_MANY_REDIRECTS エラーは解決していない可能性が高いです。これは、URL スキーム上は HTTPS なのですが処理サーバー側は HTTP であるために自サイトへのリダイレクトパスの挙動がおかしくなってしまうためです。

そこで、WordPress (厳密には WordPress を実行する PHP)に HTTPS であることを認識させます。

サーバー内の、/usr/share/nginx/html/wp-config.php 内を開き、

$ sudo su -
# vi /usr/share/nginx/html/wp-config.php

wp-setting.php が読み込まれる前に WordPress 自身に HTTPS での接続を認識させる ($_SERVER['HTTPS'] = 'on'; および $_ENV['HTTPS'] = 'on';) よう設定を追記し、保存します。

...
/* 以下の 2 行を追記 */
$_SERVER['HTTPS'] = 'on';
$_ENV['HTTPS'] = 'on';
...
/** Sets up WordPress vars and included files. */
require_once ABSPATH . 'wp-settings.php';
...

厳密には、こちらによると Web サーバー側 (本記事の構成だと Nginx) のEnv を HTTPS と認識させる方が保守性の観点から、また正式な方法という意味でもより良さそうです。こちらについては筆者は未検証です。

SSL Insecure Content Fixer プラグインを導入し完全 HTTPS 化

ここまで来たらあと一息です (プラグインを導入するために管理画面にログインできる状態にまで来ているはずですので)。WordPress には完全 HTTPS 化するためのプラグインが用意されていますので、使っていきます。

WordPress のメニューに、「プラグイン」があります。そこで「新規追加」を押すと、プラグインを検索できる画面が表示されます。「SSL Insecure Context Fixer」で検索して、SSL Insecure Content Fixer を「今すぐインストール」、「有効化」していきます。
WordPress に SSL Insecure Content Fixer プラグインを追加

その後、WordPress の「設定」、「SSL Insecure Content」(SSL Insecure Content Fixer 設定)画面内の 「HTTPS の検出方法」で 「HTTP_CLOUDFRONT_FORWARDED_PROTO (Amazon CloudFront HTTPS キャッシュ済みコンテンツ)」を選択し、「変更を保存」ボタンを押します。
SSL Insecure Content Fixer プラグインで CloudFront 用の設定を実施

これで、HTTPS 化の作業は完了です。

ネクストアクション

次からは、ようやくサイトの中身に移っていきます。公開するにあたり、最低限用意した方がいい、プライバシーポリシー、免責事項等について言及したいと思います。

タイトルとURLをコピーしました