【CloudFront】index.html を省略してサブディレクトリへアクセスできるようにする
index.html を省略して
CloudFront のサブディレクトリへアクセスしたときに index.html を表示させたい!
CloudFront にデフォルトディレクトリインデックスというものを実装して実現していきます。
Terraformを使って設定していきます
・バージョン
$ terraform providers -version
Terraform v1.4.2
on linux_amd64
+ provider registry.terraform.io/hashicorp/aws v4.67.0
index.html を省略してルート URL にアクセスする方法は ↓ をご覧ください
現状
CloudFront のオリジンにしているS3 バケットにはこんな感じで index.html を配置しています
~$ aws s3 ls --recursive s3://<S3バケット名>
2023-07-23 23:38:50 0 about/
2023-07-23 23:42:30 279 about/index.html
2023-07-23 23:42:48 273 index.html
about というサブディレクトリにアクセスした場合、index.html を指定しないと表示しません
// ファイル名指定
~$ curl https://test.hisui-app.com/about/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>about/index.html</h1>
</body>
</html>
// ファイル名省略
~$ curl https://test.hisui-app.com/about/
~$
ただ、デフォルトルートインデックスに index.html を設定しているため、
ルート URL にアクセスした場合には index.html が返ってきます
// ファイル名指定
~$ curl https://test.hisui-app.com/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>index.html</h1>
</body>
</html>
// ファイル名省略
:~$ curl https://test.hisui-app.com
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>index.html</h1>
</body>
</html>
デフォルトディレクトリインデックスを実装するにあたって、 デフォルトルートオブジェクトが設定されている必要はない。
CloudFront Functions とは?
まずは、デフォルトディレクトリインデックスの実装に必要なCloudFront Functionsについて。
特定のイベントタイプに対して、事前に定義している JavaScript の関数を実行できる機能のこと。
イベントタイプには2種類あり、
- ビューワーリクエスト:ビューワーからリクエストを受信したとき
- ビューワーレスポンス:ビューワーにレスポンスを返す前
リクエスト(レスポンス)ヘッダーの操作やリダイレクト処理などを実現できます。
公式ドキュメントは ↓ です。目を通してみるといいと思います
デフォルトディレクトリインデックスとは??
デフォルトルートオブジェクトを設定しただけでは、サブディレクトリに対してはエラーを返してしまいます。
そこで、**デフォルトディレクトリインデックスを実装し、****デフォルトインデックスファイル(今回は index.html)を返すようにします。**
アーキテクト図はこちらです
例えば、https://example.com/about にアクセスするとします。
- Cloudfront Fuctions で https://example.com/about/index.html に書き換え
- CloudFront やオリジンからレスポンスを返す
このような機能(デフォルトディレクトリインデックス)を実装していきます。
CloudFront Functions の料金
公式サイトより、
100 万件の呼び出しあたり 0.10 USD です (1 回の呼び出しごとに 0.0000001 USD)。
また、無料枠として
各月 2,000,000 件の CloudFront Function 呼び出し
が設けられています。
実装
CloudFront Functions
CloudFront Functions で実行する関数はこちらのコードをそのまま使います
js ファイルを作成し、tf ファイルから参照するようにします。
function handler(event) {
var request = event.request;
var uri = request.uri;
// Check whether the URI is missing a file name.
if (uri.endsWith("/")) {
request.uri += "index.html";
}
// Check whether the URI is missing a file extension.
else if (!uri.includes(".")) {
request.uri += "/index.html";
}
return request;
}
if 文を使ってリクエスト URI を index.html を付与したものに書き換えます。
Terraform
resource "aws_cloudfront_distribution" "main" {
...
default_cache_behavior {
...
# CloudFront Functionsの紐づけ
function_association {
event_type = "viewer-request"
function_arn = aws_cloudfront_function.main.arn
}
}
...
}
...
# CloudFront Functions
resource "aws_cloudfront_function" "main" {
name = "function"
runtime = "cloudfront-js-1.0"
comment = "default directory index"
publish = true
code = file("./CloudFront_Functions/function.js")
}
aws_cloudfront_distribution > default_cache_behavior ブロック内で CloudFront Functions を紐づけていきます
プロパティ | 説明 |
---|---|
event_type | どのイベントタイプで実行するか viewer-request に対して関数を実行します |
function_arn | 後ほど定義する CloudFront Functions の ARN を指定します |
aws_cloudfront_function にて、CloudFront Functions を定義します。
プロパティ | 説明 |
---|---|
name | CloudFront Functions の名前 |
runtime | ランタイム。2023/07 現在、cloudfront-js-1.0 のみ指定可能 |
comment | コメント。 |
publish | 関数をデプロイするかどうか。デフォルトは true。 テストなどをしたい方はデプロイしない(false) ことも可能。 |
code | 関数のソースコード。先ほど作成した js ファイルを相対パスで指定。 |
plan , apply
$ terraform plan
$ terraform apply -auto-approve
ダウンタイムはなかったと思います。。。
動作確認
サブディレクトに対しても index.html が返ってくれば OK です!
~$ curl https://test.hisui-app.com/about/
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>about/index.html</h1>
</body>
</html>
参考文献
Discussion