ワンダウォールのWeb構築レギュレーションはこれだ(というものを考え中)
WebサーバーのSSL化(ELBをやめてCloudFrontへ)
WebサーバーのSSL化、これは個人的には必須だと思っている。GoogleはSSL化されたWebサイトの順位を優遇するSEO施策を行なっているし、AppleはATS(App Transport Security)という考えに基づき、iOSアプリケーションがSSL化されていないサイトやサーバーにアクセスするのに制限をかけつつある。GoogleはWebから、AppleはAppから世界中のSSL化を進めようとしているという構図だ。
しかしSSL対応のためには証明書の購入が必要になる。最近は安くなってきたとはいえ、1FQDNあたり年間1,000円ほどかかる。wonderwall.netは3つほどサブドメインを切っているので年間3,000円のコスト。まぁ安いと言えば安いけど、設定したり更新したりする手間を考えるとフリーハンドに越したことはない。
そこで、AWSで簡単にSSL/TLS証明書を発行できるAWS Certificate Managerを使うことにした。これなら証明書発行は無料だし、Amazonが発行しているということで証明書の信頼性も高い。ただ落とし穴があり、AWSのWebサーバーであるEC2には証明書をアタッチできず、ELB(ロードバランサー)とCloudFront(コンテンツ配信ネットワーク)だけとなる。
先月はELBに証明書をアタッチして運用してみた。そもそもそんなにアクセス負荷が高くないサイトなので、単純にhttps://でアクセス可能にするためだけの処置なわけだが、ELBは$0.027/h(月額$19.4)のコストがかかる。証明書発行だけなら年間3,000円(3FQDN)に対して、ELBは月に2,000円強。まったく割に合わなかった。
そこで、もうひとつの選択肢であるCloudFrontに切り替えてみた。CloudFrontは時間単位ではなく転送量とリクエスト数で料金が決まる。ELBとの比較は一概にできないが、たぶんうちのサーバーであれば月に$1.65くらい? 年間20ドル弱なのでELBの12分の1だし、FQDNが2つを超える場合は証明書もこちらの方が安い。
これで対ELBで毎月$17ドルほど、コスト削減。
CloudFrontの各種設定
CloudFrontには他にもメリットがある。世界中にあるAmazonのエッジサーバーにコンテンツがキャッシュされ、アクセスされるとユーザーの一番近くにあるエッジサーバーに誘導されるため、Webサーバーがt2.microと低性能なものであっても、Webの表示スピードは高速化する。また、wonderwall.net の実サーバーはエッジサーバーの奥に隠蔽されるので、DDoS攻撃を受けにくくなるなどのメリットもある。
では簡単にCloudFrontの設定を説明する。WordPressなどWebコンソールが起動している場合、それらへのアクセスはエッジサーバーを経由しないように設定しなければならないので、そこが話のポイント。
1) General
ここは普通に設定する。「デリバリーメソッド(Delivery Method)」はWebにし、ACMで生成した証明書を設定する。
2) Origin
エッジサーバーがアクセスするWebサーバーの設定では、Origin Domain Nameの欄にEC2のパブリックDNS (ec2-で始まるアドレス)を入力。エッジサーバーはHTTPSのアクセスを受け付けるが、AWS内部におけるエッジからWebサーバーへのアクセスは従来どおりHTTPとなるので、Origin Protocol Policyの欄はHTTP Onlyとする。
3) Behavior
Webサーバーのコンテンツ・ディレクトリーごとに振る舞い(Behavior)を個別設定していく。Viewer Protocol Policyはユーザーからアクセスされる際のプロトコルを設定する。URLにhttp://と書かれても自動的にhttps://にリダイレクトしてほしいので「Redirect HTTP to HTTPS」に設定。
一方、WordPressコンソールが稼働するURLパスである wp-admin/* 以下がキャッシュを通るを避けるためにhttpもhttpsも許容。TTL(Time to live)も0秒に設定しておく。
続いてCache Based on Selected Request HeadersはNoneに。Query String Forwarding and Cachingはすべてフォワードするように。この設定でWordPressコンソールにアクセスできる…はずだがどうにも上手くいかず、URLを叩くと大量のリダイレクトが発生してブラウザに怒られたり、それを解決してもCloudFrontからのエラーが表示されたり大変だった。
そこで、WordPressのwp-config.phpを以下のように書き換えた。以下の最初の行は、wp-config.phpの最後の行ということになる。
/* 編集が必要なのはここまでです ! WordPress でブログをお楽しみください。 */
/** Absolute path to the WordPress directory. */
if ( !defined('ABSPATH') )
define('ABSPATH', dirname(__FILE__) . '/');
define('FORCE_SSL_ADMIN', true);
$_SERVER['HTTPS']='on';
$_ENV[ "HTTPS" ] = 'on';
$_SERVER['HTTP_HOST'] = 'wonderwall.net';
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
/** Sets up WordPress vars and included files. */
require_once(ABSPATH . 'wp-settings.php');
これでようやくコンソールも起動したし、WebサイトのコンテンツはCloudFrontのキャッシュにヒットしするようになった。ブラウザのキャッシュが効かない状態で、以前は2秒ほどかかっていたはずのところ、CloudFrontのキャッシュが効くことで 秒にまで短縮された。サーバーは東京リージョンにあるが、海外でも速度向上されているのだろう。これによるコスト削減は、アクセスする側のユーザー体験に紐付くのでプライスレス。
なお、CloudFrontを使ったこの方法でWordPressを稼働させた際に、記事の投稿編集画面でビジュアル・エディターが表示されなくなることがある。WordPressはビジュアル・エディターを表示するための判定としてWebブラウザーのUser Agentを確認するが、この方法だとWordPressが認識するUser Agentが「CloudFront」になるため、通常の設定だとビジュアル・エディターが見えなくなる。
解決方法は、wp-includes/functions.php に下記のコードを追加する(場所は末尾とかでOK)。
function dtbaker_wp_cloudfront(){
add_filter('user_can_richedit','__return_true');
}
add_action( 'init', 'dtbaker_wp_cloudfront' , 9 );
コンテンツ・ファイルの定期バックアップ
以下のスクリプトをセットして、cronによる定期バックアップを行う。
#!/bin/sh
DATE=`date +%Y%m%d`
BACKUPDIR=/www-contents/backups
SUFFIX=PRODUCTION
tar cvzf ${BACKUPDIR}/$DATE-contents-$SUFFIX.tar.gz /www-contents/htdocs
mysqldump -u root -p7CXEpdvsexon --all-databases | gzip > ${BACKUPDIR}/$DATE-mysqldump-$SUFFIX.gz
cd ${BACKUPDIR}
DELDAY=`date --date '7 days ago' '+%Y%m%d'`
for LINE in `find -iname "*.gz"`
do
FILEDATE=`echo "$LINE" | sed -e 's/[^0-9]//g'`
if [ $DELDAY -gt $FILEDATE ] ; then
echo "delete $LINE"
rm -f $LINE
fi
done
このスクリプトによるバックアップ・ルールは次の通りとなっている。
- バックアップしたファイルは /www-contents/backups ディレクトリーに保存される。
- バックアップしたファイルはgzip形式で圧縮される。
- バックアップの間隔は1時間に1回で、同じ日付内でのバックアップの場合は上書き保存される。
- バックアップしたファイルは最長7日間保存され、7日を過ぎると自動削除。
- 自動バックアップのスケジュールは cron コマンドにて定義。
余談:t1.microからt2.microへの移行
4年前に立ち上げたサーバーなだけに、旧世代のt1.microインスタンスというのをずっと使ってきた。2014年夏にローンチされたt2の方が性能がアップしているしインスタンスの稼働コストも安い。東京リージョンの場合t1.microが$0.026/h(月額$18.7)に対してt2.microは$0.0152/h(月額$10.9)と、かなり安い(共に2017年12月時点の価格)。
しかし、t1とt2では仮想化の仕様が違うため、AWSお得意のWebコンソールでちゃちゃっと移行ってわけにはいかないのだ。具体的にはt1の仮想化技術であるPV (paravirtual)からt2のHVM (Hardware-assited VM)へ、コマンドラインでコツコツと変換する必要がある。
今動いているサーバー(CentOS+もろもろ)の状態をそのままにPVをHVMへ変換し、新たに用意したt2.micro(1年間の無料枠あり)インスタンスで起動し直すという作業を行うわけだが、Qiitaのこの記事がとてもよくまとまっているし、コマンドをコピペするだけで進められるので、とても助かった。
https://qiita.com/cs_sonar/items/21dbb3462708e146a426 とは言っても一発で完了するほど甘くはなく、最後まで操作しても新インスタンスは起動せず最初からやり直し。それでも起動せず…三度目の正直でようやくうまくいった。何が悪かったか判然としてないが、ここかな?と思える部分は以下の引用箇所。
ボリュームのサイズは既存のPV AMIのディスク以上であればOKです(同じでいいと思います。) 「同じでいい」という言葉に頼れば良かったのだが、既存のPV AMIのディスクよりも数GB盛って作って失敗。同じにしたら上手くいった。
作業には1日かかったが、これで毎月8ドルほどのコスト削減。本日は、これまで。