1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

AWS CloudFrontのアクセスを一律リダイレクトするように設定できるまでの話

Posted at

背景

この間、運営している2つのメディアサイトを統合させたくて、AWSのCloudFrontで配信している古いサイトから外部のサイトに移行する必要があった。

  • old.example.comはCloudFrontを使ってS3に入っているコンテンツを配信しているサイト
  • new.example.comはAWS外でホスティングしているサイト

古いサイトのページはアクセス数が少ないため、内容は移行せずold.example.com/*に来たアクセスを一律new.example.com/homeにリダイレクトするのが今回の要件。

なお、AWSのリソースや設定はTerraformで管理している。

やったことその① HostNameReplaceKeyWithでURLを完全に書き換える

まずはリダイレクトの基本設定として、RoutingRulesRedirectRuleを追加する。

ReplaceKeyWithを使ってすべてのリクエストを同じURLにリダイレクトする。そして、今回リダイレクトしたいURLはドメインも違うのでHostNameでリダイレクト先のドメインになる。(外部のドメインになるということは特に意識する必要はない。)

website {
  routing_rules = jsonencode([
    {
      Redirect = {
        HostName         = "new.example.com"
        HttpRedirectCode = "301"
        Protocol         = "https"
        ReplaceKeyWith   = "home"
      }
    }
  ])
}

こうするとドメインもそれ以降のURL(CloudFormationでS3オブジェクトのキーとして使われていた部分)も置き換えられる。

やったことその② IndexDocument を追加する

すべてのリクエストをリダイレクトしているからIndexDocumentはいらないと思っていたけど、 terraform applyをしたら以下のエラーが発生した。

Error: Must specify either index_document or redirect_all_requests_to.

どうやらTerraformの使用上、redirect_all_requests_toを使っていない限り、IndexDocumentの設定が必須。

website {
  index_document = "home"
  routing_rules = jsonencode([
    {
      Redirect = {
        HostName         = "new.example.com"
        HttpRedirectCode = "301"
        Protocol         = "https"
        ReplaceKeyWith   = "home"
      }
    }
  ])
}

ページを含めて移行していたら、redirect_all_requests_toですべてのリクエストのドメインだけを変えてリダイレクトを設定できるけど、どのリクエストでも固定したページにリダイレクトしたいのでIndexDocumentとして現在の「Default Root Object」のキーを設定することにした。

やったことその③ CloudFrontのOriginを変更する

上記のリダイレクト設定は正しいが、そもそもリダイレクトを使うためにCloudFrontが使っているS3 BucketのURLを変更する必要があるのが分かった。

NG: old-example-files.s3.amazonaws.com
OK: old-example-files.s3-website.ap-northeast-1.amazonaws.com

(CloudFrontのOrigin設定なのでブラウザに入力するURLと関係ない)

origin {
- domain_name = aws_s3_bucket.old_example_files.bucket_domain_name
+ domain_name = aws_s3_bucket.old_example_files.website_endpoint
  origin_id   = "S3-old-example-files"
}

Terraformの場合、aws_s3_bucketのリソースにwebsite_endpointという属性が使える。

やったことその④ Custom Origin Configを追加する

リソースの変更は成功したけど、ブラウザで古いサイトのページにアクセスしてみるとそもそも開かない…

When we want to create a CloudFront origin for a S3 static website, we must define a custom_origin_config, otherwise it won't work.

Custom Origin Configの設定も必要か。

origin {
  domain_name = aws_s3_bucket.old_example_files.website_endpoint
  origin_id   = "S3-old-example-files"

  custom_origin_config {
    http_port              = 80
    https_port             = 443
    origin_protocol_policy = "https-only"
    origin_ssl_protocols   = ["TLSv1.2"]
  }
}

やったことその⑤ 使っているAWSリージョンの正しいウェブサイトエンドポイントを使うようにする

AWSリージョンによってURLが違うよ、とAWSのドキュメンテーションに書いてあったからTerrraformがよしなにやってくれると思いきや、そうでもなかった…

NG: old-example-files.s3-website-ap-northeast-1.amazonaws.com
OK: old-example-files.s3-website.ap-northeast-1.amazonaws.com

どのリージョンでも、Terraformのwebsite_endpointが生成するのは上の方になる。

リージョンはTerraformの変数として用意して、正しいURLを生成するロジックを自前で実装した。

-domain_name = aws_s3_bucket.old_example_files.website_endpoint
+domain_name = "${aws_s3_bucket.old_example_files.bucket}.s3-website.${var.aws_region}.amazonaws.com"

ap-northeast-1以外のリージョンを使う予定はなかったけど、他のリージョンも使使いたい場合は適切なロジックを組めばいい。各リージョンのウェブサイトエンドポイントがこちらで確認できる。

やったことその⑥ HTTPステータスによってリダイレクトするように変更する

ここまで来てやっとリダイレクトできるようになった :tada:

ただ、そもそもBucketの中身も消したい…と思った時、この設定ではいけない。S3にファイルがある前提の設定になるので、コンテンツがなくても対応できるように少し変える必要がある。

website {
  index_document = "home"
  routing_rules = jsonencode([
    {
      Redirect = {
        HostName         = "new.example.com"
        HttpRedirectCode = "301"
        Protocol         = "https"
        ReplaceKeyWith   = "home"
      }
+     RoutingRuleCondition = {
+       HttpErrorCodeReturnedEquals = "404"
+     }
    }
  ])
}

RoutingRuleConditionを追加することで、リクエストされたオブジェクトが見つからない時だけリダイレクトするように変わる。S3 Bucketのすべてのオブジェクトを削除する予定なので、どのリクエストも404になる。つまり、どのリクエストもリダイレクトされる。

最後に

ここまですれば古いサイトへのリクエストはすべて新しいサイトにリダイレクトされるし、古いS3の中身を消してもOK!

:warning: 1点だけ注意が必要 :warning:

リダイレクトさせるためにS3のBucket自体とCloudFrontのDistributionが必要になるので、リダイレクトさせたい間はリソースを残し続けないといけない。

リダイレクトをやめて古いサイトを完全に捨てる、ということになったらもちろんこれらのリソースも削除しちゃっても問題ない。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?