【AWS】WixのサイトをS3+CloudFront+Route 53に移行してみた|ハマった4つのポイント
こんにちは! ボンドバンドでインフラまわりを担当しているエンジニアです。 いま、自社のコーポレートサイトを Wix から AWS に引っ越している最中です。
「静的なサイトを S3 に置いて CloudFront で配信するだけでしょ?」
最初はそう思っていたんですが、実際に手を動かすと地味なところで何度も止まりました。
証明書が選択肢に出てこない、URL の最後にスラッシュを付けると 403 が返る……。
どれも調べれば分かる話なんですが、知らないと普通に30分くらい溶けます。 同じ構成を考えている方が同じところで止まらないように、つまずいた点を中心に残しておきますね。
そもそも、なんで Wix をやめたのか
先に言っておくと、Wix が悪いという話ではありません。エディタは分かりやすいし、公開までがとにかく速い。 サイトを立ち上げた当初は、これがベストな選択でした。
ただ、運用を続けるうちにこういうのが積もってきます。
- HTML / CSS を直接触れないので、細かい調整に手が届かない
- 変更履歴が Git に残らない。「これ誰がいつ変えたの?」が追えない
- 表示速度をチューニングしようにも、できることが限られる
- 更新してもしなくても月額は同じ
で、思い切って静的な HTML + Bootstrap で作り直すことにしました。 S3 に置いて CloudFront で配信すれば、普段のシステム開発と同じ流れ(ブランチ切って、レビューして、デプロイ)に乗せられます。 自分たちで直せる状態に戻す、というのが一番の動機でした。
構成はこれだけ
登場人物は4つだけです。シンプルですよね。
ブラウザ
↓ 名前解決(bondband.jp → CloudFront)
Route 53
↓
CloudFront ── ACM の証明書で HTTPS 終端/キャッシュ配信
↓ OAC で署名付きリクエスト
S3(パブリックアクセスはブロックしたまま)
ここから先が本題です。この4つをつなぐ途中で、見事に4回止まりました。
ハマり① S3 は公開しちゃダメ
「S3 に静的ウェブサイトホスティングって機能があるじゃん、これでいいのでは?」と最初は思いました。 でもこれ、HTTPS に対応していません。独自ドメインで https:// で配信したい時点で、CloudFront は必須になります。
だったら S3 のほうは公開しないほうがいい。CloudFront からだけ読めるようにします。 この仕組みが OAC(Origin Access Control)です。昔は OAI というものでしたが、今は OAC が推奨されています。
CloudFront 側でオリジンアクセスコントロールを作ると、必要なバケットポリシーをコンソールが出してくれます。こんな内容です。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipalReadOnly",
"Effect": "Allow",
"Principal": { "Service": "cloudfront.amazonaws.com" },
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<バケット名>/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::<アカウントID>:distribution/<ディストリビューションID>"
}
}
}
]
}
地味に大事なのが AWS:SourceArn の行です。ここで自分のディストリビューションに限定しています。
省略しても動いてしまうんですが、そうすると他人の CloudFront からも読めてしまうので、必ず入れてください。
バケットの「パブリックアクセスをすべてブロック」は、オンのままで大丈夫です。
ハマり② 証明書がプルダウンに出てこない
ACM で証明書を発行して、さあ CloudFront に設定しよう……と思ったら、プルダウンに何も出てこない。 発行済みになっているのに、です。しばらく画面をリロードし続けました。
CloudFront に使う ACM 証明書は、バージニア北部(us-east-1)で発行したものしか選べません。東京リージョンで作ったものは、そもそも一覧に出てきません。
ALB などで使う証明書とはリージョンが別になる、というのがポイントです。 リージョンを切り替えて発行し直し、DNS 検証用の CNAME を Route 53 に登録すれば、数分で発行済みになります。
あと、証明書を作るときは bondband.jp と www.bondband.jp のように、
使う予定のドメインをまとめて1枚に入れておくと後がラクです。あとから足せないので。
ハマり③ /blog/ を開くと 403
CloudFront の「デフォルトルートオブジェクト」に index.html を設定すれば、トップページは表示されます。
ところが /blog/ みたいなサブディレクトリを開くと 403。
理由はシンプルで、S3 に /blog/ という名前のオブジェクトは存在しないからです。
デフォルトルートオブジェクトの設定は、ルート(/)にしか効きません。ここ、勘違いしやすいところです。
解決策は、CloudFront Functions で URI を書き換えること。こんな関数をビューワーリクエストに紐づけます。
function handler(event) {
var request = event.request;
var uri = request.uri;
if (uri.endsWith('/')) {
// /blog/ → /blog/index.html
request.uri += 'index.html';
} else if (!uri.includes('.')) {
// /blog → /blog/index.html
request.uri += '/index.html';
}
return request;
}
Lambda@Edge を持ち出すほどの処理ではないので、CloudFront Functions で十分です。
当サイトのように about-1.html と拡張子付きのフラットな構成にしている間は、この関数がなくても動きます。ディレクトリ構成に変えた瞬間に必要になるので、「そのうち必要になるやつ」と覚えておくといいです。
ハマり④ 更新したのに画面が変わらない
CloudFront を挟むとサイトは速くなります。その代わり、「更新したのに画面が変わらない」が起きます。 キャッシュが効いているので当然なんですが、最初はブラウザのせいかと思ってスーパーリロードを連打しました。
静的サイトでは、ファイルの種類でキャッシュの扱いを分けるのが定番です。
| 対象 | キャッシュ | 更新の反映方法 |
|---|---|---|
| HTML | 短め | デプロイのたびに無効化する |
| CSS / JS | 長め | ファイル名かクエリでバージョンを変える |
| 画像・フォント | 長め | 差し替えるときにファイル名を変える |
当サイトでは、CSS の読み込みを assets/css/style.css?v=20260916a のようにクエリ付きで書いて、
更新のたびにこの値を変えています。原始的ですが、ビルド環境を持たない静的サイトではこれが一番確実でした。
デプロイは AWS CLI の2コマンドで終わります。
# サイトのファイルを同期(不要になったファイルは --delete で消す)
aws s3 sync . s3://<バケット名> --delete \
--exclude ".git/*" \
--exclude "README.md"
# CloudFront のキャッシュを消して、すぐ反映させる
aws cloudfront create-invalidation \
--distribution-id <ディストリビューションID> \
--paths "/*"
キャッシュ削除(Invalidation)は執筆時点で月1,000パスまで無料です。"/*" は1パス扱いなので普通の更新頻度なら問題ありませんが、CI から何度も叩くなら、変更したファイルのパスだけ指定するほうが安全です。
本番ドメインの切替は、ビビりながらやる
ここが一番緊張します。失敗すると、サイトが見られなくなりますからね。 次の順番でやると、だいぶ安心して進められます。
- まず CloudFront のドメインで全ページ確認。
dxxxxxxxx.cloudfront.netを開いて、リンク切れや画像の 403 を先に潰しておきます - 数日前に TTL を下げておく。3600秒のままだと、問題が起きたときの切り戻しにも1時間かかります。60〜300秒にしておくと安心です
- Route 53 のエイリアスレコードで向き先を変える。A(と AAAA)をエイリアスにして CloudFront を指定します。CNAME ではなくエイリアスなので、ドメイン直下でも設定できます
- しばらく旧サービスは解約しない。戻せる状態を残しておきます。ここは焦らないほうがいいです
あと忘れがちなのが 301 リダイレクト。旧サイトの URL 構造を変えるなら、旧 URL から新 URL へリダイレクトを入れておきましょう。 せっかく検索エンジンが評価してくれていた URL を、何もせず捨てるのはもったいないです。
で、いくらかかるの?
気になりますよね。この構成で課金されるのは、だいたい次の4か所です。
| サービス | 課金されるもの |
|---|---|
| S3 | 保存容量とリクエスト数。サイト1つ分ならごくわずか |
| CloudFront | データ転送量とリクエスト数。常時無料枠(月1TB・1,000万リクエスト)あり |
| Route 53 | ホストゾーンの月額と、クエリ数に応じた分 |
| ACM | パブリック証明書は無料 |
数万 PV くらいのコーポレートサイトなら、けっこうな部分が無料枠に収まります。 固定費として意識するのは、ドメインとホストゾーンくらい。 ただ料金体系は変わるので、見積もりは必ず AWS の公式料金ページと料金計算ツールで確認してくださいね。
まとめ
というわけで、今回ハマったのはこの4つでした。
- S3 は公開しない。OAC で CloudFront からだけ読ませる
- ACM の証明書は us-east-1 で発行する(東京で作ると出てこない)
- ディレクトリ構成にするなら CloudFront Functions で
index.htmlを補う - 切替前に TTL を下げて、CloudFront のドメインで検証してから DNS を向ける
やってみて一番よかったのは、移行そのものより「自分たちで直せる状態」になったことでした。 ちょっと直したいと思ったときに、その日のうちに直せる。これ、地味にストレスが減ります。
同じように Wix や他のサービスからの引っ越しを考えている方の参考になればうれしいです。
サイトやシステムの構成、ちょっと相談してみませんか
株式会社ボンドバンドは、業務システムの開発から AWS 上のインフラ構築・運用まで手がけています。 「今の構成のままでいいのかな?」くらいのご相談も歓迎です。
お問い合わせはこちら