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.