はじめに
SPA(Vue.js / React など)を AWS で公開する場合、S3 + CloudFront が定番構成ですが、以下のような要件では悩みが出てきます。
- 社内向け / 特定ネットワーク向けに公開したい
- ALB 配下に API と SPA をまとめたい
- CloudFront を使わず ALB で制御したい
- /xxx/yyy へのアクセスも SPA の index.html で処理したい
本記事では、ALB + S3(静的コンテンツ)構成で SPA(Vue.js)を公開 し、さらに ALB のルールで / や任意パスを /index.html に変換 する方法をまとめます。
全体構成
[ Client (Browser) ]
|
| https://test.co.jp
v
[ Application Load Balancer ]
|
| Forward
v
[ Target Group (S3) ]
|
v
[ S3 Bucket (Vue.js build成果物) ]
ポイント
- CloudFront は使わない
- ALB から S3 に直接静的ファイルを配信
- SPA 用に ALB のルールで index.html にトランスフォーム
- HTTPS は ALB で終端
手順
1. Vue.js をビルドする
まずは SPA を通常通りビルドします。
> npm run build
生成物(例):
dist/
├─ index.html
├─ js/
├─ css/
└─ assets/
2. S3 バケットを作成し、静的ファイルを配置
- S3 バケットを作成
- 静的ウェブサイトホスティングは使わない
- ALB からアクセスするため、公開設定は不要
S3 Bucket
└─ index.html
└─ js/
└─ css/
3. ALB から S3 へアクセスできるようにする
ALB から S3 に直接配信するため、以下を設定します。
3-1. ALB 用の IAM ロールを作成
- s3:GetObject を許可
- 対象バケットを指定
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::your-bucket-name/*"
}
3-2. ターゲットグループを作成(S3)
- タイプ:IP
- プロトコル:HTTPS
- ポート:443
ALB から S3 へは HTTPS + S3 のエンドポイント を利用します。
4. ALB を作成(HTTPS)
- Application Load Balancer
- リスナー:443
- ACM 証明書を設定(test.co.jp)
5. ALB のルールで S3 にフォワードする
基本ルール
IF
Host is test.co.jp
THEN
Forward to S3 Target Group
6. SPA 用に「/ → /index.html」へトランスフォームする
ここがこの記事の 一番のポイント です。
SPA は以下のような URL を直接叩かれると、
https://test.co.jp/dashboard
https://test.co.jp/user/123
S3 に実ファイルが存在せず 404 になる 問題があります。
これを ALB のルールで解決します。
ALB リスナールール例
IF
Path is /
THEN
Redirect to /index.html
さらに SPA 向けの応用(任意パス対応)
IF
Path is /*
THEN
Forward to S3
AND
Rewrite path to /index.html
これにより、
- /
- /dashboard
- /user/123
すべて index.html が返却され、
Vue Router 側でルーティング可能になります。
7. 動作確認
ブラウザで以下を確認します。
すべて Vue.js の画面が表示されれば成功!
おわりに
HTMLを含める全て(/api/*はもちろん)を ALB を通す事によりセキュアに構築する事は、アプリケーションで考える事が減るので、とても良いと思いました。
今回は"認証"を省いているので、次回は Cognito を含めて記事を書きたいと思います!
参考(感謝)
