How to Deploy an AWS S3 Hosted React SPA through CloudFront
Introduction
The purpose of this short tutorial is to demonstrate how to deploy an AWS S3 hosted React Application using Cloud Front.
To successfully complete this tutorial you will need:
- Linux Bash shell
- React framework
- Serverless framework
- Text editor
- AWS Free tier account
Step 1: Creating a React Application
For the purposes of this tutorial a simple react application will be built using the automatic application generation tools.
The following command can be run to create a react application in the current directory:
To validate this has completed successfully, you can change into the newly created application directory aws-cloudfront-react-app and start up the react application locally (we're not in AWS yet!) as follows:
If all goes well, then depending on your OS setup you may see the following window come up in your browser. If not, you can manually open the React app by navigating to http://localhost:3000/
We now have the code for a working React Application that we are ready to build and deploy to a production environment.
Step 3: Generate a production-optimised build of the React Application
The application we have locally run at this point is not yet form suitable for public distribution through CloudFront. To achieve this,. we can run the following command:
What we get at the end of a successful build is a "build" folder that (in theory) is as simple to deploy as copying over to a web server's public HTML folder.
This folder may look something like this:
.
├── asset-manifest.json
├── favicon.ico
├── index.html
├── manifest.json
├── precache-manifest.054774adbe886ee6e3c29227ef1745b5.js
├── service-worker.js
└── static
├── css
│ ├── main.2cce8147.chunk.css
│ └── main.2cce8147.chunk.css.map
├── js
│ ├── 2.b41502e9.chunk.js
│ ├── 2.b41502e9.chunk.js.map
│ ├── main.28647029.chunk.js
│ ├── main.28647029.chunk.js.map
│ ├── runtime~main.a8a9905a.js
│ └── runtime~main.a8a9905a.js.map
└── media
└── logo.5d5d9eef.svg
We are now ready to write some infrastructure automation scripts for deploying this folder to the AWS cloud!
.
├── asset-manifest.json
├── favicon.ico
├── index.html
├── manifest.json
├── precache-manifest.054774adbe886ee6e3c29227ef1745b5.js
├── service-worker.js
└── static
├── css
│ ├── main.2cce8147.chunk.css
│ └── main.2cce8147.chunk.css.map
├── js
│ ├── 2.b41502e9.chunk.js
│ ├── 2.b41502e9.chunk.js.map
│ ├── main.28647029.chunk.js
│ ├── main.28647029.chunk.js.map
│ ├── runtime~main.a8a9905a.js
│ └── runtime~main.a8a9905a.js.map
└── media
└── logo.5d5d9eef.svg
|
Step 4: YAML File for Deployment to AWS
The Serverless Framework provides a layer of abstraction over cloud-vendor specific infrastructure automation tools, eg, CloudFormation in the case of AWS.
This section describes how to write a single Serverless Framework YAML script that will achieve the following goals:
1) Creating an AWS S3 Bucket that will host our React Application build files
2) Creating an AWS CloudFront distribution for making the React Application accessible to the public web through Amazon's content delivery network
3) Restrict the S3 Bucket to only be accessible to the public through the CloudFront distribution
3) Automatically deploying the React production optimised build to the AWS S3 bucket from the local machine
Create a file called serverless.yaml in text editor in the root of the react application folder. This is "aws-cloudfront-react-app" in our example.
This file consists of the following sections, described individually. The entire serverless.yaml file can be found on the GitHub page.
Service Name, Provider, Plugins, and Custom
The following lines show the initial part of the YAML file. The indentation in YAML files is essential to proper parsing, so if copying and pasting this, please make sure that the spaces are exactly as given here:
- The Service Name describes the overall infrastructure stack - this can be anything you like
- The provider for this tutorial is AWS, and the region I'm deploying into is EU-WEST-2. The runtime section is not relevant to our tutorial but still has to be present. Although the Serverless Framework supports other cloud providers, this tutorial will only work on AWS due to the specific Amazon resource dependencies such as S3.
-
The plugins section includes an entry for a plugin that will allow automatic deployment of the production build to an S3 bucket.
- The custom section defines the name of the S3 bucket we want to create - remember this has to be unique across the entire set of all S3 buckets, so you may need to adjust this variable
- The custom section includes a directive telling the plugin that the build folder (which contains our production optimised react build) needs to be uploaded to S3
The plugins section includes an entry for a plugin that will allow automatic deployment of the production build to an S3 bucket.
S3 Bucket
Next, we have the Resources section which includes AWS-specific Resource configurations. The first of these is an S3 Bucket definition. The bucket is defined as publicly readable, and some instruction is given to AWS to treat this bucket as a website, rather than just a file object store. The ${XXXXXX} syntax enables the serverless framework to cross reference any constants declared in the custom section. If the referenced bucket name is already taken, an alternative can be declared in the siteName constant .
CloudFront Origin Access Identity
This section puts a layer of security over the bucket read access, insuring that it's only ever accessed through the CloudFront network. A special type of identity is a created for this purpose and a Bucket Policy is applied which allows the CloudFront original access identity to call S3 Get Object.
CloudFront Distribution
The following portion is the setup of a CloudFront content distribution network (CDN) in front of an Origin Server, which in our example is the S3 bucket created earlier. The CDN ensures that consumers load the React application as fast as possible by 1) delivering it through their nearest edge location and 2) caching it for future requests. The caching time-to-live (TTL) settings are specified in seconds, so the DefaultTTL setting means that any new features or bugfixes on the React App would not show up for the user until a minute - this is a trade-off from caching.
Although it's not relevant for S3 origins, the MaxTTL setting ensures that irrespective of HTTP cache headers on the origin response, resources are not cached for any longer than 24hrs.
Step 5: Generate AWS Stack & Deploy SPA using the Serverless Framework
Before this YAML script can be executed through the Serverless framework deployment process, the serverless-s3-sync plugin needs to be installed. Serverless framework plugins are installed on a per-service basis, so the following command has to be run within the "aws-cloudfront-react-app" folder:
Once this has been done, you can run the deployment into AWS as follows. This process will take a long time (~15 minutes) when run for the first time, and whenever any configuration settings are changed on the CloudFront distribution. Presumably, this is because the CloudFront resource deployments require global distribution to all of Amazon's CDN edge locations.
jafrimo@LP00650:~/tutorials/aws-cloudfront-react-app$ sls deploy --force --verbose
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Validating template...
Serverless: Updating Stack...
Service Information
service: aws-cloudfront-react-app
stage: dev
region: eu-west-2
stack: aws-cloudfront-react-app-dev
resources: 5
api keys:
None
endpoints:
None
functions:
None
layers:
None
Stack Outputs
ReactAppDistributionOutput: d3o2e8g5rtoidi.cloudfront.net
ServerlessDeploymentBucketName: aws-cloudfront-react-app-serverlessdeploymentbuck-k7pzdbyvk1zr
S3 Sync: Syncing directories and S3 prefixes...
.
S3 Sync: Synced.
jafrimo@LP00650:~/tutorials/aws-cloudfront-react-app$ sls deploy --force --verbose
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Validating template...
Serverless: Updating Stack...
Service Information
service: aws-cloudfront-react-app
stage: dev
region: eu-west-2
stack: aws-cloudfront-react-app-dev
resources: 5
api keys:
None
endpoints:
None
functions:
None
layers:
None
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Validating template...
Serverless: Updating Stack...
Service Information
service: aws-cloudfront-react-app
stage: dev
region: eu-west-2
stack: aws-cloudfront-react-app-dev
resources: 5
api keys:
None
endpoints:
None
functions:
None
layers:
None
Stack Outputs
ReactAppDistributionOutput: d3o2e8g5rtoidi.cloudfront.net
ServerlessDeploymentBucketName: aws-cloudfront-react-app-serverlessdeploymentbuck-k7pzdbyvk1zr
ReactAppDistributionOutput: d3o2e8g5rtoidi.cloudfront.net
ServerlessDeploymentBucketName: aws-cloudfront-react-app-serverlessdeploymentbuck-k7pzdbyvk1zr
S3 Sync: Syncing directories and S3 prefixes...
.
S3 Sync: Synced.
.
S3 Sync: Synced.
Step 6: Validate publicly accessible web application
If all has worked, you should be able to browse to the URL shown under "ReactAppDistributionOutput" to view the website, .eg,, https://d3o2e8g5rtoidi.cloudfront.net. from the example given here. The output should unsurprisingly be the same as Step1
Step 7: Make a Change in React Application Code and Republish
We can now start changing our application to shape into whatever we want. Lets' simply change line of code from src/App.js as follows:
The production optimised build needs to be re-done to reflect this now
After doing this we rredploy our application. Notice how, this time, there is no re-instantiation of either the S3 bucket or the CloudFront distribution. The only action that will happen is the production optimised build being uploaded to the S3 bucket.
We can open a browser window against the same domain once again to validate our change has gotten deployed . Remember to wait at least ONE MINUTE before doing this, of course, as our Cloud Front caching TTL aws set to 60s.
We can now start changing our application to shape into whatever we want. Lets' simply change line of code from src/App.js as follows:
The production optimised build needs to be re-done to reflect this now
After doing this we rredploy our application. Notice how, this time, there is no re-instantiation of either the S3 bucket or the CloudFront distribution. The only action that will happen is the production optimised build being uploaded to the S3 bucket.
We can open a browser window against the same domain once again to validate our change has gotten deployed . Remember to wait at least ONE MINUTE before doing this, of course, as our Cloud Front caching TTL aws set to 60s.
Step 8 : Clean up
To ensure you don't get billed for unwanted resources, it's usually a good idea to tidy up AWS resources. This is especially important if opening up any public website as we have done, through which someone could potentially flood the site with thousands of unwanted requests. Where a traditional web hosting server might max out and crash, this "serverless" combination of CloudFront and S3 will happily take whatever you throw at it and scale up elastically with a £££ bill.
The following command will clean up all AWS resources created in this tutorial. Once again, this step will take a long time (~15 mins) as this action has a global scope.
jafrimo@LP00650:~/tutorials/aws-cloudfront-react-app$ sls remove
S3 Sync: Removing S3 objects...
..
S3 Sync: Removed.
Serverless: Getting all objects in S3 bucket...
Serverless: Removing objects in S3 bucket...
Serverless: Removing Stack...
Serverless: Checking Stack removal progress...
.........
Serverless: Stack removal finished...
To ensure you don't get billed for unwanted resources, it's usually a good idea to tidy up AWS resources. This is especially important if opening up any public website as we have done, through which someone could potentially flood the site with thousands of unwanted requests. Where a traditional web hosting server might max out and crash, this "serverless" combination of CloudFront and S3 will happily take whatever you throw at it and scale up elastically with a £££ bill.
The following command will clean up all AWS resources created in this tutorial. Once again, this step will take a long time (~15 mins) as this action has a global scope.
jafrimo@LP00650:~/tutorials/aws-cloudfront-react-app$ sls remove S3 Sync: Removing S3 objects... .. S3 Sync: Removed. Serverless: Getting all objects in S3 bucket... Serverless: Removing objects in S3 bucket... Serverless: Removing Stack... Serverless: Checking Stack removal progress... ......... Serverless: Stack removal finished... |


Comments
Post a Comment