0
2

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.

CloudFormationで作る!独自ドメインを使った静的Webサイト

Posted at

この記事で作れるもの

  • ウェブサイト、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

デプロイ :rocket:

マネージメントコンソールにログインしCloudFormationに移動します。

[スタックの作成]をクリック

テンプレートファイルのアップロードで先ほどローカルに保存したyamlファイルを選択

パラメータの入力

##### スタックの名前 適当につけます
BucketName

S3の全リージョン(地域)にてユニークな名前のBucketNameをつけます。
使えない文字などがあるので注意!Amazon S3 バケットの命名要件

WebsiteDomainName

サブドメインをつけ入力します。
例)www.example.com

CFSSLCertificateId

ACMで発行したSSL証明書の識別子を入力
米国東部 (バージニア北部) us-east-1になっていることを確認!!

HostZoneId

Route 53に作成したホストゾーンのホストゾーンIDを入力

残りはデフォルトのまま作成!
5分ちょい位で出来ると思います:smile:

S3にindex.htmlファイルをアップロード

CloudFormationで作成したバケット({BucketName}がついてるもの)に適当なindex.htmlをアップロードし、
{WebsiteDomainName}でアクセス出来れば完成!

※ S3にアップロード後すぐに{WebsiteDomainName}アクセスするとアクセス拒否されるのでアップロード後30分ほど(もう少し短くても大丈夫?)待ってからアクセスしてみて下さい。

※ ファイルの更新が反映されない時はCloudFrontのキャッシュをクリアするか、キャッシュの有効期限が切れるのを待つ必要があります。

CLIでデプロイ :rocket:

ログインの手間も省けるし個人的にはCLIでの実行がおすすめ

deploy.sh
#!/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

0
2
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
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?