Overview
In this post we will discuss how to set up a static HTML website in S3. We have even provided a little bonus to help you quickly get started!
Note: If you want us to help you connect your domain name or any web design or development services check out this page: Web Development Services.
Prerequisites
Quick & Sweet
For those of you that aren't interested in the technical how to and just want to launch your free HTML website on S3 use the launch stack button below.
Pretty cool huh?
Note: This does not include connecting your domain or the HTTPS protocol. You would need to add Route53 and a SSL certificate into the mix.
The Breakdown
The CloudFormation template above has a lot of operations running to get the end result. Here is the breakdown of the CloudFormation template:
- Create S3 Bucket
- Configure S3 Bucket Policy
- Create CloudFront Distribution
- Create IAM user with Access Keys
Create S3 Bucket
We need to first create the S3 bucket to contain the website HTML.
# Create the bucket to contain the website HTML S3Bucket: Type: 'AWS::S3::Bucket'
Configure S3 Bucket Policy
We also want to configure the bucket policy.
# Configure the bucket as a CloudFront Origin ReadPolicy: Type: 'AWS::S3::BucketPolicy' Properties: Bucket: !Ref S3Bucket PolicyDocument: Statement: - Action: 's3:GetObject' Effect: Allow Resource: !Sub 'arn:aws:s3:::${S3Bucket}/*' Principal: CanonicalUser: !GetAtt CloudFrontOriginAccessIdentity.S3CanonicalUserId
Create CloudFront Distribution
Then we need to configure the bucket as a CloudFront Origin which includes a read policy, CloudFront origin access identity, and CloudFront distribution.
CloudFrontOriginAccessIdentity: Type: 'AWS::CloudFront::CloudFrontOriginAccessIdentity' Properties: CloudFrontOriginAccessIdentityConfig: Comment: !Ref S3Bucket CloudFrontDistribution: Type: 'AWS::CloudFront::Distribution' Properties: DistributionConfig: CustomErrorResponses: - ErrorCode: 403 # not found ResponseCode: 404 ResponsePagePath: !Ref ErrorPagePath DefaultCacheBehavior: AllowedMethods: - GET - HEAD - OPTIONS CachedMethods: - GET - HEAD - OPTIONS Compress: true DefaultTTL: 3600 # in seconds ForwardedValues: Cookies: Forward: none QueryString: false MaxTTL: 86400 # in seconds MinTTL: 60 # in seconds TargetOriginId: s3origin ViewerProtocolPolicy: 'allow-all' DefaultRootObject: !Ref DefaultRootObject Enabled: true HttpVersion: http2 Origins: - DomainName: !GetAtt 'S3Bucket.DomainName' Id: s3origin S3OriginConfig: OriginAccessIdentity: !Sub 'origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}' PriceClass: 'PriceClass_All'
Create IAM user with Access Keys
We want to create an IAM user that can publish the website. This will require obtaining a public and private access key.
PublishUser: Type: 'AWS::IAM::User' Properties: Policies: - PolicyName: !Sub 'publish-to-${S3Bucket}' PolicyDocument: Statement: - Action: 's3:*' Effect: Allow Resource: - !Sub 'arn:aws:s3:::${S3Bucket}' - !Sub 'arn:aws:s3:::${S3Bucket}/*' PublishCredentials: Type: 'AWS::IAM::AccessKey' Properties: UserName: !Ref PublishUser
All Together Now
Here is the full code for the CloudFormation template.
AWSTemplateFormatVersion: '2010-09-09' Description: 'Static website hosting with S3 and CloudFront' Parameters: DefaultRootObject: Description: 'The default path for the index document.' Type: String Default: 'index.html' ErrorPagePath: Description: 'The path of the error page for the website (e.g. /error.html). Must be a root-relative path.' Type: String Default: '/404.html' Resources: # Create the bucket to contain the website HTML S3Bucket: Type: 'AWS::S3::Bucket' # Configure the bucket as a CloudFront Origin ReadPolicy: Type: 'AWS::S3::BucketPolicy' Properties: Bucket: !Ref S3Bucket PolicyDocument: Statement: - Action: 's3:GetObject' Effect: Allow Resource: !Sub 'arn:aws:s3:::${S3Bucket}/*' Principal: CanonicalUser: !GetAtt CloudFrontOriginAccessIdentity.S3CanonicalUserId CloudFrontOriginAccessIdentity: Type: 'AWS::CloudFront::CloudFrontOriginAccessIdentity' Properties: CloudFrontOriginAccessIdentityConfig: Comment: !Ref S3Bucket CloudFrontDistribution: Type: 'AWS::CloudFront::Distribution' Properties: DistributionConfig: CustomErrorResponses: - ErrorCode: 403 # forbidden ResponseCode: 404 # not found ResponsePagePath: !Ref ErrorPagePath DefaultCacheBehavior: AllowedMethods: - GET - HEAD - OPTIONS CachedMethods: - GET - HEAD - OPTIONS Compress: true DefaultTTL: 3600 # in seconds ForwardedValues: Cookies: Forward: none QueryString: false MaxTTL: 86400 # in seconds MinTTL: 60 # in seconds TargetOriginId: s3origin ViewerProtocolPolicy: 'allow-all' DefaultRootObject: !Ref DefaultRootObject Enabled: true HttpVersion: http2 Origins: - DomainName: !GetAtt 'S3Bucket.DomainName' Id: s3origin S3OriginConfig: OriginAccessIdentity: !Sub 'origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}' PriceClass: 'PriceClass_All' # Create an IAM user with Access Keys to enable automated deployment of the website to this bucket PublishUser: Type: 'AWS::IAM::User' Properties: Policies: - PolicyName: !Sub 'publish-to-${S3Bucket}' PolicyDocument: Statement: - Action: 's3:*' Effect: Allow Resource: - !Sub 'arn:aws:s3:::${S3Bucket}' - !Sub 'arn:aws:s3:::${S3Bucket}/*' PublishCredentials: Type: 'AWS::IAM::AccessKey' Properties: UserName: !Ref PublishUser Outputs: BucketName: Description: 'S3 Bucket Name' Value: !Ref S3Bucket AccessKeyId: Description: 'S3 Access Key' Value: !Ref PublishCredentials AccessKeySecret: Description: 'S3 Secret Key' Value: !GetAtt PublishCredentials.SecretAccessKey DistributionId: Description: 'CloudFront Distribution ID' Value: !Ref CloudFrontDistribution Domain: Description: 'Cloudfront Domain' Value: !GetAtt CloudFrontDistribution.DomainName
Conclusion
That's a wrap folks. If you enjoyed this tutorial, please let us know!
Need expert help? Work directly with James Malin now.