Route53 + Cloud Front + S3 でWebサイトを構築する

# はじめに
サーバーレスで静的ウェブサイトを構築する機会がありましたので、
備忘録も兼ねて手順等についてまとめたいと思います。
AWSでWebサイトの構築を考えている人の参考になれば幸いです。

# アーキテクチャー
Cloud Front + S3 で 静的ウェブサイトを構築する場合、主に2つの方法があります。
今回は、Cloud FrontとS3間の接続にSSLを利用したかったので、①を採用しました。

① S3のREST API エンドポイントを使用する + Cloud FrontのOAIでアクセス制限する
② S3のウェブサイトエンドポイントを使用する

S3のウェブサイトエンドポイントとREST APIエンドポイントの主な違いは、下表の通りです。
※「[ウェブサイトエンドポイントと REST API エンドポイントの主な違い](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/WebsiteEndpoints.html#WebsiteRestEndpointDiff) 」より一部抜粋。

|項目|REST API<br>エンドポイント　　|ウェブサイト<br>エンドポイント　　　　　|
| :-- | :-- | :-- |
|サポートされるリクエスト|すべてのオペレーション|GETリクエスト<br>HEADリクエスト|
|エラーレスポンス形式|XML|HTML|
|リダイレクトのサポート|×|〇|
|SSLのサポート|〇|×|

上記以外にもREST APIエンドポイントを使用する場合、
Cloud Frontでデフォルトのルートオブジェクトを指定する際に、
Cloud Frontはサブディレクトリのルートオブジェクトを返すことができない等
細かな違いがあるので、実現したい要件に合わせて選択する必要があります。
※ [CloudFront がサブディレクトリからデフォルトのルートオブジェクトを返さないのはなぜですか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/cloudfront-default-root-object-subdirectory/)

# Webサイト構成
構築するWebサイトの全体構成について記載します。
　　<img width="600" alt="Webサイト構成.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689353/b676c679-7402-59da-6ef9-a47c1ca052b0.png">

各サービスの主な役割は、以下の通りです。

- Route53
Webサイトのドメイン名とCloud Frontを紐づけるDNSとして利用します。

- Cloud Front
WebサイトのS3バケットをオリジンとするディストリビューションを作成し、
Webサイトのコンテンツ配信を行います。
今回は、エラー発生時にエラーページを表示する機能等もCloud Frontで実現します。

- ACM
WebサイトのSSL証明書を管理します。
ACMでSSL証明書の発行 または SSL証明書をインポート してSSL証明書を登録します。 
登録方法などの詳細については割愛します。

- S3
WebサイトのHTML、JavaScript、CSS等のファイルを格納します。
S3バケットに対するパブリックアクセスは許可せず、Cloud FrontのOAIを利用して、
Cloud Front経由のアクセスだけを許可するようにします。

# Webサイト構築
それでは、Webサイトの構築を行っていきます。

## Amazon S3
S3バケットを作成して、ウェブサイトのコンテンツをアップロードします。
今回は、S3のREST APIエンドポイントを利用する為、
S3の静的ウェブホスティングは無効、ブロックパブリックアクセスはオンに設定します。

- パブリックアクセスをすべてブロック：オン
<img width="600" alt="S3設定①.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689353/f2889e2a-1b53-36fa-f65d-da002537dcd2.png">

- 静的ウェブホスティング：無効
<img width="600" alt="S3設定②.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689353/69d24b81-cdd1-c948-ed52-1e3012ebfd8d.png">

## Cloud Front
WebサイトのS3バケットをオリジンとするディストリビューションを作成します。
Cloud FrontのOAIを設定して、Cloud Front経由のアクセスだけを許可するよう
S3のバケットポリシーを更新します。

- S3 bucket access：use OAI
- Origin access identity：xxxxx（OAIを選択）
- Bucket Policy：update the bucket policy
<img width="600" alt="CloudFront設定①.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689353/f16200dc-ba13-44f9-5b7d-175815011335.png">

クライアントとCloud Front間の接続はSSLを利用する為、SSL証明書（※1）を選択します。
また、https\://sample.com へアクセスした場合（※2）に https\://sample.com/index.html を
返すようデフォルトのルートオブジェクトに"index.html"を設定します。

- Custom SSL certificate：xxxxx（SSL証明書を選択）
- Default root object：（例）index.html
<img width="600" alt="CloudFront設定②.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689353/89965b0c-fe53-fee7-2a07-669c7278cb17.png">

※1 ACMのSSL証明書は、バージニア北部のリージョンに登録する必要があります。
※2 デフォルトのルートオブジェクトを設定しない場合、エラーが応答されます。

ディストリビューションの作成が完了したら、エラーが発生した場合にエラーページを
返すようエラーページの設定を行います。
ディストリビューションの"Error pages"より、Custom error responseを設定します。

- HTTP error code：（例）403
- Customize error response：Yes
- Response page path：（例）error.html
- HTTP Response code：（例）403
<img width="600" alt="CloudFront設定③.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689353/0b519b67-5a38-80c1-6804-c0df1a67c706.png">

## Route53
Webサイトのドメイン名とCloud Frontを紐づけるALIASレコードを設定します。

- レコード名：ドメイン名
- レコードタイプ：Aレコード
- エイリアス：ON
- トラフィックのルーティング先：Cloud Front ディストリビューションへのエイリアス
<img width="600" alt="Route53設定①.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689353/658e2ad1-c2eb-ada9-30ca-dea03fac6511.png">

これで、Webサイトの構築は完了です。
ドメイン名にアクセスすればWebサイトが表示されるはずです。
Cloud Frontのディストリビューションのドメイン名からもアクセスできるので、
ドメイン名からアクセスできないときは試してみてください。

# さいごに
Webサイトを構築する場合、LightsailやEC2でWebサーバを立てる方法もありますが、
アクセス数が少なければ Route53 + Cloud Front + S3 の方がコストを安く収える
ことが出来る場合もあると思いますので、選択肢として考えてみてはどうでしょうか？