AWS S3で静的Webページをホスティングする

## TL;DR

<a href="#%E6%89%8B%E9%A0%86">手順へスキップ</a>

下記の全てのステップをクリアすると、独自ドメイン+HTTP/2+apexドメインでの配信ができるようになります。

- **AWSのS3＋CloudFrontを使い、静的Webページをサーバレスで独自ルートドメイン（apexドメイン）上にホスティングする**
	- S3で静的Webページをホスティングする　←いまここ
	- S3の前段にCloudFrontを設置
	- 手持ちのドメインのネームサーバを Route 53 に向ける
	- 独自ドメインでCloudFrontを運用

## はじめに

上記のステップを全てクリアして、実際に運営している[Webサイトがこちら](https://ai-deep-kabu.com)です。
https://ai-deep-kabu.com


本記事では前述の通り、S3で静的Webページをホスティングする方法を紹介します。構成図は下記の通りです。
![hosting_by_S3.png](https://qiita-image-store.s3.amazonaws.com/0/28930/08cb3fd9-7306-982a-fc65-5fe80bd87dfb.png)


S3に独自ドメインを設定してホスティングする方法は紹介しません。S3に独自ドメインを設定したい場合は、下記の記事を参考にしてください。

- [独自ドメインを使ってAmazon S3で静的Webサイトをホストする](https://qiita.com/Ichiro_Tsuji/items/c174d580587a622d3358)
- [AWS S3バケットに独自ドメインを割り当てる。](https://qiita.com/kooohei/items/bdfe8ce3c3ef2af510ad)
- [Route53で設定したドメインにS3バケットを紐付ける](https://qiita.com/kkam0907/items/e5e5a91f25cf10e07322)


## S3 とは

Amazon S3とは、 `Amazon Simple Storage Service` の略です。容量無制限のファイル置き場（例えばNAS, Dropbox, Google Drive, OneDriveのようなもの）です。

アクセスできる人や対象を柔軟に指定することができ、以下のようなことができます。

- 作った人だけが変更・読み取りできる
- 作った人は変更・読み取りできるが、その他の指定した人は読み取りだけできる
- 作った人は変更・読み取りでき、その他全世界中からは読み取りだけできる

今回は上記のうち3番目の `作った人は変更・読み取りでき、その他全世界中からは読み取りだけできる` 権限を使用して、サーバレスでWebページをS3にホスティングしてもらい、Webサイトを作成します。

## メリット・デメリット

### メリット

- サーバレスなので、サーバのお守りが不要
	- apacheやらnginxやらで面倒を抱えなくて良い
	- サーバダウンからの復旧や監視やらはAmazonに任せて、コンテンツ作りに集中できる
    - AZ（コンテンツ配信拠点のようなもの）が1つダウンしても他の拠点で自動的に配信が継続する
- 安い（規模によるが）
	- 小規模ならレンタルサーバーを借りるより安い
	- https://aws.amazon.com/jp/s3/pricing/
- IAMでAPIアクセス可能
	- 自分でプログラムを組んで、自動更新することができる
		- 他のAWSサービスと連携させやすい
	- IAMで権限を厳密に絞ることができる
- 独自ルートドメイン（apexドメイン）で配信できる
	- これは Google Cloud Platform の Cloud Storage と比較してのメリットです
	- GCPでのS3に相当する[Cloud Storage](https://cloud.google.com/storage/?hl=ja)でも似たことはできますが、apexドメイン（例: `https://example.com` のように `www.` 無しのドメイン）で配信することができません
	- [Route 53](https://aws.amazon.com/jp/route53/) (AWSのDNSサービス)を使うと、エイリアスという仕組みでAレコードとAAAAレコードをCloudFrontやS3へ振り替えてくれるので、CNAMEを使わずともWebページへアクセスすることができます
	- この辺の仕組みは後日別記事にて詳しく掲載します

### デメリット

- サーバサイドスクリプトを動かすことができない
	- クライアントでJSを走らせることはできるので、APIサーバは別でホスティングして、クライアント側のスタティックファイルをS3でホスティングするのがよさそう
- 高頻度に追加・更新すると料金が高くなる（といってもそんなに大した額でもないですが…）
	- $0.0047 / 1,000回 （東京リージョン）
	- ＝$4.7 / 10万回
	- 1時間に1回追加・更新すると、30日で$0.03384/ファイル


## S3の用語説明

S3で使用される独特の用語をご紹介します。

- バケット
- バケットポリシー
- Static website hosting
- S3 Management Console


### バケット

バケットは英語で書くとBucketです。要はバケツです。様々なファイルを置いておくことができます。

### バケットポリシー

バケットには、それぞれ誰がどんなアクセス権限を持つか等を設定することができます。その権限情報を JSON で記述したものをバケットポリシーと呼びます。

### Static website hosting

日本語訳で「静的Webサイトホスティング」です（あまりかわらないですね）。

Webサイトが、PHPやRuby等サーバサイドでプログラムが動いた結果を表示させるのではなく、持っているHTMLファイルをそのまま表示させるのが `静的Webサイト` です。それをホスティングするので、 `静的Webサイトホスティング` となります。

### S3 Management Console

日本語訳で「S3 マネージメントコンソール」です。下記のURLでアクセスできるページで、S3の捜査を行う際の全ての出発点です。

あなたの管理下にある全てのバケットを一覧で見ることができます。作成やファイルのアップロードもここから行います。

https://s3.console.aws.amazon.com/s3/home?region=ap-northeast-1


## 手順

### バケットの作成

#### S3の Management Consoleを表示

まずバケットを作ります。`S3 Management Console` を表示。
https://s3.console.aws.amazon.com/s3/home?region=ap-northeast-1

続いて、 `バケットを作成する` を選択。
<img width="1075" alt="s3_01.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/f01453a7-0d1e-5e3a-1bce-fc4905754d7b.png">


#### `バケットの作成` ダイアログ（ `名前とリージョン` ）

 `バケット名` `リージョン` を入力して、 `次へ` ボタンを選択。
<img width="700" alt="s3_02.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/858cd581-5388-9e4b-8c13-781b00d4981b.png">


この時、 `バケット名` には以下の制限があるので注意してください。

- 全世界中のバケット名でユニーク（唯一）でないといけない
	- 「同名のバケットを別リージョンで作る」といったこともできません
	- なので、 `example` 等のよくある名前のバケットは作れない場合があります
- DNSとして有効な名前でなければならない
  - 基本的には英数字とハイフン `-` 、ピリオド `.` が使える
  - ただし、末尾に ハイフン、ピリオドは付けられない
  - 連続するピリオドもダメ
  - 使えない文字を入力すると教えてくれるので、あまり怖がる必要はない
 - 独自ドメインを使って、S3でWebサイトをホスティングするならば、FQDNとバケット名が一致する必要がある
	 - 日本語ドメインの場合、[Punycode](https://ja.wikipedia.org/wiki/Punycode)を使えば大丈夫だと思います（未検証）
	 - 参考: [独自ドメインを使ってAmazon S3で静的Webサイトをホストする](https://qiita.com/Ichiro_Tsuji/items/c174d580587a622d3358)

`リージョン` は、[選んだリージョンで若干料金が変わってきます](https://aws.amazon.com/jp/s3/pricing/)。この記事中では説明のためにすぐ消すので、一番日本から近そうかつ安い `米国西部（オレゴン）` を使用しています。

#### `バケットの作成` ダイアログ（ `プロパティの設定` ）

バージョニング（変更履歴）やアクセスログの設定を行えます。特に必要なければそのまま `次へ` を選択。
<img width="701" alt="s3_03.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/38ff27fd-fe21-9b53-043f-0ad4201ec773.png">



#### `バケットの作成` ダイアログ（ `アクセス許可の設定` ）

基本的にはそのまま `次へ` でOKです。
<img width="700" alt="s3_04.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/3510ec1e-dcd6-a8ed-35cc-434644c53c6e.png">


誰が編集や読み取りをできるかを設定します。ファイルを作った人が読み書きできて、それ以外のアクセスを拒否するならそのまま `次へ` を選択して大丈夫です。 `パブリックアクセス許可を管理する` という項目がありますが、 `Static website hosting` を使う場合でも、 `
このバケットにパブリック読み取りアクセス権限を付与しない (推奨)` でOKです。


#### `バケットの作成` ダイアログ（ `確認` ）

最終確認画面です。問題がなければ、 `バケットを作成` でバケットが作られます。
<img width="699" alt="s3_05.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/a6cc167f-c515-5d9b-83bb-53501a969c2e.png">


`バケット名` `リージョン` に誤りが無いか確認してください。一度バケットを作ると、そのバケットを削除するまで同名のバケットは作れません。前述の通り、この制限は全世界中のバケットで共有されています。

また、 `アクセス制限` の `ユーザー` が `1` になっているか確認してください。 `1` 以外であれば、自分以外にもアクセス権限を持っているユーザが存在することになります。誤って指定していないか、 `戻る` ボタンを選択して `アクセス許可の設定` で確認してください。


### ファイルのアップロード

#### 概要

`バケットを作成` すると、先ほどの `S3 Management Console` に今作成したバケットが表示されます。
<img width="970" alt="s3_06.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/84ac5ae7-6796-175a-2502-bcb9b7753fee.png">


バケット名をクリックし、バケットを開きましょう。
<img width="402" alt="s3_07.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/1baa1e7b-aa48-6de0-0ffe-6f1432f19036.png">


バケット内のファイルがリスト表示されます。まだ何もアップロードしておらず空っぽなので、今はアップロード済みファイルは表示されません。

次のステップでは、例としてブラウザで遊べるテトリスを設置してみます。

[github: ttencate/tis](https://github.com/ttencate/tis) (great thanks to Thomas ten Cate!)

まず、下記2つをダウンロードします。右クリックして、 `リンク先を別名で保存 （Chromeの場合）` で保存してください。

- [https://raw.githubusercontent.com/ttencate/tis/master/index.html](https://raw.githubusercontent.com/ttencate/tis/master/index.html)
- [https://raw.githubusercontent.com/ttencate/tis/master/tis.js](https://raw.githubusercontent.com/ttencate/tis/master/tis.js)

次のステップでは、これらをS3へアップロードします。


#### `アップロード` ダイアログ（ `ファイルの選択` ）

 `アップロード` を押してください。
<img width="1031" alt="s3_08.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/a818b779-56aa-068f-72b1-935a616cf059.png">


`アップロード` ダイアログが表示されます。ファイルやフォルダをドラッグ&ドロップでアップロードできます。または、 `ファイルを追加` ボタンを押せばアップロードするファイルを選択するダイアログが開きます。

アップロードするファイルを選択したら `次へ` を選択。
<img width="702" alt="s3_09.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/1769d840-e32c-d10e-9ade-b764459928a0.png">



#### `アップロード` ダイアログ（ `アクセス許可を設定する` ）

この画面は特に設定不要で、そのまま `次へ` を選択。
<img width="701" alt="s3_10.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/529b3f1e-bf3e-1ca0-931d-29d66afbe3ee.png">


#### `アップロード` ダイアログ（ `アクセス許可を設定する` ）

この画面も特に設定不要で、そのまま `次へ` を選択。
<img width="699" alt="s3_11.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/c3b83908-1bd8-4b3c-53c8-cab00698ea67.png">



#### `アップロード` ダイアログ（ `確認` ）

確認画面です。 `アップロード` を選択。
<img width="699" alt="s3_12.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/2d52b06d-b901-c0ca-f427-f30ad54e561a.png">


#### アップロード完了

ファイルリストに `index.html` `tis.js` が表示されていればOKです。表示されない場合はブラウザの再読み込みをしてみましょう。
<img width="961" alt="s3_13.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/127289ba-3ca2-1721-8c56-43d437966d36.png">


### S3で静的Webページをホスティングする

#### `Static website hosting` の有効化

いよいよ本題です。バケット内のファイルリストが表示されている画面で `プロパティ` タブを選択。
<img width="965" alt="s3_14.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/6e551233-6a18-ef5e-7106-cce21fa2481a.png">


`Static website hosting` を選択。
<img width="726" alt="s3_15.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/ae946cff-dc8e-c383-10b6-1911bf71862f.png">


`このバケットを使用してウェブサイトをホストする` を選択、 `インデックスドキュメント` は `index.html` と入力。その後、 `保存` を選択。
<img width="553" alt="s3_16.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/172ea45c-13cb-2694-6416-c870586f93b6.png">


`Static website hosting` にチェックが入っていればOKです。
<img width="321" alt="s3_17.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/3ec985f1-37b8-3add-2e8c-ef392c8838c7.png">



#### `バケットポリシー` の設定

続いて `バケットポリシー` を設定します。 `アクセス権限` タブを選択。
<img width="696" alt="s3_18.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/0299bb50-eab1-fda8-8c3b-2ee7a9b50108.png">


`バケットポリシー` を選択。
<img width="739" alt="s3_19.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/bed3d4ae-5c19-4cfd-42b2-6601b4f493a4.png">


`バケットポリシーエディター` が表示されます。
<img width="929" alt="s3_20.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/5732f35f-83b2-34e0-a5c4-f4c0962ef820.png">

ここに以下を入力。

```json
{
   "Version":"2012-10-17",
   "Statement":[{
 	"Sid":"PublicReadForGetBucketObjects",
         "Effect":"Allow",
 	  "Principal": "*",
       "Action":["s3:GetObject"],
       "Resource":["arn:aws:s3:::【ここをバケット名に置換】/*"
       ]
     }
   ]
 }
```

> 例: 静的ウェブサイトをセットアップする - Amazon Simple Storage Service
> https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/HostingWebsiteOnS3Setup.html
> より引用、「【】」内は筆者による編集（2018/02/11 17:14 アクセス）

 `【ここをバケット名に置換】` の部分は、実際のバケット名に置換してください。私の例だと、 `dogwood008-example` というバケット名で作ったので、以下のようになります。
`"Resource":["arn:aws:s3:::dogwood008-example/*"`

`バケットポリシーエディター` に `バケットポリシー` を入力したら、 `保存` を選択。
<img width="918" alt="s3_21.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/4bd11036-422d-c151-74a2-677a677ab696.png">


うまく設定できていれば、めちゃくちゃ怖そうな警告が表示されます。これは、「あなたのファイルがインターネット上のどこからでも見える状態になっているので注意してね」という意味です。今回の目的は、Webサイトとしてどこからでも誰からでも見られるようにしたいので、この警告は無視して大丈夫です。
<img width="957" alt="s3_22.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/cc5a8465-50a9-fb73-5ff9-5caebc763307.png">


最後に `プロパティ` タブ→ `Static website hosting` を選択して、再度設定画面を表示してください。ここに `エンドポイント` が表示されます。これがインターネット上に公開されたURLです。クリックしてみましょう（ <font color="red">**音が鳴るので気をつけてください**</font> ）。
<img width="684" alt="s3_23.png" src="https://qiita-image-store.s3.amazonaws.com/0/28930/35eb1439-4e5a-cc39-c536-f305fbd98bff.png">


無事、テトリスが表示されて遊べるようになりました。
十字キーとスペースで動きます。
![s3_24.png](https://qiita-image-store.s3.amazonaws.com/0/28930/e321f60a-a5e6-6b83-8402-ab5bd8d7a416.png)


今回生成されたURLは次の通りです。
http://dogwood008-example.s3-website-us-west-2.amazonaws.com

これは `http://【バケット名】.s3-website-【リージョン名】.amazonaws.com/` となっています。 `https` でアクセスすることは残念ながらできないので、コンテンツによっては `混在コンテンツ (mixed content)` の問題があります。

なお、Static website hostingを有効にしなければ `https` でアクセスすることもできるようです。詳しくは [S3のSSL通信
](https://qiita.com/Yuhkih/items/1754ac9caf3f12d75946) を参照ください。

## おわりに

上で述べたmixed contentの問題は、S3の前段にCloudFrontを置くと `https` でアクセスできるようになり解決します。

その他、HTTP/2 で配信できるようになるので、速度の向上も見込めます。他にもIPv6に対応するなど、色々と柔軟にカスタムできます。


---


本記事の内容が少しでも参考になれば幸いです。「いいね」をいただけると筆者の励みになります :pray: 

また、 @dogwood008 からフォローしていただけると、最新の投稿記事をお知らせできます。

[ブログ ( http://blog.dogwood008.com/ )](http://blog.dogwood008.com/)もやっておりますので、よろしければ是非ご覧ください。