EC2のNodeサーバーと連携するReactクライアントをS3にデプロイ

AWS Summitに参加してからAWS関連でなんかしたいなあと思っていたので、
S3にReactで作ったクライアントを、EC2にNodeのサーバーを置いて、
簡単にアプリをデプロイしてみます:desktop:

以下の準備が整っていることを前提とします。
・Reactでクライアントアプリを作っており、これと連携しているサーバーサイドも作られている。
・EC2インスタンスを作成しており、sshでEC2に入れる。
・作成したEC2のセキュリティグループのインバウンドの設定でhttpによる接続を受け付けられるようにしておく(これは後で設定しても良いですが)。

# EC2にNodeで作ったサーバーを置く

まず、

1. git
2. nginx
3. pip3を使うためにpython3
4. pip3を使ってaws-cli
5. nodeのlts版

をインストールします。
Nodeサーバーの場合なので、他の言語で書いていたりしたらそれに合わせてください。

```shell
$ yum update -y
$ yum install git -y
$ yum install nginx -y
$ yum install python3 -y
$ pip3 install aws-cli
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
$ vim ~/.bash_profile
$ source ~/.bash_profile
$ nvm install --lts
$ nvm use --lts
$ node -v
```

.bash_profileには以下を書き込みます。

```.bash_profile
# /home/production/のところは個別に設定してください。アプリケーションのディレクトリを置くところとかでいいと思います。
export NVM_DIR="/home/production/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
```

次にサーバーのソースをクローンしてきます。
あと、nodeのプロセスを永続化するためにpm2を導入します。
pm2参考 => https://qiita.com/ikemura23/items/b3481393d4edca2d5188

```shell
$ git clone node-server
$ npm install -g pm2
$ cd node-server
$ pm2 start index.js --name node-server-on-ec2
```

EC2内で動いているサーバーにアクセスできるように、
外からやってきたhttpのリクエストをサーバーに転送してあげます。

ここで作ったindex.jsの設定ではlocalhost:3000をlistenしているので、
nginxでプロキシーの設定をして80番ポートにやってくるアクセスを3000番に転送します(localtion /を設定)。
nginxの設定参考 => https://qiita.com/morrr/items/7c97f0d2e46f7a8ec967
（プロキシーさせるためにもEC2へのhttpの接続をセキュリティグループで有効にしておくこと）

```shell
$ vim /etc/nginx/nginx.conf
```

```nginx.conf
server {
    listen       80 default_server;
    listen       [::]:80 default_server;
    server_name  _;
    root         /usr/share/nginx/html;

    # Load configuration files for the default server block.
    include /etc/nginx/default.d/*.conf;

    location / {
        proxy_pass http://localhost:3000;
    }

    error_page 404 /404.html;
        location = /40x.html {
    }

    error_page 500 502 503 504 /50x.html;
        location = /50x.html {
    }
}
```

これでec2のパブリックIPに接続すると、EC2内で動いているnodeサーバーにアクセスできます。
エラーが出る場合、pm2やnginxの再起動などを行ってください。
セキュリティグループの設定も忘れずに:information_desk_person:

とりあえずここまででサーバー側のアプリをEC2に設置して、パブリックIPでアクセスできるようになります。

# S3にReactで作ったクライアントを置く

### 1. バケット作成

S3でバケットを作成してください。
バケット名とリージョンを設定し、あとは基本的にデフォルトで良いです。
が、ブロックパブリックアクセスはオフにしておきます。

<img width="1338" alt="Screenshot 0031-07-21 at 12.36.35 PM.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245704/779fabc3-b420-ed81-f080-82e38ffa00da.png">


### 2. Static website hostingの設定

バケット作成後、Static website hostingを有効化するために、
Reactでbuildしたindex.htmlをインデックスドキュメントとして設定します。

<img width="578" alt="Screenshot 0031-07-21 at 12.37.28 PM.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245704/36ea84cc-107f-5fd8-74b9-247025badd8e.png">


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

```
{
    "Version":"2012-10-17",
    "Statement":[{
        "Sid":"PublicReadForGetBucketObjects",
        "Effect":"Allow",
        "Principal": "*",
        "Action":["s3:GetObject"],
        "Resource":["arn:aws:s3:::example-bucket/*"]
    }]
}
```
静的ウェブサイトをセットアップする => https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/HostingWebsiteOnS3Setup.html


### 4. IAMでアクセス権限を持ったユーザーを作成する

IAMに入ってサイドペインからユーザーを選択、ユーザーを追加ボタンでユーザーを作成します。

<img width="1010" alt="Screenshot 0031-07-21 at 1.14.05 PM.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245704/4a8dedf2-a204-c950-a542-320a3613fa48.png">

ユーザー名を設定し、プログラムによるアクセスにチェックを入れます。

次に、既存のポリシーを直接アタッチでs3のアクセス権を選択し、これを付与します。

<img width="1014" alt="Screenshot 0031-07-21 at 1.15.18 PM.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245704/5ec3557f-5d85-1e8b-fa9a-9395aa397fab.png">

ここではAmazonS3FullAccessを選びますが、セキュリティなども考慮すればReadOnlyAccessの方が良かったり、時と場合によっては何が良いかが別れると思うので、その都度使い分けてください。

後の項目は基本デフォルトで良いです。
ユーザーを作成すると、AccessKeyIdとSecretAccessKeyの情報が記載されたCSVができると思うので、
その中にあるそれぞれの文字列を次に利用していきます。


### 5. EC2内でaws configureを行う

先ほど取得したIAMユーザーのAccessKeyIdとSecretAccessKeyをEC2にインストールしたawsコマンドで有効化します。

```shell
$ aws configure
AWS Access Key ID     **************
AWS Secret Access Key     **************
Default region name    ap-northeast-1
Default output format     json
```

AccessKeyId, SecretAccessKey, region, output formatの入力を促されるので、それぞれ入力します。
output formatはjsonで良いです。


### 6. ReactでbuildしたファイルをS3にアップロード

ここまでできたらあとはbuildしたファイルたちをS3にアップロードするだけです。
Reactプロジェクトの中に入って、以下のコマンドを打ちます。
バケット名は自分ので埋めてください。

```shell
$ aws s3 sync ./build s3://{バケット名} --acl public-read
```

.DS_StoreとかがS3に入るのが嫌なら、以下のオプションを追加して省くこともできます。

```
--exclude '*.DS_Store'
```

また、今回はEC2でIAMユーザーを一つだけ設定したかったので、aws configureを使いましたが、
複数のIAMユーザーが必要なら、~/.awsの中にあるconfigファイルおよびcredentialファイルにそれぞれの情報を書き込みます。

[default]となっているプロファイル（IAMユーザー）はaws configureで設定したものと同じになるようです。
[profile_name]としてプロファイルを複数作成していけます。

```~/.aws/credentials
[default]
aws_access_key_id = XXXXXXXXXX
aws_secret_access_key = XXXXXXXXXX

[test]
aws_access_key_id = XXXXXXXXXX
aws_secret_access_key = XXXXXXXXXX
```

特定のIAMユーザーの権限でs3へアップロードを行いたい場合などは以下のようにコマンドを実行します。

```shell
$ aws s3 sync ./build s3://{バケット名} --acl public-read --profile {profile_name}
```

以上でデプロイが完了ですので、以下のようなURLでアプリケーションに接続できます。

http://{s3バケット名}.s3-website-ap-northeast-1.amazonaws.com

自分の作ったアプリが表示されれば成功です！
EC2に置いてあるサーバーとも連携が取れているか確認してみてください。