CloudFront Functions で S3 静的サイトの URL を書き換えてみた

CloudFront Functions で S3 静的サイトの URL を書き換えてみた

CloudFront のデフォルトルートオブジェクトはルートパスのみに適用されるため、サブディレクトリの index.html は自動的に解決されません。本記事では、CloudFront Functions を使用して /about へのリクエストを /about/index.html に内部的に書き換え、S3 上のファイルを配信する方法を実装・検証していきます。
2026.08.04

はじめに

テクニカルサポートの 片方 です。
Amazon S3 バケットを通常の S3 バケットオリジンとして Amazon CloudFront に設定する場合、CloudFront のデフォルトルートオブジェクトはルートパス / にのみ適用されます。
そのため、S3 バケットに about/index.html を配置していても、/about や /about/ へのアクセス時に、自動的に about/index.html を返すことはできません。
本ブログでは、CloudFront Functions を使用して、閲覧者からのリクエスト URI を Viewer request イベントで書き換えます。具体的には、/about および /about/ へのアクセスを CloudFront 内部で /about/index.html に書き換え、S3 バケット上の HTML ファイルを配信します。

/about
  ↓ CloudFront Functions で URI を書き換え
/about/index.html

この処理は、ブラウザへ HTTP リダイレクトを返すものではありません。CloudFront 内部で URI を書き換えるため、ブラウザのアドレスバーは /about のままであり、/about/index.html へ遷移しません。
CloudFront Function で request.uri を変更すると、閲覧者が要求するオブジェクトを変更できます。一方で、URI の変更だけでは、キャッシュビヘイビアやオリジンは切り替わりません。本記事では、デフォルトのキャッシュビヘイビアに設定した Amazon S3 オリジンへ、書き換え後の URI を送信します。

また、検証環境では S3 バケットをパブリック公開せず、Origin Access Control (OAC) を使用します。これにより、対象の CloudFront ディストリビューションからのみ S3 オリジンへアクセスできるようにします。

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/functions-event-structure.html?utm_source=openai

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-origin.html?utm_source=openai

検証内容

本記事で実施する内容は、以下のとおりです。

  • S3 バケットに index.html と about/index.html を配置する
  • CloudFront ディストリビューションを作成し、S3 バケットをオリジンとして設定する
  • OAC を設定し、CloudFront からのみ S3 オリジンへアクセスできるようにする
  • CloudFront Function を作成し、/about と /about/ を /about/index.html に書き換える
  • https://<CloudFront-domain-name>/about および https://<CloudFront-domain-name>/about/ にアクセスし、About ページが表示されることを確認する

構成(検証環境)

今回の検証環境は、Amazon S3 をオリジンとする CloudFront ディストリビューションです。
CloudFront の Viewer request イベントに CloudFront Function を関連付け、/about および /about/ へのリクエストを /about/index.html に書き換えます。

[ブラウザ]
    |
    | GET /about
    v
[Amazon CloudFront]
    |
    | CloudFront Function(Viewer request)
    | /about -> /about/index.html
    v
[Amazon S3]
    |
    | GET /about/index.html
    v
[about/index.html を返却]

S3 バケットには、以下のオブジェクトを配置します。

<バケット名>/
├── index.html
└── about/
    └── index.html

CloudFront ディストリビューションのデフォルトルートオブジェクトには、index.html を設定します。これにより、ルートパス / へのアクセス時に、S3 バケット直下の index.html を配信できます。

一方、S3 バケット内にオブジェクトキー about は配置しません。そのため、/about へのリクエストだけでは about/index.html を取得できません。

CloudFront Function で URI を /about/index.html に書き換えることで、S3 バケットに配置した about/index.html を取得できるようにします。

S3 バケットではパブリックアクセスブロックを有効にし、OAC を使用して CloudFront からのアクセスだけを許可します。また、S3 Object Ownership には Bucket owner enforced を設定します。

CloudFront では、OAC の利用が推奨されています。OAC を設定する際は、署名動作として Sign requests(recommended) を使用します。

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html

使用する AWS サービス

サービス 用途
Amazon S3 静的 HTML ファイルを配置するオリジン
Amazon CloudFront コンテンツの配信、および S3 オリジンへのアクセス制御
CloudFront Functions Viewer request イベントで URI を書き換える
Origin Access Control (OAC) CloudFront から S3 へのアクセスを許可し、S3 バケットのパブリック公開を回避する

実装してみた

本節では、S3 バケット、CloudFront ディストリビューション、CloudFront Function を順に作成します。

  1. S3 バケットを作成し、HTML ファイルをアップロードする
  2. CloudFront ディストリビューションを作成し、OAC を設定する
  3. デフォルトルートオブジェクトに index.html を設定する
  4. CloudFront Function を作成し、Viewer request イベントに関連付ける
  5. CloudFront 経由でページを表示できることを確認する

S3 バケットを作成する

まず、静的 HTML ファイルを配置する S3 バケットを作成します。
S3 コンソールで バケットを作成 を選択し、任意のバケット名を入力します。本ブログでは、以下のような名前を使用します。

cloudfront-functions-url-rewrite-handson-<任意の文字列>

以下の設定でバケットを作成します。

項目 設定値
バケット名 任意のグローバルで一意な名前
パブリックアクセスをすべてブロック 有効
Object Ownership Bucket owner enforced
バケットのバージョニング 任意
デフォルトの暗号化 任意

01

バケットを作成したら、以下のファイルを配置します。

<バケット名>/
├── index.html
└── about/
    └── index.html

今回は動作確認用として、以下の HTML ファイルを作成しました。

index.html
<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <title>CloudFront Functions Handson</title>
  </head>
  <body>
    <h1>トップページ</h1>
    <p>CloudFront Functions の URL 書き換えを検証しています。</p>
    <p><a href="/about">About ページへ</a></p>
  </body>
</html>
about/index.html
<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <title>About</title>
  </head>
  <body>
    <h1>About ページ</h1>
    <p>このファイルは S3 の /about/index.html に配置しています。</p>
    <p>CloudFront Functions により、/about でアクセスできるようにします。</p>
    <p><a href="/">トップページへ戻る</a></p>
  </body>
</html>

index.html はバケット直下へアップロードします。続けて about プレフィックスを作成し、その配下に index.html をアップロードします。

02

CloudFront ディストリビューションを作成する

続いて、S3 バケットをオリジンとする CloudFront ディストリビューションを作成します。
CloudFront コンソールで Create distribution を選択します。コンソールの項目名や画面構成は更新される可能性があるため、以下の設定内容を確認しながら進めてください。

項目 設定値
Distribution name 任意の名前
Description 任意
Distribution type Single website or app
Route 53 managed domain 必要に応じて設定

03

続いて、オリジンに以下を設定します。

項目 設定値
Origin type Amazon S3
S3 origin 作成済みの S3 バケット
Origin path 空欄
Allow private S3 bucket access to CloudFront 有効
Origin access control 新規作成、または既存の OAC を選択
Signing behavior Sign requests (recommended)

04

Allow private S3 bucket access to CloudFront を有効にすると、CloudFront から S3 バケットへアクセスするための OAC と、必要な S3 バケットポリシーを設定できます。
OAC の署名動作には、Sign requests (recommended) を設定します。この設定では、CloudFront から Amazon S3 へのリクエストに署名され、CloudFront と S3 間の通信には HTTPS が使用されます。

本ブログでは、S3 オリジン向けの推奨設定を使用します。

項目 設定値
Origin settings Use recommended origin settings
Cache settings Use recommended cache settings tailored to serving S3 content

05

次のセクションでは、今回は AWS WAF を有効化せずに進めます。

06

デフォルトルートオブジェクトを設定する

CloudFront ディストリビューションを作成した後、対象のディストリビューションを開きます。
Settings の General タブで Edit を選択し、Default root object に index.html を設定します。

index.html

07

これにより、CloudFront のドメイン名のルートパスへアクセスした場合に、S3 バケット直下の index.html を配信できます。

https://<CloudFront のドメイン名>/

この時点で、CloudFront のドメイン名へアクセスし、トップページが表示されることを確認します。
なお、この設定はルートパス / のための設定です。/about および /about/ を about/index.html に書き換える処理は、次節の CloudFront Function で設定します。

08

一方で、まだ CloudFront Function を設定していないため、以下の URL では about/index.html を取得できません。

https://<CloudFront のドメイン名>/about

CloudFront Function を作成する

CloudFront コンソールのナビゲーションペインで Functions を選択し、Create function を選択します。
関数名には、以下を設定します。

rewrite-about-to-index

09

Runtime には、cloudfront-js-2.0 を設定します。
関数を作成したら、Build タブで以下のコードを設定します。

function handler(event) {
    var request = event.request;

    if (request.uri === '/about') {
        request.uri = '/about/index.html';
    }

    return request;
}

この関数では、リクエスト URI が /about または /about/ と完全一致する場合に、URI を /about/index.html に変更します。

リクエスト URI 書き換え後の URI
/about /about/index.html
/about/ /about/index.html
/ /
/about/index.html /about/index.html
/assets/app.js /assets/app.js

010

今回は動作を分かりやすくするため、書き換え対象を /about と /about/ に限定しました。
実運用では、複数のページを対象にする場合でも、JavaScript、CSS、画像、フォント、API エンドポイントなどを誤って書き換えないよう、条件を慎重に設計してください。
コードを入力したら、Save changes を選択します。

CloudFront Function をテストする

Test タブで、以下の値を指定して CloudFront Function をテストします。

項目 設定値
イベントタイプ Viewer request
ステージ DEVELOPMENT
HTTP メソッド GET
URL パス /about

011

テスト結果の出力で、uri が /about/index.html になっていることを確認します。

{
  "request": {
    "method": "GET",
    "uri": "/about/index.html"
  }
}

続けて、URL パスを /about/ に変更してテストします。同様に uri が /about/index.html となることを確認します。

CloudFront Function を発行して関連付ける

テスト結果で、/about および /about/ が /about/index.html に書き換えられることを確認できたら、CloudFront Function を発行します。
Publish タブを開き、Publish function を選択します。
CloudFront Function は、作成直後は DEVELOPMENT ステージです。CloudFront ディストリビューションに関連付けるには、CloudFront Function を LIVE ステージへ発行する必要があります。

012
013

Function を発行した後、[関連付けを追加] を選択します。以下の内容で CloudFront ディストリビューションに関連付けます。

項目 設定値
Distribution 作成した CloudFront ディストリビューション
Event type Viewer request
Cache behavior Default (*)

014
015

Viewer request は、CloudFront が閲覧者からリクエストを受信したタイミングで CloudFront Function を実行するイベントタイプです。
今回のように URI の書き換え結果をキャッシュキーに反映させたい場合は、Viewer request を使用します。
関連付け後、CloudFront ディストリビューションのステータスが Deployed になるまで待機します。
デフォルトのキャッシュビヘイビアへの関連付けを確認できたら、設定は完了です。お疲れさまでした!
続けて、実際の配信結果を確認します。

確認してみた

CloudFront Function をディストリビューションに関連付けると、CloudFront ディストリビューションの設定がデプロイされます。
ディストリビューションのステータスが Deployed になったことを確認してから、動作確認を実施します。

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/associate-function.html?utm_source=openai

トップページを確認する

まずは、CloudFront ディストリビューションのドメイン名にアクセスします。

https://<CloudFront のドメイン名>/

S3 バケット直下に配置した index.html が表示されました。

016

今回は CloudFront ディストリビューションの Default root object に index.html を設定しているため、ルートパス / へのアクセス時に index.html が配信されます。

about へのアクセスを確認する

続いて、以下の URL にアクセスします。

https://<CloudFront のドメイン名>/about

020

S3 バケットに配置した about/index.html の内容である About ページが表示されました。
ブラウザのアドレスバーは /about のままですが、CloudFront Function により、CloudFront が S3 オリジンへ送信する URI は /about/index.html に書き換えられています。

閲覧者からのリクエスト
/about

CloudFront Function
/about/index.html

S3 から about/index.html を取得

直接 URL と比較する

比較のため、以下の URL にもアクセスします。

https://<CloudFront のドメイン名>/about/index.html

021

こちらも同じ About ページが表示されました。

アクセスしたパス CloudFront Function による URI 表示結果 ブラウザの URL
/ / index.html を表示 /
/about /about/index.html about/index.html を表示 /about
/about/ /about/index.html about/index.html を表示 /about/
/about/index.html /about/index.html about/index.html を表示 /about/index.html

以上より、/about および /about/ へのアクセス時に、CloudFront Function で /about/index.html へ内部的に書き換えられていることを確認できました。
成功です!

まとめ

CloudFront Functions を使用して、/about へのリクエストを /about/index.html へ書き換える構成を試しました。
CloudFront Function を Viewer request に関連付けることで、ブラウザの URL を変更せずに、S3 上の about/index.html を配信できました。
今回は /about のみを対象としましたが、複数のパスを扱う場合は、意図しない URI まで書き換えないように条件を設計する必要があります。特に、API のパスや JavaScript、CSS、画像などの静的アセットは、書き換え対象から除外することを検討してください。
本ブログが誰かの参考になれば幸いです。

参考資料

クラスメソッドオペレーションズ株式会社について

クラスメソッドグループのオペレーション企業です。
運用・保守開発・サポート・情シス・バックオフィスの専門チームが、IT・AIをフル活用した「しくみ」を通じて、お客様の業務代行から課題解決や高付加価値サービスまでを提供するエキスパート集団です。
当社は様々な職種でメンバーを募集しています。
「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、クラスメソッドオペレーションズ株式会社 コーポレートサイト をぜひご覧ください。※2026年1月 アノテーション㈱から社名変更しました

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事