WordPress on AWS構築の備忘録2

AWS上にWordPressを構築して割と直ぐですが、環境がガラッと変わりました。備忘録その2のメイントピックは、

  • 前回の記事の環境から静的WordPress on S3への移行
  • WordPress on EC2からローカルのWordPress on MAMPへの移行

です。ハマったポイントを重点的に書いておきます。この記事が問題なく投稿できていれば、移行はひとまず成功したことになります。


■現在のWordPress on AWSの構成図

大分スッキリしました。ELB、EC2、RDSが丸ごといなくなったのが大きいです。現在のWordPress運用の流れは、

  • ローカルPC上のWordPressで記事作成・静的htmlをデプロイ
  • aws cliでS3へアップロードして公開

です。編集環境と公開環境が違うので一、二手間増えましたが、これはこれで以下のメリットがあります。

  1. 運用コストが大きく減る
  2. WordPressのセキュリティが向上する
  3. 可用性が向上する
  4. オフライン環境でWordPressの記事が書ける

一番のメリットはとにかくコストが安い事です。EC2とRDSを利用しないだけでコストがガクッと下がります。前回の環境のままだと、無料期間中でもランニングコストが掛かる上、その期間が過ぎれば最低でも1月あたり7.000 ~ 8.000円掛かる見込みになります。アクセス数が全然無くてもこれぐらいです。それぐらい大したこと無い方には良いですが、節約できることに越したことはありません。

セキュリティの面では、WordPressを静的化する事によって公開Webサーバ上でphpを動かすことが無くなります。Webサーバのセキュリティ対策をキッチリやっていれば稀有かもしれませんが、脆弱性を少なくできる意味合いは非常に大きいです。WordPressやApache、phpの更新を忘れていて何時の間にかサイトがクラックされる心配が減るからです。

可用性の面ではS3様様です。EC2とRDSで可用性を担保するにはS3に比べてコストが多く掛かります。RDSのMulti-AZ構成は無料範囲外な上、2インスタンス以上のEC2で24時間運用をすると無料枠を楽々超えてしまいます。更に私の場合はNFSサーバがSPOFだったので、今回の構成を取る事で可用性が明らかに向上します。

オフライン環境でWordPressの記事が書ける事は、私のような非商用個人ブロガーにとってそこまで旨味では無いかもしれません。ネットに公開するにはどの道オンライン環境が必要ですし。しかし出先の喫茶店でWi-fiやスマホのテザリング無しで記事が書けるのは、私にとって大きいです。後は細かい事ですが、Route53にアクセスする頻度が減るのも若干の経費削減となります。

オフライン化の唯一のデメリットは、バックアップを取らずにPCが死んだら何も出来なくなる事ぐらいです。静的化したWordPressから変換前の状態に戻すのは不可能・不可逆です。手作業で一からの再構築が現実的ですが途方に暮れます。定期的なバックアップは必須です。ローカルではなく無料のクラウドサーバに移行するのも代替手段だと思います。それはそれでコワいのですが… 結局はトレードオフです。ITあるあるです。


■1.環境のバックアップ

移行に向けて色々弄くり回す前に、最新の状態のバックアップを取っておきます。どうしても前の環境に戻したくなった時の保険です。

お手軽なバックアップ方法には、

  • AMIイメージの取得
  • RDSスナップショットの取得
  • CloudFormationのCloud Formerでテンプレート取得

の3つがあります。WordPressディレクトリの圧縮コピーとMySQLのダンプでも良いでしょう。ただ私の環境の場合、Cloud FormerでELB(ALB)がNot Foundになりjsonテンプレートに記述されない問題に直面しました。Cloud Formerを使わず自分でjsonを書けば済む話ですが、そこまでやる必要も無かったので潔く諦めました。


■2.使用しているWPテンプレートの確認

ここからWordPressの静的化について考えます。大事なのはWordPressの動的コンテンツは何かを洗い出す事です。これはテンプレート毎/個々人のカスタマイズ状況によって千差万別ですが、メジャーなところだと以下の物でしょう。

  • WordPress標準のコメント機能
  • 外部サイト(Googleカスタム検索とか)を利用しないサイト内検索機能
  • HTTPリクエストヘッダ(User-agentとか)を利用したレスポンシブ実装
  • Jetpackプラグインの関連記事表示機能

コメント機能・サイト内検索機能・プラグインの対応は楽です。単純に使わなくすれば良いだけですので。ただしレスポンシブの実装を変えるのは大変です。User-agentによる動的制御(Apache or Nginx/PHP)からブラウザによるメディアクエリ制御(CSS/Javascript)に変えるのは、かなり詳しい人でないと厳しいと思いますし時間が掛かります。

もしもレスポンシブ実装がUser-agent制御だった場合、素直にテンプレートを変更する方が良いと思います。どうしてもそのテンプレートを使って静的化したい場合はWebデザイナー/プログラマーでも雇って下さい。タダでは誰も助けてくれないと思います。結構掛かるとは思いますけど…


■3.動的コンテンツの無効化

2.で洗い出した内容を元に動的コンテンツを無効化します。私の場合ハマったのは投稿記事ヘッダーにあるコメント数のリンクと表示を無くす事でした。

利用させて頂いているテンプレートだと、有料版でカスタマイザーの画面から1クリックで非表示に出来る機能があるのですが、私はphpを直接弄って済ませました。具体的な方法を書くと作者様にお叱りを受けそうなので控えておきます。アヤシイphpを読んで辿っていけば行き着きます。

尚、WordPressのコメント機能の無効化はfunctions.phpの最後に以下の1文を書き足したらOKでした。

add_filter( 'comments_open', '__return_false');

■4.外部コメント機能サービス(DISQUS)の導入

コメント欄が無いのも何だか味気ない気がしたので、Javascriptベースの導入コードで済ませられるDISQUSを導入することにしました。

まさかのここでハマりました。何も考えずにDISQUSのWordPressプラグインを導入して、そのまま静的化して公開したらコメント欄が読み込めない(Not Loaded)状態になったからです。

静的WordPressでDISQUSを利用する場合、潔くUniversal Codeを利用しましょう。今までプラグインを利用していた方はそちらに乗り換える必要があると思います。これが意外と情報が全く無くて気付くのが遅れました。常識的に考えれば分かることなのですが… ひねくれ者なので、プラグインのままでも他の人は普通に動いているのかと思いました。

表示したいページを生成している適当なphpファイル(content-single.phpとか)にコードをベタ貼りすれば、静的化後でもDISQUSが問題無く使えます。あぁ恥ずかしい。時間の無駄でした。


■5.静的化プラグインでWordPressを静的化

CloudFrontのキャッシュを利用していて、公開しているWordPressをSimply Staticで静的化する場合、その前に必ずキャッシュ動作を無効化(TTLを全て0に)するのと、invalidation(/*で全キャッシュ削除)をする事を忘れずに。

私はこれで少しハマりました。デプロイ後、WordPress標準機能のコメント投稿欄が残っているhtmlがあったりなかったりした原因がコレでした。

Web/APサーバ上のSimply Staticを使っているのに、なんでCloudFrontのキャッシュが影響するの?と思いますが、恐らくはhtml化のベース情報にcurlの結果を使用しているからだと思われます。詳しく調査してないので憶測に過ぎませんが。

[ec2-user@ip-XXX-XXX-XXX-XXX ~]$ curl --head https://romantic-classic.tokyo/
 HTTP/1.1 200 OK
 Content-Type: text/html
 Content-Length: 49906
 Connection: keep-alive
 Date: Fri, 06 Apr 2018 00:16:02 GMT
 Last-Modified: Thu, 05 Apr 2018 00:49:58 GMT
 ETag: "24109d98383d31e1e44ef17db83a3ac3"
 Server: AmazonS3
 Vary: Accept-Encoding
 Age: 9
 X-Cache: Hit from cloudfront
 Via: 1.1 6600d39ae39aca53f80031edaae8c0ea.cloudfront.net (CloudFront)
 X-Amz-Cf-Id: 0YU-ydeMEIEIwrGr-Sk1R5-u4d0D9Met1217RJ-uTu0R2EgkBg17sA==

キャッシュを有効化した状態でWeb/APサーバからcurlを叩くと、実際キャッシュにヒットするのです。これが原因としか今のところ考えられません。Webサーバの設定を弄るよりかは、CloudFrontのキャッシュを無効化/全削除する方が圧倒的に楽でリスクが少ない思います。

これから実施される方は、是非事前にWPサーバからcurlを叩いてチェックしておいて下さい。2回以上叩いてキャッシュヒットしなかったらこの対策は無意味です。

静的化に利用したプラグインは上述の通りSimply Staticです。先人の知識が多いStatic Pressは長い間更新されていなかったのでこちらを選びました。静的化のデプロイはApacheの一時ファイルで403エラー(どう考えてもHTTPレスポンスコード)が出たものの全然問題なかったので大丈夫でした。

S3へのファイル/フォルダアップロードは、EC2にaws cliをインストール(IAMユーザの作成も)していれば楽ですので是非。ローカルに移してブラウザからドラッグ&ドロップでもイケそうですが、ブラウザとの相性問題もあるようなので私は避けています。aws cliが非常に使いやすいのでそちらの方がお薦めです。


■6.S3で静的ウェブホスティング

今回最大のハマりポイントです。色々トラブりましたが、S3でHTTPリクエストを捌く方法には2通りの方法と3種類のエンドポイント名(要はドメイン名)がある事を私が良く理解していなかったのが原因です。

こんな駄文より、以下のAWSの公式ドキュメントの方が遥かにきっちりまとまっています。必ず読み込みましょう。

まずはドメイン名から。普通にS3を利用する上で目にするドメイン名は以下の3種類だと思います(※パス形式のドメイン名は省いています)。

  • REST API エンドポイント名:<バケット名>.s3.<リージョン名>.amazonaws.com
  • 仮想ホスティング名(↑と同じ役割):<バケット名>.s3.amazonaws.com
  • ウェブサイトエンドポイント:<バケット名>.s3-website-<リージョン名>.amazonaws.com

つまり、REST APIエンドポイントかウェブサイトエンドポイントのどちらを使うかを決める必要があります。そんなものを一切考えず、CloudFrontのOrigin設定で自動的に出てくる仮想ホスティング名と自動S3設定を利用して、色々トラブった訳です。完全に自己責任です。

REST APIでもウェブサイトでも、どちらでも静的htmlは公開できます。しかし違いがかなりあるので、上記した公式ドキュメントにあるAmazonウェブサイトとREST APIエンドポイントの主な違いを読んで、どちらが自身の場合は相応しいのか判断しなければなりません。

私の環境とWordPress設定の場合、以下の違いが決定のキーになりました。

REST APIエンドポイント ウェブサイトエンドポイント
index.htmlの自動補完 document rootのみ可能
(CloudFront)
可能
(S3の設定が反映される)
バケット直アクセス禁止 可能
(CloudFront)
可能
(S3のバケットポリシー)

index.htmlの自動補完は、WordPressのパーマリンクとfunctions.phpの設定次第です。デフォルトのままだとURLの末尾に.htmlが付かないので、Simply Staticで静的化するとindex.htmlファイルがページの分だけ出力されます。なので必然的にウェブサイトエンドポイントを利用するしかありません。

この状態の静的WordPressにREST APIエンドポイントでアクセスしてしまうと、XMLのエラーページが帰ってきます。末尾に手動でindex.htmlを付けると表示されるのですがこれではダメダメです。パーマリンクとphpを弄って、静的化後の全てのページを.htmlになるようにしていれば、REST APIエンドポイントでも問題ないでしょう。

REST APIエンドポイントのメリットは、CloudFrontの設定でバケットへの直アクセスを禁止できる事です。CloudFrontのOrigin設定に仮想ホスティング名を使うと、ページのレイアウトが変わってRestrict Bucket Accessを設定できるようになります。これは楽ですし非常に便利だと思います。またSSLにも対応しているようなので、CloudFrontより後もHTTPS化したいならREST APIを利用するしかありません。

ウェブサイトエンドポイントをOriginに設定すると、OriginはS3では無くCustom Originとして認識されます。よって上述した設定はできないのでバケット直アクセス禁止はできないように思えます。CloudFrontから設定できないのは事実ですが、S3のバケットポリシーで代替可能です。User-agentをCloudFrontのみに絞るというやや不安なセキュリティではありますが…

また、同じ理由で悩んだりハマったりする人はやはりいるようです。先人達の体験談には感謝する他にありません。


■7.固定コンテンツの手動移動

WordPress以外に自分で作ったhtmlファイルや、robots.txtは作り直して手動でS3にアップロードする必要があります。robots.txtはWordPressのデフォルトだと仮想(実ファイルではない)ですし、静的化後にディレクトリ構造が変わるので変更が必要です。忘れずに。


■8.WordPressのローカルMAMP移行

WordPressの静的化まで問題無くできるようになったら、個人PC(mac)のMAMPにEC2上のWordPressを移行しました。詳しい流れは以下のサイトを参考にしました。

MAMPの設定で特にハマった点はありませんでしたが、ローカルに落とした最新WordPressバックアップとMAMPとの環境差異で少々手こずりました。

一応、その時にやったことを箇条書きでメモしておきます。

  • MAMP(Apache)のドキュメントルートをwordpressディレクトリに変更

※肝は↑です。ApacheのドキュメントルートとWordPressの.htaccessに記載されているmod_rewriteのpathとの相対位置がずれると不具合が生じます。ログインもできるしトップページは表示されるのに、他のページやプレビューが見れない場合はmod_rewriteのpathかドキュメントルートを疑いましょう。

  • MAMP(Apache)で使用するPHPのバージョンダウン(5.X台まで下げました)
  • .htaccessを編集してベーシック認証解除
  • wp-config.phpのSSL化設定をコメントアウト
  • header.phpのGoogle Analyticsコードを削除

※↑これはやってはいけません。localhostへのアクセスも集計されるのでGAの統計が荒れるのが嫌だったのですが、公開側の統計もされなくなるので本末転倒です。正しくはGAの設定で、ホスト名がlocalhostからの統計をフィルターで除外する必要があります。ボケてました。

  • WordPressの時刻設定を更新(日本時間じゃなかったので)

ブラウザでうまく表示されない時は、Apache/MySQL/PHPエラーログをtail -fするのと、curl –headでHTTPレスポンスコードを確認して原因を探るのが良いと思います。


■9.AWSの後始末

使わなくなったサービスは利用停止/削除しましょう。これだけやって前の環境が稼働しっぱなしでは意味がありませんからね…

上乃木 燕二
クラシック音楽のブログを運営しています。後期ロマン派〜新ウィーン楽派がメイン。交響曲ネタが多目。オペラ・室内楽を扱うべく奮闘中。元トロンボーン奏者。チェロやりたい。マーラーとテンシュテットが心の師匠。