リモート開発メインのソフトウェア開発企業のエンジニアブログです

S3とCloudFront関連のあれこれ

先日、S3 に HTML、画像、CSS などを置いて、CloudFront でそれを静的サイトとして配信するという設定を行いました。その際に、サイト内でいくつかの条件に従ってリダイレクトさせるという要件がありました。

CloudFront は、それ以前もちょっとは触ったことはあったのですが、自分自身でちゃんと設定する事は初めてだったため、分からなかった点・戸惑う点などが多々あり、色々と調べつつ行いました。

本記事では、それらの調べた内容をまとめて記載します。対象読者としては、以下を前提とします。

  • CloudFront が何をするものなのかを知っている
  • S3 の基本的な設定方法(特に静的ウェブサイトホスティング関連)は知っている

また、本記事は、体系立てた情報の提供を目的としたものではありませんので、そうした情報が必要な場合は、公式ドキュメントなり書籍などを参照して下さい。

http -> https のリダイレクト

動的なwebサイトの場合、フロントに置いたリバースプロキシの Apache なり nginx で処理することが一般的だと思います。(Apache であれば mod_rewrite とか。)静的なサイトの場合でも、それらのwebサーバーを使う場合は同様の設定を行います。

それを CloudFront でやるには、Viewer Protocol Policy という設定項目で簡単に実現できます。以下のリンクを参考にしてみて下さい。

なお、S3 の静的ウェブサイトホスティング機能単体では実現できません。以下のページ末尾に記載されています。

Amazon S3 での静的ウェブサイトのホスティング – Amazon Simple Storage Service

通常のリダイレクト方法は主に2つある

http -> https ではなく通常のリダイレクト、つまり/foo にアクセスされたら/bar にリダイレクトさせる、というのは良くある要件だと思います。これを実現する方法は、主に2つあります。以下の公式ドキュメントに詳しく説明されています。

(オプション) ウェブページリダイレクトの設定 – Amazon Simple Storage Service

また、以下のページの上の方に「比較」という項目がありますので、そちらで主な違いを確認してみて下さい。

Amazon S3 でリダイレクトを扱う | DevelopersIO

ただ、いずれの方法を使うにせよ、気をつけなければいけない点があります。

共通: origin にウェブサイトエンドポイントを使用

S3 で静的ウェブサイトホスティングの設定をしている場合、S3の通常のエンドポイント(REST API エンドポイント)に加えて、もう1つエンドポイントが使えるようになります。URL に s3-website という文字列が含まれているのがウェブサイトエンドポイント、そうでないのが REST API エンドポイントです。詳細は以下のページをご参照下さい。

ウェブサイトエンドポイント – Amazon Simple Storage Service

さて、諸々のリダイレクトの機能を使う場合、CloudFront の origin には、ウェブサイトエンドポイントを指定する必要があります。origin を選択する際にプルダウンに選択肢があるのは「REST API エンドポイント」なので、そこから選ばずに手動で入力する必要があります。めっちゃ分かりにくいですね。

AWS のフォーラムでもスレッドがありましたので、そこからいくつか引用しておきます。

Redirects are only supported by the static website endpoints, which contain “s3-website”. The standard S3 endpoints, such as s3.amazonaws.com, will not serve redirects. Instead, you will see the x-amz-website-redirect-location header being returned.

https://forums.aws.amazon.com/thread.jspa?threadID=116243

It is possible to make this work with CloudFront. Instead of selecting a bucket in the dropdown, you enter the full S3 static website endpoint name manually, like “example.s3-website-us-east-1.amazonaws.com”. CloudFront will then access your bucket through the correct endpoint and all static website features will work as expected.

https://forums.aws.amazon.com/thread.jspa?threadID=116243

方法1: Redirection Rules を使う

さて、2つの方法について説明していきますが、一番素直なのは、S3 のリダイレクトルールというのを使う方法です。上で挙げた公式ドキュメントの「高度な条件付きリダイレクト」の項に詳しく説明されています。

ルールの例としては、以下のような感じです。

<RoutingRules>
  <RoutingRule>
    <Condition>
      <KeyPrefixEquals>foo</KeyPrefixEquals/>
    </Condition>
    <Redirect>
      <HostName>www.example.com</HostName>
      <ReplaceKeyWith>bar/</ReplaceKeyWith>
    </Redirect>
  </RoutingRule>
</RoutingRules>

方法1だと出来なかったことがあった

基本的にはこれを使った方が良いと思うのですが、この方法だと出来ないことがありました。

それはルートディレクトリ / から別の場所へのリダイレクトです。上に挙げたルールの例を見てもらえれば分かる通り、<KeyPrefixEquals> に指定するのは、あくまで prefix、つまりパスの先頭の / を除いたものです。なので、/ の場合にリダイレクトするという指定が出来ませんでした。

解決方法は、以下の Stack Overflow に載っていますが、空の index.html をバケットの直下に置いて、メタデータでリダイレクトの設定(後述の「方法2」)を行います。

amazon web services – How to redirect from bucket root to subdirectory in AWS S3? – Stack Overflow

方法2: S3オブジェクトにメタデータを付ける

S3にアップロードしたオブジェクトに Website-Redirect-Location メタデータ(それによりx-amz-website-redirect-location という名前のレスポンスヘッダーが返される?ようです)を設定する事で、そのオブジェクトにアクセスがあった場合にリダイレクトさせる事が出来ます。

詳しくは、先ほどの公式ドキュメントの「Amazon S3 コンソールでのページリダイレクトのサポート 」の項に記載されています。

S3オブジェクトにメタデータを設定する方法は、以下を参照して下さい。

S3 オブジェクトにメタデータを追加する方法 – Amazon Simple Storage Service

ディレクトリインデックス関連

Webサイトをホスティングする場合、ディレクトリインデックスを設定したい事が殆どでしょう。以下のようなものです。

  • / にアクセスされたら /index.html を返す
  • /foo/ にアクセスされたら /foo/index.html を返す

これに関しても、いくつか方法があります。

方法1: CloudFront でルートオブジェクトを指定

この方法で解決できるケースは限定的です。以下のうち、前者は解決できますが、後者(サブディレクトリ)は解決できません。

  • / にアクセスされたら /index.html を返す
  • /foo/ にアクセスされたら /foo/index.html を返す

あまり使いどころがないので、この機能は無効のままにしておいた方が、変なトラブルを防げると思います。

本機能に関しては、詳しくは以下のドキュメントを参照して下さい。

デフォルトのルートオブジェクトの指定 – Amazon CloudFront

方法2: S3 でインデックスドキュメントを設定する

サブディレクトリでもインデックスドキュメントを指定したい場合(ほとんどの場合そうだと思いますが)、S3 の機能を使います。同機能の詳細は、以下のドキュメントを参照して下さい。

インデックスドキュメントのサポートの設定 – Amazon Simple Storage Service

CloudFront と併用する場合の注意点としては、origin にウェブサイトエンドポイントを指定することです。詳しくは、上の方に記載しました。これは多くの人がハマるポイントのようです。

方法3: Lambda@Edge を使う

最後に紹介する方法は、Lambda@Edge を使って URI を書き換える方法です。詳細は以下に挙げたサイトを参照してください。

TTLを設定する

最後はTTLの設定方法を説明します。CloudFront のディストリビューションの設定をしていると、TTL 関連を入力する欄がありますが、グレーアウトして入力できません。入力できるようにするには「オブジェクトキャッシュ」の設定を「カスタマイズ」にする必要があります。詳しくは、以下のドキュメントを参照して下さい。

コンテンツがエッジキャッシュに保持される期間の管理 (有効期限) – Amazon CloudFront

まとめ

S3, CloudFront は機能豊富ですが、やりたいことをやる方法が複数ある場合も多く迷うことが多いです。また、origin にウェブサイトエンドポイントを指定する必要があると言うのは、多くの人にとって盲点だと思います。

本記事が、S3 や CloudFront を使う方々の何らかの役に立てば幸いです。

← 前の投稿

React.jsのコードをTypeScript化する

次の投稿 →

Laravelの多対多のリレーションについて

コメントを残す