こんにちは。かねしろ@pinkrootです。
久しぶりのブログ記事ですが、特に気にすることもなく淡々と最近取り組んだことについて書いていきたいと思います。
マルチサイト版WordPressをS3で配信したい
プライベートなプロジェクトでWordPressを複数立ち上げることになったのですが、あまりアクセスがくるものでも更新するものでもないので、運用費用を抑えつつ高速化するためにS3で配信してみようと思い立ちました。
ぐぐってみるとWordPressをS3で配信する方法をまとめてくださっているブログなどはいくつかあったのですが、記事が古かったりマルチサイト版だと正しく動作しないなどありましたので、2018年6月現在動作確認できた手順をまとめました。
なお、マルチサイト版にはいくつかパターンがあり、今回検証したのはマルチドメイン版ですがどのマルチサイト形式のWordPressでも手順は変わらないはずです。
なんならシングルサイト版の普通のWordPressでも同様の手順で動作すると思います。
構成
全体の構成ですが、下記のようになります。
EC2インスタンス
WordPressの記事投稿や設定用の環境です。すべての動作が確認できたあとには潰してしまってもブログを運用することが可能です。ユーザのアクセスを受けるわけでもないのでnanoインスタンス(t2.nano)あたりで問題ありません。
S3
WordPressの記事やページをhtml化して格納する場所として使います。S3単体でも静的サイトとしての配信が可能ですが、独自ドメインかつSSL通信(https)で運用するには後述するCloudFrontと組み合わせる必要があります。
CloudFront
CDNです。S3上のファイルを取り込んだ上で、ユーザのアクセスは基本的にCloudFrontで受けることになります。
Route53
DNSです。独自ドメインはRoute53で管理し、CloudFrontへアクセスを流すようにします。
配信までの手順
大雑把な手順としては下記のようになります。
- S3にディレクトリを作成
- SSL証明書をAWS Certificate Managerで取得
- S3に繋げる形でCloudFrontを設定
- WordPressを静的ファイル化しS3にアップロード
- Route53にてドメインをCloudFrontに向ける
なお、前提として使いたいドメインはRoute53で管理しているものとしています。
特に本記事で紹介するドメイン直下をCloudFrontに向けるにはRoute53のエイリアス設定を用いる必要があるので、別のDNSを使っている方はまずRoute53に移行しましょう。
また、検証した環境はAWS Marketplaceで公開されている
WordPress Multisite Certified by Bitnami
で立ち上げたwordpressになります。
マルチサイト化しているwordpressであれば同様の手順で実現できるはずです。
S3のディレクトリ作成
まずは静的ファイルをホスティングするためのS3バケットを作成します。
バケット名はドメイン名と同名にする必要があるので注意しましょう。
例: example.com
サブドメインで配信をする場合はバケット名もサブドメイン込みのものにすること。
次にバケットのプロパティからStatic website hostingを有効にします。
また、インデックスドキュメントとしてindex.htmlを指定しましょう。
なお、この設定画面に表示されているエンドポイントはCloudFrontの設定時に必要になるのでメモしておくこと。
例: http://example.com.s3-website-ap-northeast-1.amazonaws.com
パブリックアクセスを許可するためにプロパティからバケットポリシーを編集しましょう。
内容は下記のようにします。Resourceのドメイン名は自分のドメイン名に置き換えてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AddPerm", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::example.com/*" } ] } |
正しく設定できた場合はタブにパブリックと表示されるはずです。
SSL証明書をAWS Certificate Managerで取得
サイトの配信はhttpではなくhttpsで行いたいので、AWSのCertificate Manager(ACM)でSSL証明書を発行します。
無料で発行できるので非常に便利。
発行したSSL証明書をCloudFrontで使うにはリージョンの制約があったりするので、間違えないようにCloudFrontの画面から(ACM)に遷移しましょう。
まずはCloudFrontのダッシュボードからcreateを選び、次にwebを選択。
設定画面の中ほどまでスクロールすると「Request or Import a Certificate with ACM」のボタンがあるのでこれを押下すると有効なリージョンに切り替わった上でACMに遷移することができます。
ACMではまずドメインを入力します。今回の場合はドメイントップのみで良いので
example.com
というような形で入力しましたが、サブドメインでの利用を予定している場合は
www.example.com
といったサブドメイン決め打ちでの入力のほか、
*.example.com
というかたちでワイルドカードでの指定もできます。
次に進むと認証の方法が問われるので、DNSでの認証を指定。
ドメインがRoute53で管理されている場合はこの方法のほうが楽な模様。
次に進むと検証画面にて指定したドメインが表示されていますが、
ドメイン名の横の三角形を押下し、「Route53でのレコードの作成」ボタンを押下し、CNAMEレコードを作ることで検証を実施してください。
成功となったらSSL証明書の発行は完了です。検証に少し時間がかかるのでしばらく小休憩。
おおよそ10分ほどで検証が完了します。
S3に繋げる形でCloudFrontを設定
改めてCloudFrontのcreateに戻ります。
Origin Domain NameはS3のWeb Hostingのエンドポイントをコピペしましょう。
プルダウンから選択できるものだと、例えば
https://example.com/foo/index.html
にはアクセスできても
https://example.com/foo/
にアクセスしたときに自動的にindex.htmlを読み込んでくれないようで、
Code: NoSuchKey
Message: The specified key does not exist.
のエラーとなってしまうので注意。
特に固定ページやカテゴリページでこの事象にハマってしまいました。
S3はRESTとしてのエンドポイントとwebsiteとしてのエンドポイントの2種があるそうで、その挙動の違いが原因とのこと。
Origin Pathは空のままでOK。
Origin IDはユニークになればいいので、自動入力されたものか、テキトーに識別できるものに設定すると良いです。
今回はhttpでのアクセスをすべてhttpsにリダイレクトしたかったので、
Viewer Protocol PolicyをRedirect HTTP to HTTPSに変更。
Alternate Domain Namesの項目にはドメインを入力します。
例: example.com
サブドメインでの運用を予定している場合はワイルドカードも使えるようなので、とりあえず
*.example.com
といった形で入力すると良いかと思います。
Custom SSL CertificateはACMで作成したSSL証明書を選択します。
(デフォルトはDefault CloudFront Certificate (*.cloudfront.net)にチェックが入っているはずなのでCustom SSL Certificateにチェックを切り替えてください。)
Default Root Objectは
index.html
を設定。
以上でcreateをするとCloudFrontのdeployが開始されます。
待ち時間が15分~30分程度かかるので小休憩。
WordPressを静的ファイル化しS3にアップロード
まずはプラグインを導入します。
wordpressの記事やページを静的ファイル化するプラグインはいくつかありますが、メンテナンスが止まっていたり、マルチサイト環境では動かなかったりなどあり、僕は
WP Static HTML Output
に落ち着きました。
プラグインの新規追加から検索すると表示されるバージョンをインストールすると良いと思います。
また、
Disable Responsive Images
も導入する必要があります。
これを入れないと埋め込み画像が正常に機能しないようです。
ダッシュボードからの検索では出てこないのでwordpress.orgからダウンロードし、FTPなどでアップロードする必要があります。
以上のプラグインを導入し、サイトネットワークで有効化してください。
次に各種設定。
最初にやるべきはパーマリンクの確認です。
といいつつ、ここまでの設定が正常にできているのであれば割とどのような設定でも問題ありません。
S3やCloudFrontの設定にミスがある場合は、パーマリンク末尾に「.html」を付ける必要があり、そのように解説しているブログも多数ありますが、僕のブログのように
/%category%/%postname%/
という設定でも、S3内のpostnameと同名のフォルダ配下のindex.htmlが自動で読み込まれるため、きちんとページが表示されます。
とはいえ、パーマリンクには一つ問題があります。それは日本語URL問題です。
今回利用しているプラグインが海外製ということもあり、日本語のURLはエンコードされた状態でS3にフォルダ・ファイルが作られ、結果読み込みがうまくいかないという事象が発生してしまいます。
この問題を回避するには、
- 記事のスラッグはもちろん、カテゴリやタグなどURLに影響するスラッグはすべて英数字にする
- プラグインを一部書き換え、URLをデコードした上でフォルダ・ファイルを生成するようにする
簡単な対応は1ですが、既存記事のURLを変えたくない場合はSEO観点などから2を取りたい方は、自己責任のもとプラグインをカスタマイズしてください。
なお、私の手元の環境ではver 2.5のプラグインに対して
library/StaticHtmlOutput/UrlRequest.php
のファイルにある
1 |
$this->_url = filter_var(trim($url), FILTER_VALIDATE_URL); |
の処理を
1 |
$this->_url = rawurldecode(filter_var(trim($url), FILTER_VALIDATE_URL)); |
と変更することで正常な動作を確認しました。
なお、プラグインのバージョンアップをすると変更点は上書きされるはずなので、バージョンアップをしないという判断か、都度書き換えを行う必要があります。
(プルリクエスト送ろうと思ったらSVNだったので断念)
続いてWP Static HTML Outputの設定。
ツールからWP Static HTML Outputを選択すると設定画面が開きます。
Base Urlはhttpsのプロトコル込でドメイン名を入力します。
例: https://example.com
Output Directoryはbitnamiのディレクトリ内に出力したいので
/opt/bitnami/apps/wordpress/htdocs/wp-content/static/example
といった形で設定しました。
末尾のexampleの部分はサイト毎に異なるものとしています。ドメイン名を入れておくとわかりやすいかと思います。
今回はS3にファイルをアップロードするので、Transfer files via S3へチェックを入れ、各種認証情報を入れていきます。
これらの認証情報はIAMで作ったユーザの認証情報なので、ユーザ未作成の方は各種ドキュメントを参考にIAMのユーザ作成とkey/secretの取得を行ってください。
IAMにつけるRoleはS3のFullAccessなどで良いと思います。適宜権限を絞ってもよいかと思いますが、ReadとWriteの権限は必要です。
Bucketnameはドメイン名で作成したバケットの名前(exapmle.comなど)で、
CloudFront DistributionIdはCloudFrontのダッシュボードから、先程デプロイした環境のIDをコピペしてください。
ここまで入力できたらSave Current Optionsのボタンを押下して設定を保存します。
保存ができたらページ下部にあるStart Static Site Exportボタンを押下することで、各記事・ページがhtmlファイルとなりS3にアップロードされます。
正常に動作した場合、S3のバケット内にファイルが出力されているはずです。
Route53にてドメインをCloudFrontに向ける
ここまで来たらあとはドメインへのアクセスをCloudFrontに向けるだけです。
Route53で当該ドメインの設定画面を開き、
AレコードのAliasをYesに設定。
向き先はプルダウンからCloudFrontのDistributionを選択してください。
以上で設定は完了です
お疲れ様でした。以上で設定は完了です。
独自ドメインにアクセスすることで各ページが表示されることを確認したあとはWordPressを動かしているEC2インスタンスを停止してしまって問題ありません。
一見複雑な手順となりますが、一度やってしまえば2回目以降は非常に楽に作業を行うことができました。
いくつブログを立ち上げてもコストをそこまで増やさずに運営できるのは良いですね。
また、副次的な作用としてS3で配信することで各ブログのIPアドレスを分散させることになるので、ブラックSEO的なサテライトサイトの量産といった使い方もできそうです。
ご利用は計画的に。
おしまい