【AWS】サーバレスで堅牢な静的ウェブサイト運用（独自ドメイン + https通信）


# はじめに

個人のポートフォリオページなどを作って公開するとき、サーバ管理に手間をかけたくない。
とはいえ、あまりにもお粗末な環境で配信するのも気が引ける。
AWSのサーバレスサービスで手軽に、かつ "ちゃんとした" 配信環境を整備する手順をまとめる。

サンプルコード↓

https://github.com/uni-ezobafun/ocean_static_website_hosting

### サーバレスでウェブサイトを運用するメリット

* サーバ負荷を気にしなくて良い
* SSLサーバ証明書を勝手に更新してくれる
* AWSは言わずもがな堅牢

要するに、最初と更新時だけ気にかけてやれば、あとはAWSに丸投げして放置できる。



### やること

* ポートフォリオページなど、静的なウェブサイトを運用する環境をつくる
* 手間は最小限に、"ちゃんとした" 配信環境をつくる（独自ドメイン + https通信）
* AWSのS3、CloudFront、CertificateManagerを使う



### 前提

* 取得済の独自ドメイン (本ページでは、[MuuMuuドメイン](https://muumuu-domain.com/)で契約したもの)



# もくじ

1. S3 bucketにhtmlファイルを配置する
* CloudFrontとS3を接続する
* CloudFrontと独自ドメインを接続する
* [option] エラー時に返すファイルを設定する

# 1. S3 bucketにhtmlファイルを配置する

### 1-1. S3 bucketを新規作成する
S3のコンソールを開いたら、画面右上のCreate bucketをクリック
![Screen Shot 2021-01-24 at 17.50.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/eedac797-8e16-9dae-b1ed-6bc810d40063.png)

① 適当なBucket nameを入力する。
② (CloudFrontを介さない) S3への直接アクセスは全て遮断する。
![Screen Shot 2021-01-30 at 17.06.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/087d3d53-a2fe-79e7-7ec2-14f7c756d7d0.png)

他の項目はご自由に。
画面右下のCreate bucketを押して完了。
![Screen Shot 2021-01-30 at 17.06.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/274fdd31-37de-aee0-d8e1-93fb2a56fba8.png)

### 1-2. S3 bucketにファイルをアップロードする

作成されたbucketを開いて、Uploadを押す。

![Screen Shot 2021-01-30 at 17.29.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/54f24c27-38d1-6ff9-7846-b1a979b277d3.png)

① Add files または Add folderでアップロードしたいファイルを選択する。
② Uploadボタンを押す。

![Screen Shot 2021-01-30 at 17.29.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/34bf6b0c-24cc-7a7e-757b-7e29322763d2.png)

必要なファイルが揃うまで、アップロードを繰り返す。
本ページでは、下記のようなファイル構造でS3 bucketのルートディレクトリに配置した。

```
assets/
├ css/ - default.css
└ img/ - image.png

index.html
```

![Screen Shot 2021-01-30 at 18.11.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/33e61411-19c4-3e3e-5c0b-049fef8b1d82.png)

これでS3の準備が整った。

# 2. CloudFrontとS3を接続する

### 2-1. CloudFront Distributionを新規作成する

CloudFrontのコンソールを開いたら、画面左上のCreate Distributionを押す。

![Screen Shot 2021-01-30 at 18.17.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/ecaf67d1-6b69-d411-c774-27124bdcc6e9.png)


① Origin Domain Nameには、先程新規作成したS3 bucketを設定する。
```${作成したbucket名}.s3.amazonaws.com```に名称が一致していることを確認する。
② CloudFrontからのみS3 bucketの中身を参照する権限の設定。
```Origin Access Identity```を新規発行して、S3 bucketのポリシーも勝手に書き換えてくれる。
③ http通信もhttps通信として解釈する設定。

![Screen Shot 2021-01-30 at 18.27.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/ee6324a7-c973-3d61-8320-a1c861929257.png)

④ 手順1-2でS3 bucketに配置したhtmlのファイル名を設定する。

⑤ 全て設定したら、画面右下のCreate Distributuionを押す。

![Screen Shot 2021-01-30 at 19.01.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/98b7f9ff-2f78-b746-42b9-fa8cb2802562.png)

はじめの画面に戻ると、新しいDistributionが一覧に加わっている。
Statusが```In Progress```から```Deployed```に変わったら、作成完了。

![Screen Shot 2021-01-30 at 18.45.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/869b7c5b-a56f-5ea6-702b-3465475ec50e.png)

### 2-2. CloudFrontからS3 bucketの中身を参照できるか確認する

作成されたDistributionを開いて、ドメイン名を確認する。

![Screen Shot 2021-01-30 at 19.18.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/043707ec-7787-bbc9-dc0a-e8b1495e8188.png)

確認したドメイン名をブラウザにコピペして、S3 bucketに配置したhtmlを参照できればok。
ファイルをS3 bucketに正しく配置できていれば、cssや画像も読める。

![Screen Shot 2021-01-30 at 19.22.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/0b0d60b8-e406-35a2-2980-d3aebad7ddc1.png)

これでCloudFrontとS3を接続できた。

# 3. CloudFrontと独自ドメインを接続する

本ページでは[MuuMuuドメイン](https://muumuu-domain.com/)で契約した```uni-ezobafun.com```をCloudFrontに紐付ける。

### 3-1. Certificate Managerで証明書発行をリクエストする

手順2-2と同じ画面で、左上にあるEditを押して、```Distribution Settings```を開く。

![Screen Shot 2021-01-30 at 21.15.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/c9b857b3-52b7-9fb7-7166-ba990ab85040.png)

画面中央の```Request or Import a Certificate with ACM```を押す。

![Screen Shot 2021-01-30 at 19.33.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/c59e9b1a-290e-83c5-5d33-e9895815c3e7.png)

画面の案内に従って、Domain nameは```*.${設定する独自ドメイン}```、Validation methodは```DNS```を設定する。
正しく設定するとReview画面に進むので、内容を確認したら```Confirm and request```を押す。

![Screen Shot 2021-01-30 at 19.41.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/2c50edd2-496a-329a-b93c-e4311744aa4b.png)

証明書の一覧ページからリクエストしたドメインの情報を開き、NameとValueをコピーしておく。

![Screen Shot 2021-01-30 at 21.06.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/98704907-c402-ee66-0595-eea22fc3ea33.png)

### 3-2. MuuMuuドメインに認証情報を登録する

画面左の```ムームーDNS```を押す。
CloudFrontに紐付けるドメインの```変更(利用する)```を押す。

![Screen Shot 2021-01-30 at 20.38.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/d52346e0-07e7-2971-bfa2-66a5bb77228e.png)

ここでは2行追加する。
種別はいずれもCNAMEを選択する

1行目では、手順3-1でコピーしておいたNameをサブドメイン欄に、Valueを内容欄にペーストする。
このとき下記の[ ]で示した部分 (2箇所) は省いてペーストする。

```
name 
_4c450f3c7930a5e76f5573d74a67fb2c[.uni-ezobafun.com.]

value
_0c7f35b87c9dcb9ac0a7d3df240fc2b1.vtqfhvjlcp.acm-validations.aws[.]
```


2行目では、任意の文字列をサブドメイン欄に、手順2-2で確認したCloudFrontのドメイン名を内容欄にペーストする。

```セットアップ情報変更``` を押して、変更を反映する。

![Screen Shot 2021-01-30 at 22.10.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/18d06c94-017a-e52f-d2f2-29a89a412dc5.png)


### 3-3. 証明書が発行されたことを確認する

しばらく待ってから右上の更新ボタンを押すと、Statusが```Issued```に変わる。

![Screen Shot 2021-01-30 at 21.13.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/956d2181-cb1c-eea1-9d7b-1d701af9707d.png)

### 3-4. 発行された証明書を使って、CloudFrontに独自ドメインを接続する

手順3-1と同様に```Distribution Settings```を開く。
CloudFrontに接続するドメイン名(手順3-2で設定したサブドメインを先頭に付与したもの)を```Alternate Domain Names```に設定する。
```SSL Certificate```は```Custom SSL Certificate```とし、手順3-3で発行した証明書を選択する。
画面右下の```Yes, Edit```を押すと、DistributionのStatusが再び```In Progress```になるため、```Deployed```になるまで待つ。

![Screen Shot 2021-01-30 at 21.58.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/efc3abd6-6d23-6e5f-27b6-b4eaa650a0b0.png)

設定したドメイン名をブラウザにコピペして、S3 bucketに配置したhtmlを参照できればok。

![Screen Shot 2021-01-30 at 22.20.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/bff82f06-51cd-07dd-0cfd-2d35c5100939.png)

これでCloudFrontと独自ドメインを接続できた。

# 4. [option] エラー時に返すファイルを設定する

### 4-1. エラー時に返すファイルをS3 bucketにアップロードする

error.htmlをS3 bucketのルートディレクトリに配置する。

```
assets/
├ css/ - default.css
└ img/ - image.png

index.html
error.html
```
### 4-2. CloudFrontでエラー時に返すファイルを指定する

Distributionを開いて、```Error Pages```タブから、```Create Custom Error Response```を押す。

![Screen Shot 2021-01-30 at 22.49.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/cc5ac858-3efc-86b1-30db-501fd6653c29.png)

下記は内部で403エラーだった時、一律でerror.htmlを返し、404エラーとしてレスポンスする例。

![Screen Shot 2021-01-30 at 22.50.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050582/a3e94ecd-44f4-d4f4-5924-6f5012a7aff4.png)

その他、好みの組み合わせにて。

# トラブルシュート

### S3のファイルを更新しても変更が反映されない
まずはブラウザのキャッシュをクリアしてみる。
それでも変更が反映されなければ、CloudFrontのキャッシュをクリアする。

### エラーページでcssや画像を読み込めない
cssファイルや画像ファイルの参照先を相対パスで指定していると、エラーページから読み込めない。
error.htmlを配置したパスではなく、リクエストされたパスを起点にして参照してしまうのが原因。
ルートパスで参照先を指定すれば解決する。

### リクエストURLからindex.htmlを省略できない
手順3-4では、```https://welcome.uni-ezobafun.com```の末尾で```/index.html```を指定しなくても、暗黙的にS3 bucketのルートディレクトリに配置したindex.htmlを参照できた。
ルートディレクトリ以外に配置した他のファイルも```/index.html```を省略したリクエストURLで参照したいところだが、結論から言うと本ページの方法では実現できない。
手順2-1で設定したCloudFrontの```Default Root Object```が、各Originのルートディレクトリ以外には適用されないのが原因。
解決策としては、参照するページごとに別のS3 bucketを作成するか、S3の```Static website hosting```を使うことになる。
前者はファイル管理が面倒そうな点、後者はCloudFrontを通さない通信を許容してしまう点がデメリット。

# 参考

### 公式ドキュメント
https://aws.amazon.com/premiumsupport/knowledge-center/cloudfront-serve-static-website/
https://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteEndpoints.html#WebsiteRestEndpointDiff