Edited at

特定のサイトにリダイレクトするだけのページをサーバーレスで構築する方法(HTTPS対応)

サービスのドメイン変更などの理由によって、特定のドメインへのアクセスをすべて別ドメインにリダイレクトしたくなったとします。

この記事ではこれをサーバーレスで構築してみたいと思います。


お題


  • 特定のドメインへのアクセスをすべて他のページにリダイレクトする

  • 管理コストを低減するためにサーバーレスで構築したい

  • 常時HTTPSが当たり前の時代なので、HTTPS対応をしたい

  • インフラコストを低く抑えたい(awsの無料利用枠の範囲内くらいにしたい)


出来上がったもの

これらのページにアクセスをすると弊社社員である遠藤のfacebookにリダイレクトされます。

http://endo.farm/

https://endo.farm/


構成

まず、構築してみたシステムの構成を紹介します。

リダイレクトを行っているのはS3で、その手前にはHTTPS終端のためにCloudFrontを配置してあります。

ACMでSSL証明書を取得することで無料でHTTPSを利用することができます。

また、Route53のALIASレコード機能を使うことでZone Apexに対しても名前解決を行うことができます。


説明

ではここから、これらの設定をCloudFormationのテンプレートファイルを利用して説明します。

なお、完全なCloudFormationのテンプレートファイルは以下のリポジトリにあります。

https://github.com/shio-phys/endo-farm


Route53

まずは、Route53のHosted Zoneがないと何も始まらないので作ります。

なお、Route53を使ってドメインの登録をしている場合は自動的にHosted Zoneが作られているので、これは不要です。

Parameters:

NakedDomain:
Type: 'String'
Default: 'endo.farm'
Resources:
Route53HostedZoneEndoFarm:
Type: "AWS::Route53::HostedZone"
Properties:
Name: !Ref NakedDomain


ACM

ACMを使って証明書を取得します。

なお、CloudFrontにこの証明書をアタッチするために、必ずus-east-1リージョンで証明書を取得して下さい。

Parameters:

NakedDomain:
Type: 'String'
Default: 'endo.farm'

Resources:
CertificateManagerCertificateEndoFarm:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref NakedDomain
ValidationMethod: 'DNS'

テンプレートの適用をしている最中の画面で、このDNSレコードを登録して下さいという旨のメッセージが出るのでそれに従って、CNAMEレコードの登録を行います。

Resources:

Route53RecordSetCNAMENakedDomain:
Type: 'AWS::Route53::RecordSet'
Properties:
HostedZoneId: !Ref Route53HostedZoneEndoFarm
Name: <画面に表示されたドメイン名>
ResourceRecords:
- <画面に表示されたドメイン名>
TTL: 60
Type: 'CNAME'

DNSレコードが登録されたあとに暫く待つと、証明書が使えるようになります。


S3 + CloudFront

次にS3とCloudFrontの設定を行います。

S3のWebsiteConfigurationを利用してリダイレクトを設定します。

そして、その前段にCloudFrontを配置します。

このときの注意点はOriginを指定する時にS3のバケットを直に指定するのではなく、そのwebSiteURLを指定することです。

この設定にしないとCloudFrontはS3バケットに設定したWebsiteConfigurationを無視します。

Parameters:

AcmCertificateArnEndoFarm:
Type: 'String'
Default: <SSL証明書のARN>

Resources
S3BucketEndoFarm:
Type: 'AWS::S3::Bucket'
Properties:
AccessControl: Private
BucketName: !Ref NakedDomain
WebsiteConfiguration:
IndexDocument: 'index.html'
RoutingRules:
- RedirectRule:
HostName: 'www.facebook.com'
ReplaceKeyWith: 'mari.endou.75'
HttpRedirectCode: '302'

CloudFrontDistributionEndoFarm:
Type: 'AWS::CloudFront::Distribution'
Properties:
DistributionConfig:
Enabled: true
Origins:
- Id: !Sub S3-${NakedDomain}
DomainName: !Select [1, !Split ['://', !GetAtt S3BucketEndoFarm.WebsiteURL] ]
CustomOriginConfig:
OriginProtocolPolicy: 'http-only'
Aliases:
- !Ref NakedDomain
DefaultCacheBehavior:
DefaultTTL: 0
ForwardedValues:
QueryString: false
MaxTTL: 0
MinTTL: 0
TargetOriginId: !Sub S3-${NakedDomain}
ViewerProtocolPolicy: 'allow-all'
HttpVersion: 'http2'
IPV6Enabled: true
ViewerCertificate:
AcmCertificateArn: !Ref AcmCertificateArnEndoFarm
MinimumProtocolVersion: 'TLSv1.1_2016'
SslSupportMethod: 'sni-only'


ZoneApexに対するAレコード

最後にZoneApexに対してAレコードを設定すれば完成です。

ZoneApexに対するCNAMEは設定できないので、必ずAliasTargetを利用してAレコードを登録して下さい。

Resources:

Route53RecordSetANativeDomain:
Type: 'AWS::Route53::RecordSet'
Properties:
HostedZoneId: !Ref Route53HostedZoneEndoFarm
Name: !Ref NakedDomain
AliasTarget:
DNSName: !GetAtt CloudFrontDistributionEndoFarm.DomainName
HostedZoneId: !Ref Route53HostedZoneEndoFarm
Type: 'A'


費用

さて、この構成の費用はいくらになるでしょうか?

アクセスが十分に少なく、aws無料利用枠の範囲内に入っている場合は月額$1.5( + ドメイン取得費用)で運用することができます。

なお、この$1.5はRoute53のHostedZoneに対する課金額です。


まとめ

特定のサイトにリダイレクトするだけのページをサーバーレスで構築することができました。