この記事で作れるもの
- ウェブサイト、SPAの公開
- 独自ドメインの使用
- SSL証明書を発行しセキュアな通信
- アクセスログ収集
- サーバレスアーキテクチャ
料金
- ドメイン取得
- Route 53
- CloudFront
- S3
構築のみであればドメイン取得(1円〜)、Route 53(0.5ドル)で出来ます。
事前準備
- お名前ドットコムでドメイン取得
- AWS ACMで証明書発行(CloudFront使用の為
米国東部 (バージニア北部) us-east-1で発行してください!!) - Route 53にホストゾーン作成
下記の記事を参考に準備して頂きACM発行リージョンを米国東部 (バージニア北部) us-east-1にしてください!
[AWS] 徹底図解!お名前.comで取得したDNSをAWS Route53/Cloudfrontで管理するまでの手順
サブドメイン分の発行もお忘れなく!
example.com
*.example.com
事前準備が完了したら実装!
マネージメントコンソールでぽちぽち作るのは面倒なのでCloudFormationで作ります!
まずはCloudFormationを知りたいよって方は↓
CloudFormationの全てを味わいつくせ!「AWSの全てをコードで管理する方法〜その理想と現実〜」 #cmdevio
まずは下記のコードをまるっとコピってyamlファイルをローカルに作成します。
例) example.yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: This CloudFormation template to create static website.(S3, CloudFront, ACM)
Parameters:
BucketName:
Type: String
WebsiteDomainName:
Type: String
CFSSLCertificateId:
Type: String
HostZoneId:
Type: String
Resources:
S3Bucket:
Type: AWS::S3::Bucket
DeletionPolicy: Retain
Properties:
BucketName: !Ref BucketName
LoggingConfiguration:
DestinationBucketName: !Ref "S3BucketAccesslogs"
LogFilePrefix: !Sub "s3/${AWS::StackName}"
LifecycleConfiguration:
Rules:
- Id: NoncurrentVersionExpiration
Status: Enabled
NoncurrentVersionExpirationInDays: 45
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
VersioningConfiguration:
Status: Enabled
Tags:
- Key: CloudFormationArn
Value: !Sub "${AWS::StackName}"
S3BucketAccesslogs:
Type: AWS::S3::Bucket
DeletionPolicy: Retain
Properties:
AccessControl: LogDeliveryWrite
BucketName: !Sub "${AWS::StackName}-accesslogs-${AWS::Region}-${AWS::AccountId}"
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
LifecycleConfiguration:
Rules:
- Id: AutoDelete
Status: Enabled
ExpirationInDays: 10
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
Tags:
- Key: CloudFormationArn
Value: !Sub "${AWS::StackName}"
CloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: !Ref AWS::StackName
S3BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref S3Bucket
PolicyDocument:
Statement:
- Sid: AllowGetObjectForUsersFromCloudFront
Action: s3:GetObject
Effect: Allow
Resource: !Sub arn:aws:s3:::${S3Bucket}/*
Principal:
AWS: !Sub arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${CloudFrontOriginAccessIdentity}
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Aliases:
- !Ref WebsiteDomainName
Origins:
- DomainName: !GetAtt S3Bucket.DomainName
Id: !Sub "S3origin-${BucketName}"
S3OriginConfig:
OriginAccessIdentity: !Sub origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}
Enabled: true
DefaultRootObject: index.html
Logging:
IncludeCookies: "false"
Bucket: !Sub "${S3BucketAccesslogs}.s3-${AWS::Region}.amazonaws.com"
Prefix: !Sub "cloudfront/${AWS::StackName}"
CustomErrorResponses:
- ErrorCachingMinTTL: 300
ErrorCode: 403
ResponseCode: 200
ResponsePagePath: /index.html
Comment: !Sub "${AWS::StackName}-distribution"
DefaultCacheBehavior:
TargetOriginId: !Sub "S3origin-${BucketName}"
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
DefaultTTL: 3600
MaxTTL: 86400
MinTTL: 60
Compress: true
ForwardedValues:
Cookies:
Forward: none
QueryString: false
ViewerCertificate:
SslSupportMethod: sni-only
AcmCertificateArn: !Sub "arn:aws:acm:us-east-1:${AWS::AccountId}:certificate/${CFSSLCertificateId}"
Tags:
- Key: CloudFormationArn
Value: !Sub "${AWS::StackName}"
DnsRecord:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneId: !Ref HostZoneId
Comment: "DNS for CloudFront"
Name: !Ref WebsiteDomainName
Type: A
AliasTarget:
HostedZoneId: "Z2FDTNDATAQYW2"
DNSName: !GetAtt CloudFrontDistribution.DomainName
Outputs:
DistributionID:
Value: !Ref CloudFrontDistribution
DomainName:
Value: !GetAtt CloudFrontDistribution.DomainName
- ログ用のバケットのオブジェクトはライフサイクルで保存期間を10日にしています。
- OAIを使用してアクセスをCloudFrontからのみに制限をしています。
- ※ パブリック設定の為CloudFrontの料金が発生する可能性があります。WAF、バケットポリシーでアクセスを限定的にすることも出来ます。Amazon S3 バケットにアクセスできる VPC エンドポイントまたは IP アドレスを指定するにはどうすればよいですか?
- DefaultCacheBehaviorなど自分好みで変更して下さい。
デプロイ
マネージメントコンソールにログインしCloudFormationに移動します。
[スタックの作成]をクリック
テンプレートファイルのアップロードで先ほどローカルに保存したyamlファイルを選択
パラメータの入力
##### スタックの名前 適当につけますBucketName
S3の全リージョン(地域)にてユニークな名前のBucketNameをつけます。
使えない文字などがあるので注意!Amazon S3 バケットの命名要件
WebsiteDomainName
サブドメインをつけ入力します。
例)www.example.com
CFSSLCertificateId
ACMで発行したSSL証明書の識別子を入力
米国東部 (バージニア北部) us-east-1になっていることを確認!!
HostZoneId
Route 53に作成したホストゾーンのホストゾーンIDを入力
残りはデフォルトのまま作成!
5分ちょい位で出来ると思います
S3にindex.htmlファイルをアップロード
CloudFormationで作成したバケット({BucketName}がついてるもの)に適当なindex.htmlをアップロードし、
{WebsiteDomainName}でアクセス出来れば完成!
※ S3にアップロード後すぐに{WebsiteDomainName}アクセスするとアクセス拒否されるのでアップロード後30分ほど(もう少し短くても大丈夫?)待ってからアクセスしてみて下さい。
※ ファイルの更新が反映されない時はCloudFrontのキャッシュをクリアするか、キャッシュの有効期限が切れるのを待つ必要があります。
CLIでデプロイ
ログインの手間も省けるし個人的にはCLIでの実行がおすすめ
#!/bin/bash
CFN_TEMPLATE=YOUR TEMPLETE NAME
CFN_STACK_NAME=YOUR STACK NAME
BucketName=YOUR BUCKET NAME
WebsiteDomainName=YOUR DOMAIN NAME
CFSSLCertificateId=YOUR CERTIFICATEID
HostZoneId=ROUTE53 HOSTZONEID
aws cloudformation deploy --template ${CFN_TEMPLATE} --stack-name ${CFN_STACK_NAME} \
--parameter-overrides \
BucketName=${BucketName} \
WebsiteDomainName=${WebsiteDomainName} \
CFSSLCertificateId=${CFSSLCertificateId} \
HostZoneId=${HostZoneId}
$ sh deploy.sh
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - YOUR STACK NAME
CodePipelineを使って自動デプロイを追加実装したい方
マネージメントコンソール実装です↓
CodePipelineで誰でもお手軽自動デプロイ(静的webページ編)
参考
CloudFormationの全てを味わいつくせ!「AWSの全てをコードで管理する方法〜その理想と現実〜」 #cmdevio
5分でできるS3とCloudFrontを利用したセキュアな静的Webサイトの作り方
AWS::CloudFront::Distribution
AWS::Route53::RecordSet