Open8

Cloudfront Functionsでhugoのindex.htmlを補完する

not75743not75743

つまりどういうことだってばよ

hugoでページ遷移すると遷移先のURLは以下のようになる(あくまで一例)

https://<domain>/posts/<ページ名>/

そう、index.htmlがなく、遷移先のページにアクセス出来ないのだ。
自動的にこうなってほしい

https://<domain>/posts/<ページ名>/index.html

これを実現するためにCloudfront Functionsを試す

curlでの例

cloudfront functionsを設定しないと403エラー

$ curl -I https://<domain>/posts/<ページ名>/
HTTP/2 403
server: AmazonS3

設定後このようにステータスコード200で返ってくるのが目標

$ curl -I https://<domain>/posts/<ページ名>/
HTTP/2 200 
server: AmazonS3
not75743not75743

cloudfront functions is なに

コードをCloudFront Distributionに紐付け、それを各エッジロケーションで動作させる実行環境のこと。
cloudfrontを経由するリクエストやレスポンスの操作が出来る

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/cloudfront-functions.html
https://dev.classmethod.jp/articles/amazon-cloudfront-functions-release/
https://www.infiniteloop.co.jp/tech-blog/2022/12/sounds-good-cloudfront-functions-use-case/

似たようなサービスであるLambda@Edgeとの違いはこちら
https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/edge-functions.html

無料枠があるのはいいですね!
あとさばけるリクエスト数もCloudfrontFunctionsに軍配です

not75743not75743

手動で試す

ここを参考に試してみます
https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/functions-tutorial.html

使うコードはこちら

function handler(event) {
    var request = event.request;
    var uri = request.uri;
    if (uri.endsWith('/')) {
        request.uri += 'index.html';
    }
    else if (!uri.includes('.')) {
        request.uri += '/index.html';
    }
    return request;
}

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/example-function-add-index.html

このコードを保存後、

  • [Publish] タブを選択し、[Publish] ボタンを選択して関数を公開
    • cloudfrontディストリビューションに紐付ける前に公開する必要あり
  • Associated distributionsから
    • 紐づけたいcloudfrontディストリビューション
    • Event TypeとしてViewer Request
    • Cache behaviorでデフォルト
  • ディストリビューションのステータスが [Deployed] になったら動作確認を行う
not75743not75743

動作確認

index.htmlついた!すごい!
見た目は↓のままなんだけど、CloudfrontFunctionsがリクエストを加工してくれるからですね

https://<domain>/posts/<ページ名>/
not75743not75743

削除

Terraform化のため、一度手動で作成したfunctionを削除しました

  • cloudfrontディストリビューションとの関連付けを解除
  • ディストリビューションへの適用をしばらく待つ
not75743not75743

Terraform化

コードは別ファイルで管理して、fileで参照するようにします。

resource "aws_cloudfront_function" "add-index-function" {
  name    = "add-index-function"
  runtime = "cloudfront-js-1.0"
  comment = "Add index.html to the path"
  publish = true
  code    = file("${path.module}/addIndexFunction.js")
}

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_function

addIndexFunction.js
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;
}

https://blog.nns7.work/post/publish-hugo-blog-using-cloudfront-and-s3/