Using AWS to Host a Static Website - Part 6
- Jamie Tyler
- Aws
- January 1, 2025
Table of Contents
In part 5 I created the SSL certificates to use with the static website. In this post, I am going to deploy Amazon CloudFront for the CDN portion. Before I do that, I am going to upload the static HTML files that will be rendered.
Using the AWSCLI to Upload Content
The content can be whatever but for ease I have provided the HTML files I am using here.
This assumes that the files to be uploaded are available locally. In this example they are in the directory static-files.
aws s3 sync ./static-files/ s3://S3_BUCKET_NAME --delete --cache-control max-age=3153600 --region us-east-1
So breaking this down.
aws s3 sync
: This command synchronizes the contents between a source and destination location. It recursively copies new and updated files./static-files/
: This is the source directory on your local machine containing the files you want to syncs3://S3_BUCKET_NAME
: This is the destination - an S3 bucket where the files will be synced to. This was defined earlier in the series of posts--delete
: This flag is important - it will remove files from the destination (S3 bucket) that don’t exist in the source directory. This ensures the destination exactly matches the source--cache-control max-age=3153600
: This sets the Cache-Control header for all uploaded files to have a maximum age of 3,153,600 seconds (approximately 36.5 days). This tells browsers and other clients how long they should cache these files--region us-east-1
: Specifies the AWS region where the S3 bucket is located (US East 1 in this case)
The Sequence
- Create the Amazon S3 bucket policy
- Create the Amazon CloudFront Origin Access Control (OAC)
- Create the Amazon CloudFront Distribution
The CloudFormation Template
This CloudFormation template is available here.
AWSTemplateFormatVersion: "2010-09-09"
Description: "CloudFront distribution with existing S3 bucket as origin"
Parameters:
ExistingBucketName:
Type: String
Description: "Name of the existing S3 bucket to use as origin"
DomainName:
Type: String
Description: "The apex domain name (e.g., example.com)"
AcmCertificateArn:
Type: String
Description: "ARN of ACM certificate (must be in us-east-1)"
TagValue:
Type: String
Description: "The tag value for the distribution"
Resources:
CloudFrontOriginAccessControl:
Type: "AWS::CloudFront::OriginAccessControl"
Properties:
OriginAccessControlConfig:
Name: !Sub "${AWS::StackName}-OAC"
Description: "Origin Access Control for S3"
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
CloudFrontDistribution:
Type: "AWS::CloudFront::Distribution"
Properties:
DistributionConfig:
Enabled: true
PriceClass: PriceClass_100 # US, Canada, Europe (not Middle East) Edge Locations
DefaultRootObject: index.html
Aliases:
- !Ref DomainName
- !Sub "www.${DomainName}"
ViewerCertificate:
AcmCertificateArn: !Ref AcmCertificateArn
MinimumProtocolVersion: TLSv1.2_2021
SslSupportMethod: sni-only
Origins:
- DomainName: !Sub "${ExistingBucketName}.s3.${AWS::Region}.amazonaws.com"
Id: S3Origin
S3OriginConfig:
OriginAccessIdentity: ""
OriginAccessControlId: !GetAtt CloudFrontOriginAccessControl.Id
DefaultCacheBehavior:
TargetOriginId: S3Origin
ViewerProtocolPolicy: redirect-to-https
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 # Managed-CachingOptimized
OriginRequestPolicyId: 88a5eaf4-2fd4-4709-b370-b4c650ea3fcf # Managed-CORS-S3Origin
Tags:
- Key: workload
Value: !Ref TagValue
S3BucketPolicy:
Type: "AWS::S3::BucketPolicy"
Properties:
Bucket: !Ref ExistingBucketName
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: "AllowCloudFrontServicePrincipalReadOnly"
Effect: Allow
Principal:
Service: "cloudfront.amazonaws.com"
Action: "s3:GetObject"
Resource: !Sub "arn:${AWS::Partition}:s3:::${ExistingBucketName}/*"
Condition:
StringEquals:
"AWS:SourceArn": !Sub "arn:${AWS::Partition}:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}"
Outputs:
DistributionDomainName:
Description: "CloudFront Distribution Domain Name"
Value: !GetAtt CloudFrontDistribution.DomainName
The parameter file.
[
{
"ParameterKey": "ExistingBucketName",
"ParameterValue": "INSERT_BUCKET_NAME"
},
{
"ParameterKey": "DomainName",
"ParameterValue": "INSERT_DOMAIN_NAME"
},
{
"ParameterKey": "AcmCertificateArn",
"ParameterValue": "INSERT_CERTIFICATE_ARN"
},
{
"ParameterKey": "TagValue",
"ParameterValue": "INSERT_DOMAIN_NAME"
}
]
Deploying the CloudFormation Template
aws cloudformation create-stack --stack-name STACKNAME --template-body file://cloufront-distribution.yaml \
--parameters file://parameters.json --region us-east-1
The STACKNAME can be whatever you choose but I recommend it is meaningful.
Conclusion
A CloudFormation template and a parameter file is a repeatable way of setting up CDN using Amazon CloudFront. In the next post I will walk through creating the appropriate DNS records.