シングルページアプリケーションを作っていて、外部には公開したくないが、ローカル以外のサーバーに置いて配信テストをしたいことがあったので、その時の構築メモです。
要件
静的配信だし、S3を使えばサーバー立てなくてもAWSのサービスだけでできそうな感じだったので、下記のようなものを想定しました。
- サーバーレス(既存サービスを利用する・インスタンスを立ち上げない)
- httpsで静的配信
- http通信は不可
- キャッシュしない(アップした更新をすぐに確認できるようにするため)
- サブディレクトリによるルーティング可能
- IPアドレスによるアクセス制限
手順
HTTPS静的配信
S3にファイルを置いて、Static website hostingすればいいのかなと考えていたのですが、https配信するにはCloudFrontを使う必要がありました。 また、CloudFrontで配信すれば、S3をStatic website hostingで公開する必要はなかったです。
CloudFrontのDistributionsページから[Create Distribution]-[Web]-[Get Started]と進んで配信を作成します。
Origin Settings
- Origin Domain Name
- 公開するバケットを選択します
- Origin Path
- どのサブディレクトリ配下を公開するかを指定します。「/」から始まり、最後の「/」は不要です。
- Restrict Bucket Access
- CloudFrontを使って公開する場合、S3を公開する必要はありません。「Yes」にします。
- Origin Access Identity
- Identityが必要なのですが、作成していない場合「Create a New Identity」で作成します。
- Grant Read Permissions on Bucket
- よしなに権限設定してくれるので「Yes」にします。
Default Cache Behavior Settings
- Viewer Protocol Policy
- HTTPS配信のみを行いたいので「Redirect HTTP to HTTPS」にします
- Object Caching
- 開発用サイトなので、ファイルをアップしたらすぐに確認したく、キャッシュをしない設定にするため「Customize」を選択します。
- Minimum TTL・Maimum TTL・Default TTL
- キャッシュ時間の設定。キャッシュしないので「0」にします
Distribution Settings
- AWS WAF Web ACL
- ここでIP制限をかけることができます。後からでも設定できるので「None」にしておきます。
- Default Root Object
- シングルページアプリケーションの配信HTMLのファイル名を指定します。
「Create Disctibution」ボタンを押して配信を作成します。 結構時間がかかります。おそらく、想像しているより時間がかかり、動いているのかと途中心配になるかもしれませんが、忘れたころに完了します。
サブディレクトリによるルーティング
シングルページアプリケーションだと、サブディレクトリでルーティングを行うことがあるかと思います。
初期設定のままだと、サブディレクトリにファイルは無いためエラーがでてしまいます。 なので、エラーではなく配信ページを呼び出すように設定します。
先程作成した配信の詳細を開いて[Error Pages]-[Create Custom Error Response]ボタンを押して、エラー毎の挙動を追加します。
- HTTP Error Code
- 「404」を選択します。
- Customize Error Response
- エラーページではなく、配信ページを表示するため「Yes」を選択します。
- Response Page Path
- アプリケーションの配信HTMLファイル名を指定します。
- HTTP Response Code
- 「200」を選択します。
エラーコード「403」も同様に作成します。
これで、サブディレクトリにアクセスするとエラーではなく、配信ページが呼び出されるようになります。
ブラウザキャッシュ時間の設定
CloudFrontで設定したキャッシュ時間はCloudFrontのキャッシュ時間で、ブラウザのキャッシュ時間ではありません。 CloudFrontのキャッシュ時間を0にしても、ブラウザでキャッシュが有効になっていると、アクセスしても更新されません。 ですので、別途ブラウザのキャッシュを無効にする必要があります。
ブラウザがそのファイルをどれくらいキャッシュしておくかは、ファイル取得時のヘッダーの「Cache-Control」で判断し、値が「no-chache, no-store」だとブラウザはそのファイルをキャッシュしません。
CloudFrontで「Cache-Control」を設定するには、S3に置かれた大本のファイルの「メタデータ」に設定します。
ただ、これを手動で1ファイル毎に設定するのは手間なので、AWS CLIでファイルをS3にアップする時に、フォルダごと設定するようにしました。
aws s3 cp --recursive --metadata-directive "REPLACE" \ --cache-control "no-cache, no-store" \ $LOCAL_PATH "s3://${UP_PATH}/"
IPアドレスによるアクセス制限
AWSのWAFでアクセス制限の設定(=ACL)を作成して、それをCloudFrontの配信に割当ます。
配信の詳細で、[General]-[Edit]-[AWS WAF Web ACL]で作成したACLを指定します。
ACLの作成は難しくはないのですが、手順が多いので、ここではIPアドレス制限のACLの作成についてザックリとだけ説明します。
- [IP addresses]で許可するIPアドレスを作成する
- [Rules]で指定IPアドレスにマッチした時のルール「When a request [does] [originate from an IP address in] [上記で作成したIPアドレス]」を作成する
- [ACL]で上記のルールを追加し、「Action」を「Allow」、「Default action」を「Block」とする
以上で、CloudFrontが作成したURLにアクセスすると、S3にアップした「index.html」を起点としたSPAが読み込まれるようになります。