AWSでURLリダイレクトを設定する方法

この記事は[レコチョク Advent Calendar 2024](https://qiita.com/advent-calendar/2024/recochoku)の19日目の記事となります。

## はじめに
こんにちは。
次世代プロダクト開発Gで、主にバックエンド領域で業務をしている徐と申します。

今年もAdvent Calendar シーズンがやってきました！

担当しているサービスのEggs Passは、2020年5月にリリースされて以来、たくさんのユーザーが楽曲を配信しています。Eggs Passでは、楽曲を登録するだけで、Apple Music、Spotify、LINE MUSIC、レコチョクなど、世界中の音楽配信ストアを通じて、楽曲の販売だけでなく、配信や権利収益化なども可能です！
![スクリーンショット 2024-12-11 19.12.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2423004/04032e23-0e4f-7900-69dd-809873121abf.png)


今後も、たくさんの機能を追加する予定ですので、ぜひご注目ください。

さらに詳しく知りたい方は、以下のリンクをご確認ください。
https://eggspass.jp/distribution/

## 今回のテーマ
直近の業務では、しばらくの間、旧ドメインを新ドメインにURLリダイレクトしたいという要望があり、その設定作業を行いました。
また、インフラには主にAWSを利用しているため、今回はAWSでのURLリダイレクト設定方法について共有したいと思います。

## 内容に関して
本記事は、ある程度AWSの利用経験がある方を対象としています。記事内では、URLリダイレクトを設定する際に必要な新規リソースの作成や変更点に重点を置いて解説しますが、すべての構築手順や関連するAWSサービスの詳細については割愛しています。

内容や手順については、2024年12月10日時点の情報を基に記載しています。また、AWSのアップデートによりUIや仕様が変更になる可能性がありますので、添付画像などの内容が古くなることもご了承ください。

## 目次
  - 背景・課題
  - 必要なリソース
  -  CloudFormationのサンプルテンプレート
  -  まとめ

## 背景・課題
経験としてはあまりないことかもしれませんが、開発を担当しているプロジェクトで途中でサービス名（以下、遷移元のドメイン名）が変更になるという状況に直面しました。その結果、今まで使用していたサイトを別のドメイン（以下、遷移先のドメイン名）に変更しなければならなくなりました。

ただ、いきなりサービスのドメインを変更すると、ユーザーは慣れ親しんだドメインにアクセスし続けるため、突然のドメイン変更は混乱を招き、アクセス障害やユーザー離れにつながる可能性があります。また、検索エンジンに対する影響も大きく、検索エンジン最適化（以下、SEO)の評価の低下が懸念されるなどの問題があります。これらの問題を解決するため、一定の期間を設けてURLリダイレクトを設定し、ユーザー体験の維持やSEOの評価保護などを図りたいと考えています。

## 必要なリソース
  - S3
  - CloudFront
  - Route53

### S3作成
#### 1. S3の「プロパティ」から「静的ウェブサイトホスティング」に移動
![スクリーンショット 2024-11-29 10.29.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2423004/197fd28c-b093-6553-4b57-378b91d45422.png)

#### 2.「編集」ボタンを押して、下記の画像のように設定
![スクリーンショット 2024-11-29 11.30.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2423004/d586f6d2-c82f-0646-804e-07ecc7ebb17e.png)

### CloudFront作成
#### 1.CloudFrontから「ディストリビューションを作成」ボタンを押下
![スクリーンショット 2024-11-29 10.53.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2423004/ee78a0d5-1d21-52f9-03cb-8cd13be45277.png)


#### 2.オリジンの設定

![スクリーンショット 2024-11-29 10.46.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2423004/ef70716b-3168-ed9e-44fb-535538f79b9f.png)

＊先ほど作成したS3バケットを選択し、「Webサイトのエンドポイントを使用」をクリックして、自動的に、以下の画像のように設定されることを確認してください。

![スクリーンショット 2024-11-29 10.49.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2423004/6e0e958a-cf0f-2fa5-b058-b40e94e322fc.png)

#### 3.デフォルトのキャッシュビヘイビア
![スクリーンショット 2024-11-29 10.52.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2423004/be7e864e-c600-2078-5970-eaefdef3a5dd.png)

#### 4.キャッシュキーとオリジンリクエスト
![スクリーンショット 2024-11-29 11.02.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2423004/793d4eb4-63aa-5627-586d-c06217b37b05.png)

＊クエリパラメータを保持したままのリダイレクト処理したい場合は、「クエリ文字列」を「すべて」に選択する必要はあります。

#### 5.ウェブアプリケーションファイアウォール (WAF)
![スクリーンショット 2024-11-29 11.04.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2423004/9bca88ff-9c12-3cce-097c-9f3b70e52839.png)

#### 6.設定
![スクリーンショット 2024-11-29 11.25.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2423004/62dd7b06-be01-aca4-5d3c-57fdf0d1554b.png)

### Route53作成
#### 1.Route53の「ホストゾーン詳細」から「レコードを作成」を押下
![スクリーンショット 2024-11-29 11.33.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2423004/d21c5cd4-b9c4-c6a3-484e-76a41f7ce028.png)

#### 2.レコードを作成
![スクリーンショット 2024-11-29 11.36.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2423004/f4cdd7ab-0424-d381-9b25-2a66d6667f3f.png)

必要な資材と設定は以上です。
最後に、ブラウザでURLを開き、正常に遷移するか確認してください！

## CloudFormationのサンプルテンプレート
#### 1.S3のサンプルテンプレート
```
Description: >
  Create Redirect S3 Buckets for Redirect

Parameters:

  OrganizationName:
    Description: Organization name
    Type: String

  EnvironmentName:
    Description: An environment name that will be prefix to resource names
    Type: String
    AllowedValues:
      - dev
      - dvm
      - pro

  HostName:
    Description: Host name
    Type: String

Resources:
  TestRedirectBucket:
    Type: AWS::S3::Bucket
    Properties:
      AccessControl: BucketOwnerFullControl
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
            BucketKeyEnabled: true
      BucketName: !Sub ${OrganizationName}-test-website-${EnvironmentName}
      WebsiteConfiguration:
        RedirectAllRequestsTo:
          HostName: !Sub ${HostName}
          Protocol: https
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      Tags:
        - Key: name
          Value: redirect bucket

Outputs:
  TestRedirectBucketName:
    Description: The name of the S3 bucket created for redirection
    Value: !Ref TestRedirectBucket
    Export:
      Name: !Sub ${OrganizationName}-TestRedirectBucketName-${EnvironmentName}
  TestRedirectWebsiteURL:
    Description: The URL of the S3 bucket website endpoint
    Value: !GetAtt TestRedirectBucket.WebsiteURL
    Export:
      Name: !Sub ${OrganizationName}-TestRedirectWebsiteURL-${EnvironmentName}
  TestRedirectBucketOrigin:
    Description: The origin domain name of the S3 bucket
    Value: !Sub ${OrganizationName}-test-website-${EnvironmentName}.s3-website-ap-northeast-1.amazonaws.com
    Export:
      Name: !Sub ${OrganizationName}-TestRedirectBucketOrigin-${EnvironmentName}
```

#### 2.CloudFrontのサンプルテンプレート
```
Description: >
  Create CloudFront Distribution Origin S3

Parameters:

  EnvironmentName:
    Description: An environment name that will be prefix to resource names
    Type: String
    AllowedValues:
      - dev
      - dvm
      - pro

  OrganizationName:
    Description: Organization name
    Type: String

  OriginPath:
    Description: origin bucket name
    Type: String

  WebACL:
    Description: WebACL id of global WAF
    Type: String

  ACMArnResourceId:
    Description: SSL certificate(ACM) arn resource id
    Type: String

Resources:

  TestDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Enabled: true
        Comment: brand rename
        Aliases:
          - !Sub ${OriginPath}
        DefaultCacheBehavior:
          TargetOriginId: myCustomOrigin
          SmoothStreaming: false
          ForwardedValues:
            Cookies:
              Forward: none
            Headers: []
            QueryString: true
          AllowedMethods:
            - GET
            - HEAD
          CachedMethods:
            - GET
            - HEAD
          Compress: true
          ViewerProtocolPolicy: allow-all
        HttpVersion: http2
        Origins:
          - Id: myCustomOrigin
            DomainName:
              Fn::ImportValue: !Sub ${OrganizationName}-TestRedirectBucketOrigin-${EnvironmentName}
            CustomOriginConfig:
              HTTPPort: 80
              OriginProtocolPolicy: http-only
        WebACLId: !Ref WebACL
        ViewerCertificate:
          AcmCertificateArn: !Sub arn:aws:acm:us-east-1:${AWS::AccountId}:certificate/${ACMArnResourceId}
          SslSupportMethod: sni-only
          MinimumProtocolVersion: TLSv1.2_2021

  TestCloudFrontOriginAccessIdentity:
    Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
    Properties:
      CloudFrontOriginAccessIdentityConfig:
        Comment: CloudFrontOriginAccessIdentity

Outputs:

  TestDistribution:
    Description: Distribution id.
    Value: !Ref TestDistribution
    Export:
      Name: !Sub ${OrganizationName}-Test-distribution-${EnvironmentName}

  TestCloudFrontOriginAccessIdentity:
    Description: CloudFrontOriginAccessIdentity
    Value: !Ref TestCloudFrontOriginAccessIdentity
    Export:
      Name: !Sub ${OrganizationName}-Test-CloudFrontOriginAccessIdentity-${EnvironmentName}

  TestDistributionDomainName:
    Description: Domain name of the distribution
    Value: !GetAtt TestDistribution.DomainName
    Export:
      Name: !Sub ${OrganizationName}-Test-DistributionDomainName-${EnvironmentName}
```

#### 3.Route53のサンプルテンプレート
```
Description: >
  Create Route 53 RecordSet

Parameters:
  EnvironmentName:
    Description: An environment name that will be prefixed to resource names
    Type: String
    AllowedValues:
      - dev
      - dvm
      - pro

  OrganizationName:
    Description: Organization name
    Type: String

Mappings:
  EnvMap:
    HostedZoneName:
      dev: aaaa.develop.sample.net.
      dvm: aaaa.develop.sample.net.
      pro: aaaa.product.sample.net.

Conditions:

  IsDevEnvironment:
    Fn::Equals: [ !Ref EnvironmentName, "dev" ]

Resources:
  TestDNSRecord:
    Type: AWS::Route53::RecordSet
    Properties:
      AliasTarget:
        DNSName:
          Fn::ImportValue: !Sub ${OrganizationName}-Test-DistributionElbDomainName-${EnvironmentName}
        HostedZoneId: AAABBBCCCDDD
      HostedZoneName:
          Fn::FindInMap:
            - EnvMap
            - HostedZoneName
            - !Ref EnvironmentName
      Name: !Join
        - "."
        - - !Sub sub-domain-${EnvironmentName}
          - Fn::FindInMap:
            - EnvMap
            - HostedZoneName
            - !Ref EnvironmentName
      Type: A

Outputs:
  TestDNSRecordName:
    Description: The DNS record created for the CloudFront distribution
    Value: !Ref TestDNSRecord
```

## まとめ

本記事では、AWSでURLリダイレクトを設定する方法ついてご紹介しました。
この記事が皆さまのお役に少しでも立てば幸いです！最後まで読んでいただきありがとうございました。

明日の[レコチョク Advent Calendar 2024](https://qiita.com/advent-calendar/2024/recochoku)は20日目「【Kotlin】初心者がJetpack Composeでチンチロゲームを作ってみる 」です。お楽しみに！

この記事はレコチョクのエンジニアブログの記事を転載したものとなります。 
 
https://techblog.recochoku.jp/11472