自分のウェブサイト( http://www.3qe.us/ )をCloudFront+S3構成からCloudflareを使った構成に乗り換えたので、ひっかかった点やつまづいた点などをメモしておく。
結論としては普通に移行できたが、メールとの兼ね合いでDNSまわりでちょっと配慮が必要な部分があるかも、といった具合。試したいときは全部読んでからチャレンジしよう。
ウェブサイトの静的配信にCloudFrontとS3を使っていた
ホームページといえば昔は雑にHTTPで配信していいみたいな時代もあったけれど、残念ながらもうそういう時代ではないので、基本的にHTTPSで通信を暗号化するのが普通という世の中。そういうわけなので、今まではコンテンツをS3に置き、HTTPS終端をCloudFrontにやらせるという立て付けでホームページを配信していた。
その他にも、DNSのCNAMEレコードを使って blog.3qe.us
(このブログだ) を設定したり、MXレコードを使ってメールの設定を行ったりしていた(図の通り)。
モチベーション: ALBのコストが高い
CloudFrontを使ったことがある人なら分かると思うけど、CloudFrontを経由してなにかをホスティングしたい場合、とにかくALBを接続してそこから別のオリジンにリダイレクトするといった構成になってしまう(今もそうしなければならないかは知らないが、自分が組んだときはそうなっていた)。
これは柔軟性を持たせるためにどうしても必要なのだろうけど、先日マネーフォワードで家計をチェックしているとAWSで5000円以上の費用が発生しており、そのコストのほとんどがALB関連のものだったので、ちょっと看過できない感じになっていた。
Cloudflare
そこで目をつけたのがCloudflareだった。最近CloudflareはS3互換APIを備えた安価なストレージサービスであるR2を提供していて、うまくやるとこれを静的配信できるのだ。なんか名前もちょうどS3を1つずらした形になっていて、当て付けっぽい。
自分はどちらかといえばエグレス料金よりもロードバランサの費用が気になっていたのだけれど、まあ安いのは良いこと。
そこで、今回はS3にホストしているデータを全部R2に移行して、HTTPS終端をCloudflareに載せ変えて、カスタムドメインに対応させるためにDNSまわりの設定を修正することにした。
構成
2023年現在、Cloudflareでコンテンツを直接ホストするにはいくつかの方法がある。
- Cloudflare Pagesを使う
- Cloudflare+ Denoflare + R2を使う
- R2のstatic hosting機能を直接使う
これらの手法には長短があって、今回は2番目のCloudflare+ Denoflare + R2の構成を採択した。どうしてこの手法を選んだかが明白になるように、各手法についての説明もしておこう。
Cloudflare Pages
CloudflareはPagesというサービスを展開している。これはGitHubなどで開発しているNext.jsといったフロントエンド寄りのコンテンツをホストしつつ、コミットごとのURLを作成してステージング環境的なものを構築したり、画像圧縮をやってもらったりという感じの高級なサービスだ。
これはこれで便利そうなのだが、自分はstaticなホームページをホストしたいだけなので今回は見送ることにした。また機会があったら使ってみたい。
Cloudflare+ Denoflare + R2
今回採用した構成はこれ。CloudflareにはWorkerという機能があり、飛んできたリクエストに対してエッジでちょっとした処理を行うといったことが可能なのだけれど、このWorkerにR2へのルーティングをやってもらうという手法。
そして、実際にWorkerを開発したりデプロイしたりするためのツールキットがDenoflare。
この方法は広く使われているようで、Denoflareの公式がサンプルページも用意している。
今回はこれにわずかに修正(後述)を加えた方法でホストした。
図にするとこういう構成になる。
修正
公式の手順に従うと、デフォルトでは/
といったパスへのアクセスには単にファイルリストが返される。古き良きApacheを思い出す挙動である。
今回は静的ウェブサイトの配信なので、/
へのアクセスは自動的に/index.html
へのアクセスということにしてほしい。
このような場合は、デプロイ時のflags
にemulatePages
を追加してやればよい(最後らへんで示す)。
R2のstatic hosting機能を直接使う
ちなみに去年の9月ごろに、R2はカスタムドメインでのパブリックアクセスができるようになっていた。
しかしながらR2単体ではどうやら前項で述べた/
を/index.html
扱いする機能は使えないようだった。したがって今回はR2単体での構成は見送ることにした。
手順
構成手順は基本的に以下のサイトに書かれている通りに操作したら完了した。
簡単に手順をなぞってみよう。
Webサイト追加
静的ホスティングをセットアップする前に、ダッシュボードからドメインを追加する必要がある。画面には「Webサイト」とあるが、実際はドメインごと登録しなければならない。
この過程でドメインに紐付いたネームサーバをCloudflareが提供するものに振り替える作業が必要になる。自分の環境の場合、AWS R53からCloudflareへの振り替えになった。
ちょっとここで問題があったのがDNSレコード。Cloudflareは気を利かせてくれるので、自動的に既存のレコードをインポートしてくれるのだが、この自動インポートが若干ガバっていて、MXレコードをなぜかAレコードに変換したりと、謎の変換をしてしまう。また、AWS上のCloudFrontを向けているレコードは、名前解決をしてIPアドレスベタ書きのAAAAレコードが生成されたりする。あまりあてにならないので、手でMXレコードを設定してやる必要がある。
また、デフォルトでは設定されたDNSレコードへのアクセスはCloudflareを通過してコンテンツをキャッシュする挙動になる。メールなどでそういう挙動をされては困るし何が起こるかわからないので、メールやはてなブログへのリダイレクト設定ではCloudflareを通過しない設定にする必要があった。
DNSレコードの書き換えが終わったら、最後にCloudflareが提供するネームサーバを自分のドメインと紐付けることになるが、当然まだR2側の設定はできていないので、一定時間アクセスできない期間が生じてしまう。その一方で、Dynoflareはネームサーバの振り替えが完了してCloudflare上のウェブサイトがアクティブ状態になっていないとデプロイを拒否する(!)ので、どのみちアクセス不能期間が生じてしまう。あきらめるしかない。
R2バケット作成
ここは特段困ることはなかったが、Cloudflare上のWebインターフェイスではディレクトリの削除やリネームができないという仕様で、間違えてアップロードするとAPIを使わない限りファイルを削除できないようだ。なのでリネームしてからアップロードするといった小技が必要になる。今回はS3からaws s3 sync
を使ってダウンロードしてきたものをアップしなおせばよいので、あまり困らなかったがいちおう覚えておくとよいだろう。
APIトークン作成
ここは手順通りにトークンを作成すればよかった。1Passwordとかに覚えさせておくとよい。
Denoflareでworkerをデプロイする
なんと、先程のトークンを使ってコマンドポチポチするだけでWorkerをデプロイできるのだ。すごい。Denoflareをインストールした状態で、以下のコマンドを叩いたらすぐドメインがR2と接続され、ウェブサイトが見られる状態になった。CloudflareがHTTPS終端もやってくれるので、もうこれで終わり。
$ denoflare push \ https://raw.githubusercontent.com/skymethod/denoflare/v0.5.6/examples/r2-public-read-worker/worker.ts \ --name ${ここに適当なWorkerの名前をつける} \ --r2-bucket-binding bucket:${ここにR2バケット名を入れる} \ --text-binding flags:listDirectories,emulatePages \ # emulatePagesをつけるのを忘れない --text-binding 'allowCorsOrigins:*' \ --custom-domain www.3qe.us \ --account-id ${アカウントID} \ --api-token ${APIトークン}
emulatePages
というフラグを付けることで、/
へのアクセスは自動的に/index.html
に変換されるようになる。
完了
これだけでカスタムドメインで静的ファイルを配信できるようになった。CloudflareがSSL証明書としてLet's Encryptのものを自動的に用意してくれるので、こちら側で設定する必要はない。本当にファイルとドメインがあればウェブサイトをホストできる。
まとめ
CloudFront+S3の構成からCloudflare+R2の構成にウェブサイトを移行できた。ALBの費用がまるっと吹き飛んだので、かなりコストが浮くのではないかと期待している。
その一方で、www
といったサブドメインだけCloudflareにNSレコードを使って委譲するといった設定はどうやら不可能なようで、完全にドメイン全体のホストゾーンをCloudflareに渡さなければならないのがちょっと違和感があった。サブドメイン単位でホストできれば便利なのだが、それができないのでMX
レコードの設定を書き直す必要があった。
余談ながら、AWSと比べてCloudflareの管理画面は非常に軽くてサクサク操作できたのが嬉しかった。AWSの画面重すぎるんだよな。
Cloudflare独自の機能を有効化できるのが面白くて、Under Attackモードを有効化するとDDoSなどを喰らっているときに強制的に認証を挟むモードが起動されたり、開発中の環境向けにキャッシュを無効化できたりするなど、CDN屋さんならではの便利機能が揃っている。
また、謎の広告ツイートボタンがあるのも良い。
私の Web サイトは、Cloudflare のおかげで処理可能なトラフィックが増加しました。 #cloudflare
— windymelt (@windymelt) 2023年1月14日
ボタンを押すと、きわめて簡素なツイートができる。
オチ
CloudflontのオリジンにS3バケット指定すればALB要らなさそう
— jun (@nahcnuj) 2023年1月14日
実はALB取り外せたらしい。マジかよ!まあいいか