(AWS) Host Your React App on AWS S3 with SSL
Hosting a React app on AWS S3 with SSL could be a bit tricky to set up. In this article, I will show you how you can configure everything.
Prerequisites
- You have
aws-cli
installed - You have an AWS account
Note: You might get charged if you’re not on the free tier
My Environment
aws-cli
version 1.17.9- macOS Catalina Version 10.15.6
create-react-app
version 3.4.1
1. Create an S3 bucket
First, create an S3 bucket on AWS. You can use the default settings for most of the options except for the permissions. Uncheck the “Block all public access” option to allow anyone to access your website.
2. Configure the bucket to host a React app
Next, click on your newly created bucket, navigate to Permissions > Bucket Policy and add the following policy. Replace {your_bucket_name} with your S3 bucket name.
{
"Version": "2008-10-17",
"Id": "PublicRead",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::{your_bucket_name}/*"
}
]
}
Then, also add the following configuration to the CORS configuration next to the Bucket Policy tab. You can remove unwanted AllowedMethod as necessary.
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>HEAD</AllowedMethod>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>DELETE</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
Now, go to Permissions > Static website hosting and enable it by checking the Use this bucket to host a website option. Under the Index document section, put your app’s entry filename. You also need to put something under the Error document section not to show the ugly default error page. If you don’t have an error page yet, you can just put your entry filename for now.
3. Create an AWS certificate for SSL
At this point, you should be able to host a static website on this S3 bucket. Next, let’s move on to the SSL part. To be able to access the website via https, you need a certificate tied with your domain. On the AWS console, go to Certificate Manager and click on the “Get started” button under the Provision certificates section.
Note: Before you create a certificate, make sure that you’re currently in the “US West (N. California)us-west-1” region. Otherwise, it can’t be used later to configure your CloudFront distribution.
On the next page, you will be asked what kind of certificate you are requesting. Choose the Request a public certificate option there and add your domain including subdomains that you wish to have.
Then, you will be asked to select a validation method. I recommend that you select DNS validation.
You can skip Step 3: Add tags if you don’t want to add any tags to it. After going through all steps here, you will need to create a CNAME record on your DNS manager following the instructions on the page. Name would be the host name and Value would be where it should point at.
Note: If your DNS manager does not allow a value with an underscore at the beginning, you can just remove the underscore.
4. Create a CloudFront distribution
Now, you are going to create a CloudFront distribution to serve your React app through https. Navigate to the CloudFront page and click on the “Create distribution” button. Then, select Web as the delivery method.
On the next screen, you are going to configure the following things.
Origin Domain Name
Put your S3 bucket’s URL. You can find it under Permissions > Static website hosting > Endpoint of your S3 bucket. If you just select your S3 bucket name here, it won’t be able to handle page refresh.
Origin Custom Headers:
This is needed to be configured to make sure that the requests come from this specific CloudFront distribution. You can put anything as Header Name and Value. I always put something like below.
Origin Custom Headers:
Header Name = Referer
Value = any-value-to-identify-the-distribution
Default Cache Behavior Settings
In this section, you can configure your distribution’s cache behaviour.
- Viewer Protocol Policy
In order to make sure that the app always uses https, the “Redirect HTTP to HTTPS” or “HTTPS Only” option is recommended. - Allowed HTTP Methods
You can just choose the list of HTTP methods you want to allow caching. - Cache and origin request settings
You can either choose a cache policy that you need or use legacy cache settings to manually set the values. If you want to have more control over the caching time, select “Use legacy cache settings” for “Cache and origin request settings” and “Customize” for “Object Caching”. In that way, you can define the values for Minimum TTL, Maximum TTL and Default TTL manually.
Distribution Settings
Under this section, configure the following things.
- Alternate Domain Names (CNAMEs)
Put the domain names that you want to use for your app. - SSL Certificate
Select the certificate that you created in the previous step of this article. Your certificate must have been created in the “US West (N. California)us-west-1” region to be listed as an option here.
5. Add a CNAME record pointing to the CloudFront distribution on your DNS manager
Now you have a CloudFront distribution tied with your S3 bucket where actual website data exists. In order to let your domain know where it should point at, add a CNAME record on your DNS manager. The record should be something like below.
CNAME record:
Name: example.com
Value: assignedcfdomain.cloudfront.net
6. Deploy your React app
Finally, build your React app and deploy it to the S3 bucket. If you have multiple environments to build with different env files like staging and production, you might find the following scripts useful. Make sure you have installed aws-cli
and configured your profile correctly. For the following scripts to work properly, you need to name your env files as .env.environment-name
.
"build": "sh -ac '. .env.${REACT_APP_ENV}; react-scripts build'",
"build:staging": "REACT_APP_ENV=staging npm run build",
"build:production": "REACT_APP_ENV=production npm run build",
"deploy:staging": "aws s3 sync build/ s3://staging.your-bucket-name --acl public-read --profile your-profile-name",
"deploy:production": "aws s3 sync build/ s3://your-bucket-name --acl public-read --profile your-profile-name"
Now, your web app should be properly served via https protocol if you type in your domain on your browser.
That’s everything for this article. Please don’t hesitate to let me know if I’m missing something.
References:
- Using Custom URLs for Files by Adding Alternate Domain Names (CNAMEs):
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/CNAMEs.html - How do I use CloudFront to serve a static website hosted on Amazon S3?:
https://aws.amazon.com/premiumsupport/knowledge-center/cloudfront-serve-static-website/ - Values That You Specify When You Create or Update a Distribution:
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html#DownloadDistValuesOriginCustomHeaders - Adding Custom Headers to Origin Requests:
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/add-origin-custom-headers.html - Troubleshoot DNS Validation Problems:
https://docs.aws.amazon.com/acm/latest/userguide/troubleshooting-DNS-validation.html - Create-react-app environments:
https://medium.com/@tacomanator/environments-with-create-react-app-7b645312c09d