In this blog post I will walk you through how to configure a single page application or website. In a previous blog Best practices for S3 web hosting and explaining why. Tibor Hercz explained the best practices for hosting a static website on S3.
As Tibor explained, there are some downsides on using a Origin Access Identity (OAI)
. But in some Single Page Applications (SPA)
you will not experience this downside.
What is a single page application?
A single page application loads a single web document. Based upon your interaction with this page the content is updated.
The pages are rendered on your web browser. And more API calls are performed to fetch extra input. Due to this fact an SPA can be fast!
You can use the framework of your choice: angular, reactjs, vue, etc, etc.
Setting up the infrastructure
For simplicity, I am providing CloudFormation snippets.
First we will need an S3 bucket to host the application in. We need an OAI. And we need to grant it access yo the bucket:
MyBucket:
Type: AWS::S3::Bucket
Properties:
AccessControl: Private
MyOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: Allows CloudFront to reach the bucket
MyBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref MyBucket
PolicyDocument:
Version: "2012-10-17"
Statement:
- Action:
- s3:GetObject*
- s3:GetBucket*
- s3:List*
Effect: Allow
Principal:
CanonicalUser: !GetAtt MyOriginAccessIdentity.S3CanonicalUserId
Resource:
- !GetAtt MyBucket.Arn
- !Sub ${MyBucket.Arn}/*
Next we will need the CloudFront distribution:
MyDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
CustomErrorResponses:
- ErrorCode: 404
ResponseCode: 200
ResponsePagePath: /index.html
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
Compress: true
ForwardedValues:
Cookies:
Forward: none
QueryString: false
TargetOriginId: origin
ViewerProtocolPolicy: redirect-to-https
DefaultRootObject: index.html
Enabled: true
HttpVersion: http2
IPV6Enabled: true
Origins:
- ConnectionAttempts: 3
ConnectionTimeout: 10
DomainName: !GetAtt MyBucket.RegionalDomainName
Id: origin
S3OriginConfig:
OriginAccessIdentity:
Fn::Join:
- ""
- - origin-access-identity/cloudfront/
- Ref: MyOriginAccessIdentity
Once you have set up the infrastructure. You need to build
your SPA. And upload the build to the S3 bucket.
My assumption here is that you created an app with various routes/paths.
How does it work?
When you navigate to the hostname of the created CloudFront distribution. The distribution will fall back on the index.html
file. This is because we have set the DefaultRootObject
to index.html
.
When you navigate in the application it looks like the browser is changing paths. But in fact it is only updating the address in the address bar.
Let say you created a /blog
route. You navigate to this route. And you do a hard refresh! You expect to get a 404 Not Found
error because there is no folder called blog
.
But because we configured a CustomErrorResponses
. That will redirect all 404
errors to the index.html
file with a 200
response code.
This will make sure that the Single Page Application gets loaded again. It will see the location in the address bar and renders the correct content.
This does mean that you will need to handle unknown routes in your application.
Conclusion
When you want to host a Single Page Application you can use CloudFront with private buckets. You will get all the benefits of CloudFront while keeping the bucket private.
Top comments (0)