(追記 7/11)
qiitaの記事を転機し,動作テストとする.
(追記 7/10)
cloudfrontの設定を追記した.
意外と手間がかかっていて,wordpressを普通に運営した方がいいんじゃねーのってツッコミもありうる.
注意
ドメイン名を晒していますが,403 Forbiddenが返ってしまった方がいるかも知れません.
過去にアタック性のあるURLへのアクセスが検出されたアクセス元IPアドレスは,全て機械的に拒否設定しているため,そのリストに加えられている可能性があります.
遊び半分で「w00tw00t」なんて文字列の入ったパスにアクセスしちゃダメ,絶対!
疲れた…
私の運営するwebsiteは,wordpressがメインコンテンツになっている.
運用するのは結構大変で,
もう疲れたよ!
この記事の概略
https://wp.hadacchi.com がサンプル (なぜか wp_blog/index.html だけ,index.htmlまで指定しないと読んでくれない)
※スクリーンショットを何回にも分けて取ったので,ドメイン名がコロコロかわっている点はご留意いただきたい.
対策→構成変更
ということで,手間を少なくblogを運営する方法を模索することにした.
構成っぽく書くが,AWS構成はフルマネージドのサービスを使っているので,実際の構成とはきっと違うし雰囲気だけ掴めれば良いことにする.
構成(イメージ)
[the Internet]
|
[FW]
|
+-- [Server] (nginx + wordpress)
|
+-- [Object Storage]
[the Internet]
|
[AWS Cloud Front]
|
[Amazon S3] <--(awscli)-- [FW] -- [local machine] (nginx + wordpress)
要は,従来のクラウド上の機能をローカルの非公開NWに落として,静的コンテンツに変換したものをS3にアップロードする.で,CloudFront経由で公開する.
しかも,今のクラウド料金はVMとオブジェクトストレージを合わせて400円/月くらいだが,この構成なら200円/月くらいになるはず.
あーなんで,この方法に気付かなかったんだろ.
実は,この記事[1]で行けるんだけど,ハマりどころがあるのでもう少し細かく書いたものが,本記事である.
基本的には,素晴らしき先達のノウハウを活用されたい.
S3でindex.htmlを公開する
簡単には,この記事の通りである→[2]
ただ,いくつか端折られてたりするので,もちょっとだけ詳しく書く.
なおAWSアカウントは,もうあるものとする.(既に持ってるので再現できない)
awscli導入
awscliを,まず導入してしまおう.
pipが使えるものとし,awscliをインストールする.
# user権限で入れると ~/.local/bin/ にインストールされる
pip install --user awscli
export PATH=${HOME}/.local/bin:${PATH}
aws --version
すると,こんな感じの結果が返ってくる.
aws-cli/1.15.49 Python/2.7.9 Linux/3.16.0-4-amd64 botocore/1.10.48
文献[2]の通りバケットを作成する
仮ドメインをtmp.hadacchi.com
とすると,バケット名もtmp.hadacchi.com
とする.
※他の設定を正しくしても,この名前が合ってないとs3 webhostingでは404が返るので注意.
※cloudfrontを設定した後はこの限りでない
indexesを.htmにしたい場合は,index.htmと書けば良い.
ただし,後述のstaticpressというwordpressをhtml化するプラグインはindex.htmlとして吐くので,あえてhtmにするメリットはない.
バケットポリシーは,Resourceのところを,「バケットポリシーエディター ARN: arn:aws:s3:::tmp.hadacchi.com」と編集画面で書かれているところからコピペして修正すること.

書くならこんな感じ.
Versionの値の"2012-10-17"は,このJSONの従うフォーマットのバージョンなので,この値で良いことに注意.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AddPerm",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::tmp.hadacchi.com/*"
}
]
}
IAMの作成(権限作成)
wordpressが動作しているAWS外のホストから,awscliで接続できるよう設定したい.
AWSのアクセス管理は,ユーザ(IAM)への権限付与で行なうので,まずIAMユーザを作る.
AWSコンソールの左上の「サービス」をクリックし「IAM」を選ぶ.

先にポリシーを作成する.

ビジュアルエディタでポチポチ選べば作成できる.
設定はS3を選んで,権限を選んで,対象リソースや対象オブジェクトを指定する.
具体的には,以下の通り.(ListAllMyBucketsにobjectの指定は不要なので,設定後にListAllMyBucketsだけ別グループに自動で切り出される)
サービス:S3
アクション(リスト):ListAllMyBuckets, ListBucket
アクション(読み込み):GetObject
アクション(書き込み):DeleteObject, PutObject
リソース(bucket):arn:aws:s3:::tmp.hadacchi.com
リソース(object):arn:aws:s3:::tmp.hadacchi.com/*
最後にReview policyを選んでからポリシーセットに名前をつけてcreate policyで作成できる.
IAMの作成(ユーザ作成)
今作ったポリシーを付与するユーザを作る.

とりあえずCLIからアクセスするキーさえあれば良い.

上で作成したポリシーをアタッチする.

で,スクロールして右下の確認→作成で完成.
次の画面のアクセスキーとシークレットアクセスキー(要はID/PW)はこの画面でしか確認できないので,ダウンロードしておく.
(もし確認を忘れたら,新しいキーを発行すれば良い.それは割愛する)

得たアクセスキーとシークレットキーにawscliに設定
~/.local/bin/aws
へ設定を付与する.
Tokyo regionはap-northeast-1.
aws configure
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: ap-northeast-1
Default output format [None]: json
設定がうまくできていれば,バケット一覧(aws s3 ls
)が見れるし,バケット内(aws s3 ls s3://BUCKETNAME
)も見れる.
下の例はindex.html
を置いてみた後の実行結果.
aws s3 ls
2018-07-01 15:42:56 tmp.hadacchi.com
aws s3 ls s3://tmp.hadacchi.com
2018-07-01 15:44:17 3417 index.html
コンテンツアップロード
サイト内コンテンツへのリンクを相対パスで書いていれば,今のpublic_html
以下をそのまんまputすれば静的コンテンツだけは動く.
下のコマンドの例では,public_html
というディレクトリは作成されない.(public_html/index.html
はs3://tmp.hadacchi.com/index.html
になる)
※注意: 以下のコマンドラインでアップロードしたところで,phpは動作しないので,当然ながらwordpressも動作しない.
aws s3 cp --recursive public_html s3://tmp.hadacchi.com
web公開設定の確認
文献[2]に記載の通りs3 website hosting
のエンドポイントに書かれたURLへアクセスすれば,静的コンテンツであれば表示されるはず.
更に自分のDNSレコードをCNAMEでこのエンドポイントのFQDNに転送すれば,独自ドメインで引ける.この時,バケット名が独自ドメインと合致してないとエラーが出る.
[1]の通りなんだけど,nginxを使っていると.htaccessを使ったrewriteが走らないためpermalinkの設定が反映されずハマる.
permalinkの設定反映
個人的にurlにはコンテンツに関する情報が入って欲しくないので,idで設定する.
%post_id%.html
でOK

nginxの設定ファイルでrewriteを記述
[3]の方法でphp-fpmにpathを送ってあげれば良くて,重要なのは以下に改変して抜粋したこの部分.
なぜか我が家の環境では最後の1行だけで動作する.
if (!-e $request_filename) {
#rewrite ^.+?(/wp-.*) $1 last; # ←なくても動く
#rewrite ^.+?(/.*\.php)$ $1 last; # ←なくても動く
rewrite ^ /wp_blog/index.php last;
}
timeout値の変更
次の手順のstaticpressのrebuildでタイムアウトによりエラー停止することがあるので,事前に伸ばしておく.
だいたい500sで私はうまくいった.
設定場所は上のrewriteを追記したserverディレクティブの中で,php-fpmを呼び出しているところ.
location ~ \.php$ {
# With php5-fpm:
+ fastcgi_read_timeout 500s;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
staticpressのbasic認証のところを改変
もし,wordpress本体側にBASIC認証をかける場合,staticpressのBASIC認証周りはバグ(?)で設定ページでどれだけBASIC認証情報を入れてもDBにその情報を記録してくれないので,ハードコードするかDBに書き込んでおくかしなければならない.
方法は文献[[4]](#cite4)を参照.
ハードコードするとすげー早くなったので,ハードコードオススメ.
--- class-static_press_admin.php.org
+++ class-static_press_admin.php
@@ -56,7 +56,8 @@
}
static public function basic_auth(){
- return get_option(self::OPTION_STATIC_BASIC, false);
+ //return get_option(self::OPTION_STATIC_BASIC, false);
+ return "XXXXXXXXXXXXXXXXXXX";
}
static public function timeout() {
XXXXXXXXXXX
は「ID:PW」なる文字列をbase64にかけたもの.
以下で得られる文字列である.(python2.Xの場合は,.encode('ascii')
はいらない.)
>>> import base64
>>> print(base64.b64encode('hoge:fuga'.encode('ascii')))
b'aG9nZTpmdWdh'
staticpressでbuild
staticpress optionから設定.
Static URLはs3でアクセスするためのドメインtmp.hadacchi.com
としておく.その下のパス名は,s3にアップロードする時のディレクトリ名を指定すれば良いので,ルートに置く場合はなくても良い.
SaveDIRはstaticpressがdumpするhtmlの格納先のディレクトリ名で,ubuntuの場合はwww-dataに書き込み権限がないとエラーとなる.

あとは,staticpressのRebuildボタンで生成されるのを数分まつ.

アップロード
fromで指定したディレクトリの下のファイルを,toで指定したディレクトリの直下に置く,と覚えておく.
aws s3 cp --recursive /home/hoge/public_html/wp_blog/static/wp_blog s3://tmp.hadacchi.com/wp_blog
DNSの設定(S3を直接指定)
S3のwebhostingのエンドポイントを確認する.
エンドポイントのアドレスで,まずコンテンツが表示されるはず.(内部リンクはつながらないけど)

次に,DNSでこのエンドポイントに飛ぶよう CNAME を設定する.bindを例にすると,こんな感じ.
末尾のピリオドを忘れるとgTLDとか親レベルのドメイン名(ここではhadacchi.com)が勝手に補完されるので注意.
tmp IN CNAME tmp.hadacchi.com.s3-website-ap-northeast-1.amazonaws.com.
この時点で,DNSの設定をCNAMEでwebページは表示されるようになっているはず.
証明書の作成 (Certificate Manager)
CloudFrontの設定といいつつ,Certificate Managerで証明書を先に作る.
ここでのハマりポイントは認証.
DNSの認証の場合,レジストラのDNSサービスに乗っている人だと,レジストラの設定ページに依存するので各自で当該サービスに問い合わされたい.

ここで上の「DNSの認証」を選択すると,このようなCNAMEの設定をDNSに加えることが求められる.

これを設定しようと思うと,以下に相当する設定をレジストラのDNS設定ページから登録する必要がある.
各FQDNの最後のピリオドを忘れると,gLTD(ここではhadacchi.com)が補完されるので注意.
_15370fbba1c4b1cadb21f882e5078517.tmp IN CNAME _39dc4142a943daade594b688b198dfc5.acm-validations.aws.
; または
_15370fbba1c4b1cadb21f882e5078517.tmp.hadacchi.com. IN CNAME _39dc4142a943daade594b688b198dfc5.acm-validations.aws.
Eメールの場合,admin@,webmaster@,postmaster@などよくあるユーザ名にメールが送付されてくるので,それらメールで受け取った情報から認証する.
こちらの場合,MXレコードを設定しメールを受けられるようにしていないとうまくいかない.
いずれの方法を取るにせよ,ドメイン管理ができていれば大丈夫なはずなので,ここでは認証できたものとする.
Certificate Managerで認証が通って証明書が発行されると,CloudFrontの設定の途中で独自ドメインのSSLを参照できる.
CloudFrontの設定
CloudFrontのサービスページから「Create Distribution」をクリックしコンテンツ配信設定を作る.
続いて「Web」の方のGetStartedから開始する.
その次の画面で設定するのは,多分赤枠のところくらい.
「Origin Domain Name」に入力しようとするとドロップダウンリストでS3の公開設定されているリソースなどが表示されるので,該当のものを選ぶ.
「Viewer Protocol Policy」はお好みで.私は「Redirect HTTP to HTTPS」が好みだけど,今は実験的に「HTTP and HTTPS」にしている.

下へスクロールして続き.
「Alternate Domain Names」に独自ドメイン名を入れる.
「SSL Certificate」で「Custom SSL Certificate」を選択すると,その下の入力ボックスにお待ちかねの上(Certificate Managerの設定)で発行した証明書が入るので,Alternate Domain Namesと合うものを選択する.
すぐ下のCustom SSL Client SupportはSNIのみにしておかないと鬼のような請求が来るので注意.
世界各地のClourFrontのエッジの固定IPを占有するんだろうから,仕方ないけど.

更にスクロールして,設定するのはTSLやHTTPのバージョンくらいか.
Security Policyは,私の周りではTLSv1.2のみで何の問題も起きてないけど,古いブラウザや設定に対応したいならTLSv1.1とかv1でないとダメかも.
Supported HTTP Versionsは,もともと個人サイトでSSLを導入するモチベーションはHTTP/2による転送の高速化くらいだと思うんで,HTTP/2を選べば良いと思う.

DNSの設定(CloudFront)
CloudFrontのWebコンソールに「Domain Name」という列がある.これがCloudFrontのエッジを指定する時のSNIによるドメイン名(FQDN)であるので,自分の独自ドメインからCNAMEでこのFQDNを指すように設定してやれば良い.
設定の方法は,Certificate Managerの設定を参照されたい.
配信
以上を設定して「Create Distribution」を押せば完了だが,この設定をエッジに配布するのに15分くらいかかる.
また,15分経過するとAWSのコンソール上でStatusがProceedからDeployedになるが,実際にhttpアクセスが通るまでにもう少しかかる印象.
そのため,これまでの手順に漏れやミスがあってもCloudFrontの設定配信が切り分けのボトルネックになる.
以上のことから,まずはCloudFrontなしで全てのページが表示されることを確認した上で,CloudFrontの設定を行なうのが良い.
参考文献
[1] WordPress + StaticPress S3で静的WebサイトをS3でホストする - Qiita
[2] 独自ドメインを使ってAmazon S3で静的Webサイトをホストする - Qiita
[3] nginx で WordPress のパーマリンク設定を使用する - 暇人じゃない
[4] StaticPressとS3で爆速で激安な静的サイトを作ろう