[AWS] 頑張ればS3とCloudFrontを使って２つのReactアプリを１つのドメインで配信できるように設定できるぞ！

意外とありそうでなかった手順の備忘録です。
# 概要
私自身お仕事で扱うシステム開発はAWSでのWebアプリケーション開発が多く、その中でもPoC開発に当たることもしばしば。そういったときに、一応productionとして動作しているアプリに検証を乗せるのはいやですよね。

そういったときに、実質アプリとしては別だけど、同一オリジンで配信することで、アプリ利用者はさも同じアプリケーションで動作しているように見せる事が可能です。ただこの方法を実現するために調べたところ記事が古かったり、検索ヒット数も少ない状況のため記事として残します。
# 要件
* アプリケーションはReactxTypescriptのSPA
* アプリケーションはS3にビルドして配置している
* CloudfrontからS3へのアクセスはOACを使う ※後ほど紹介します
* Cloudfrontを使ってアプリケーションを配信する
* アプリA、アプリBを別々のS3に配置し、同じCloudfrontディストリビューション、同じオリジンで配信する

とりあえず今回やりたいのはこれです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664827/e22b2682-0fea-2090-64a8-43dc1fcedf36.png)
# 手順
ReactアプリをS3に配置するまではどのやり方としても一緒なので、飛ばしたいというかたはこちらから。
## 事前準備
Reactを構築するために使用するNode.jsやnpmパッケージの導入については割愛します。
バージョンは以下の通りです。
```
$ node -v
v16.18.0
$ npm -v
8.19.2
```
## Reactプロジェクトの構築
このあたりは本筋ではないので淡々といきます
### Reactを構築する
```
$ npx create-react-app ./qiita-app-a --template typescript
$ cd qiita-app-a
$ npm start
```
アプリが起動することを確認してください。
上記の手順でqiita-app-bも作成しましょう

### Reactの動作確認を行う
各アプリですが、最終的にどちらのアプリにアクセスしているか視覚的に理解するため、今回はReact初期状態の画面のテキストを変更しました。みなさんはそれぞれ実装している複数のアプリをご用意ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664827/c4c75cf0-d161-81d8-e2c0-18bd7ce44d4c.png)


### Reactをビルドする
２つのアプリケーションをビルドしてパッケージをまとめます
```
npm run build
```
実行すると、buildディレクトリが出現します。
## S3にビルドパッケージをアップロードする
### AWSアカウントの用意、S3バケットの用意
こちらは割愛します。
### S3バケットの用意
S3バケットはA・B用にそれぞれ作ってください。今回はOACを使用してCloudfrontからアクセスするため、ブロックパブリックアクセスは「すべてブロック」しておいてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664827/5a3b9ac3-5f0d-0609-07ae-075046b949cc.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664827/6f4fcd27-4118-d2be-06c9-51e742391659.png)
### バケットにReactアプリをアップロードする
先程ビルドしたアプリを各バケットにアップロードしてください

:::note warn
2つ目のアプリケーションは最上位ではなく、最上位にフォルダを設置し、その中に格納するようにしてください。理由は後述します。
例） [バケット名]/sub/[Reactビルドアプリ] に格納
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664827/ac614a9a-9f61-2502-ca0b-1112f750d57e.png)

## 1つ目のCloudFrontディストリビューションを構築
### オリジンドメインを設定する
まずは1つ目のS3バケットに対して設定を行います。1つ目のアプリのバケットをオリジンドメインに設定する（メインのアプリケーション）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664827/c26514c8-de8a-9bf8-4ae2-a5d94a2a4d82.png)

### オリジンアクセスを設定する
CloudFrontでS3にアクセスする記事の殆どは、S3を静的サイトホスティングする方式が多いように思いますが、OACによるアクセスは2022年に発表されたセキュアなアクセス方式です。詳しは以下の記事が素敵ですのでぜひ御覧ください。今回はこの設定で進めます。

https://dev.classmethod.jp/articles/amazon-cloudfront-origin-access-control/

オリジンアクセスを「Origin access control settings」にする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664827/752617c5-866d-1900-94b4-3cb9567dc0d8.png)

「コントロール設定を作成」を押下し、特に変更せず作成する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664827/ec1ea306-3568-cbf9-760f-9962deb84138.png)

その他特に何も設定せずそのままディストリビューションを作成する

### S3バケットポリシーを更新する
正しく作成されると、黄色い表記が出るかと思います。右上の「ポリシーをコピー」を押下し、S3バケットの権限に移動してポリシーを更新していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664827/5199a003-c091-2acd-0204-642fb1aac98e.png)

該当のS3バケットが展開されますので、「バケットポリシー」の編集を押下し、ペーストします。そうすると、ポリシーが設定されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664827/9e91e2ba-eeb7-1aab-28c2-dd4ebb2af98e.png)

### １つ目のアプリケーションを確認する
CloudFrontに戻り、先程作成したディストリビューションに、「https://[ID].cloudfront.net」が表示されていると思います。
こちらを開いていただき、S3にアップロードしたReactアプリケーションが開くことができたら成功です。

:::note warn
パスエラーにご注意ください。Reactの場合、CloudFrontでデフォルルートオブジェクトをindex.htmlに設定すると、上記のリンクで開くことができます。
:::

## 2つ目のアプリを組み込む
### オリジンを作成する
先程作成したディストリビューションからオリジンを新しく作成します。
オリジンドメインは2つ目のアプリケーションのS3バケットを指定し、その他の設定は1つ目のアプリ同様に設定してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664827/58b31a33-f54e-5cc8-321b-5ee86c92cd3b.png)

### S3バケットポリシーを更新する
1つ目と同様に、2つ目のアプリケーションのオリジンのポリシーをペーストしてください。

### ビヘイビアを設定する
こちらのままでも動作自体はしますが、1つ目のアプリケーションが優先されるため、2つ目のアプリケーションにたどり着くことができません。ビヘイビアを設定することで表示するオリジンのアプリケーションの優先度が変更でき、2つ目のアプリケーションにたどり着くよう設定できます。

ただし、どちらのアプリケーションはビヘイビアで指定したパスが余計に入る形になるので、アプリケーションによってはここが少しボトルネックになるかもしれません。

まずは先程のディストリビューションのビヘイビアを新規で作成します。
パスパターンはお好きなパスを選択いただき、オリジンは2つ目のアプリケーションを選択します。

:::note warn
パスパターンは必ず/[パス名]/* の形式にしてください。
上記パス名は、2つ目のアプリで格納したフォルダにしてください。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664827/76378822-a5d3-a293-3079-26f55f934186.png)

## 2つ目のアプリにアクセスする
https://[ID].cloudfront.net/sub/index.html にアクセスすると、ようやく2つ目のアプリにたどり着くことができます。こちらではファイル名が必要になってきます。これで設定は終わりですお疲れ様でした！