コンテンツにスキップ

docusaurus + CloudFront + S3で直リンクOKにする

docusaurusCloudFront + S3でホスティングしたとき、直リンでアクセスできるパスが制限されています。

  • NG: https://example.com/foo
  • OK: https://example.com/foo/index.html
  • OK: https://example.com
  • ※デフォルトルートを設定したときのみ OK

https://example.com/fooを参照したい場合は、まずhttps://example.comにアクセスしてページ内リンクからhttps://example.com/fooへ移動しないといけません。

これが地味に使いにくい。URL をチームに共有するとき、アドレスバーをコピペするとhttps://example.com/fooとなるので、アクセスするときに手間がかかります。

Lambda@edgeを使って解決します。

手順

  1. Lambda を作成する
  2. Lambda のバージョンを作成する
  3. IAM ロール周りを修正する
  4. CloudFront をトリガーに設定する

1. Lambdaを作成する

us-east-1リージョンに Lambda を作成します。 ランタイムはNode.js 16.xを選択しました。 ロールは基本的な Lambda アクセス権限で新しいロールを作成で作成しました。

export const handler = async (event, context, callback) => {
  const request = event.Records[0].cf.request;

  const olduri = request.uri;

  if (isExistExtension(oldurl)) {
    // 拡張子があれば、そのまま返す
    return callback(null, request);
  }

  // 末尾にindex.htmlを付与する
  // - https://example.com/foo → https://example.com/foo/index.html
  // - https://example.com/foo/ → https://example.com/foo/index.html
  const newuri = (olduri.endsWith("/") ? olduri : olduri + "/") + "index.html";
  request.uri = newuri;

  return callback(null, request);
};

/**
 * 拡張子存在チェック
 */
function isExistExtension(url) {
  const ext = url.split(".").pop().trim();

  // 拡張子がない場合は、ext = url となる
  return ext !== url;
}

2. Lambdaのバージョンを作成する

右上にある「アクション」プルダウンや「バージョン」タブから「新しいバージョンを発行」をする。 入力項目は適当でよいです。

3. IAM ロール周りを修正する

1. Lambdaを作成するで作成したロールに対して色々やります。

ポリシーの追加

新たに以下のポリシーを追加します。[lambdaの関数名]には1. Lambda を作成する作成時の関数名を入力します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iam:CreateServiceLinkedRole",
        "cloudfront:UpdateDistribution"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": ["lambda:GetFunction", "lambda:EnableReplication"],
      "Resource": "arn:aws:lambda:us-east-1:371422377734:function:[lambdaの関数名]:*"
    }
  ]
}

信頼関係の変更

「信頼関係」タブがあるので、edgelambda.amazonaws.comを追加します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": ["lambda.amazonaws.com", "edgelambda.amazonaws.com"]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

4. CloudFront をトリガーに設定する

右上にある「アクション」プルダウンから「Lambda@Edge」へのデプロイを選択します。

item value
Distribution 対象の CloudFront
Cache behavior *
CloudFront event Origin request
Confirm deploy to Lambda@Edge On

これでデプロイすれば完了です。

参考