Angular2をAWSのS3とCloudFrontでホスティングする

Angular2を使い始めたら、すぐAngular4がリリースされましたね。この世界の動きは早いですね:older_man_tone2:

今日はやっとAngular2をAWSでサーバレスでホスティングしてみました。方式も手順も難しくはないですが、すぐ忘れてしまいますので、いつも通りメモしたいと思います。

## AWSでホスティング


### Angular2とサーバの関係

Angular2はコンパイル後はindex.htmlとcss, javascriptのセットからなる、静的なコンテンツですので、Webサーバを選ばずホスティングできるようです。

### AWSで静的コンテンツをホスティングする

AWSの完全ガイドは[こちら](https://docs.aws.amazon.com/ja_jp/gettingstarted/latest/swh/website-hosting-intro.html)ですが、少々難しいので、端折りながら…

基本的には、

１. S3にコンテンツをアップロードする
２. CloudFrontで、S3のコンテンツを配信する
３. Route 53で、CloudFrontのホスト名に対して公開したいホスト名をエイリアスで付ける

という手順になるようです。

S3にRoute53でエイリアスを付けることも可能ですので、S3だけでもホスティングはできるのですが、S3はHTTPsに対応していないようです。そのため、今回の手順は（HTTPsに対応している）CloudFrontまで入れています。


## 実際の手順

### 1. S3での作業

AWSの公式ガイドは[こちら](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/website-hosting-custom-domain-walkthrough.html)です。

1-1. バケットを作成

バケット名は、ホストするサーバ名にします。
※ここではAWSの例通り、『example.com』とします。

1-2. 静的ウェブサイトホスティングを有効にする

バケットのプロパティタブで、上記の項目をクリックし、ラジオボタンで『有効にする』を選択します。

```aws:AWS入力欄
- インデックスドキュメント：index.html
- エラードキュメント:error.html
```

を入力して保存します。

Angular2を ng build コマンドでトランスパイルすると、index.htmlが生成されますので、インデックスドキュメントはそれを参照する形になります。error.htmlはAngular2では用意されませんので、自分でエラーページを作って、名前をerror.htmlにします。


1-3. アクセス許可で、バケットポリシーを作成する

バケットのプロパティタブで、上記の項目をクリックし、『バケットポリシーの編集』ボタンを押して、ダイアログに以下のポリシーJSONを貼り付けます。


```:ポリシー
{
  "Version":"2012-10-17",
  "Statement":[{
	"Sid":"AddPerm",
        "Effect":"Allow",
	  "Principal": "*",
      "Action":["s3:GetObject"],
      "Resource":["arn:aws:s3:::example.com/*"
      ]
    }
  ]
}
```
コロンの後ろに続く、『example.com』の記載は、ホストするサーバ名（バケット名）になります。


1-4. Angular2ファイルのアップロード

ng buildコマンドを実行し、生成されたコンテンツ（デフォルトでは、distフォルダ）の中の、全てのファイル（index.html, xx.buldle.js, xx.buldle.js.map）を作成したS3バケットにアップロードします。

独自に、favicon, error.htmlを作成している場合は、それも同じS3バケットにアップロードします。


1-5. S3でのホスティングの確認

プロパティタブ＞静的ウェブサイトホスティングで表示されるエンドポイントをクリックして、ブラウザに表示されれば成功です。

``` aws:エンドポイント例）
example.com.s3-website-ap-northeast-1.amazonaws.com
```

以上でS3での作業は完了です。



### 2. CloudFrontでの作業

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

まず、Web distributionを作成するボタンを押し、その後に以下を設定します。

- Origin Domain Nameに、S3バケットのエンドポイントを設定
- Viewer Protocol PolicyをRedirect HTTP to HTTPSに設定（任意）
- Allowed HTTP Methodsに、GET, HEAD, OPTIONSを設定（任意）※1
- Alternate Domain Names(CNAMEs)にRoute 53で設定するホスト名を設定
- SSL Certificateを、Custom SSL Certificateを設定（任意）※2
- Default Root Objectに『index.html』を設定 ※3

※1) CORSをする場合は、プリフライトリクエストに対応するためにOPTIONSを有効にする必要があります。
※2) CloudFrontのHTTPs化については、[こちら](https://blog.majimena.co.jp/tech/2016/03/31/aws-ssl.html)と[こちら](http://dev.classmethod.jp/cloud/aws/acm-cloudfront-ssl/)を参考にしました。
※3) デフォルトルートオブジェクトについては、[こちら](http://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/DefaultRootObject.html)の説明をご参照ください。


### 3. Route53の作業

DistoributionのDomain Name(例：dxxxxxxxx.cloudfront.net）を、ホスト名のエイリアスに設定すれば完了です。

``` aws:Route53入力例）
Name: example.com
Alias Target: dxxxxxxxx.cloudfront.net
```



## 参考）S3に対してRoute 53でホスト名を割り振る場合

HTTPsが必要ない場合には、CloudFrontまで使わずにS3だけでホスティングすることができます。

このとき、Route 53でエイリアスとして指定するのは、S3のwebホスティングを示すドメイン名部分です。面白いことに『example.com』のような固有値が必要ありません。

``` aws:Route53入力例）
Name: example.com
Alias Target: s3-website-ap-northeast-1.amazonaws.com
```


私も最初は『example.com』を付けたFQDN（example.com.s3-website-ap-northeast-1.amazonaws.com）を設定してハマりまして、[こちら](https://forums.aws.amazon.com/thread.jspa?threadID=132623)を参考にさせて頂いて上記の設定に気が付きました。

Route53でTargetが表示されない場合は、[こちらのページ](https://aws.amazon.com/jp/premiumsupport/knowledge-center/route-53-no-targets/)をご参考にしてみたら良いかもしれません。


以上です:grinning: