Deploy Next.js to AWS on S3 and CloudFront
December 28, 2020
This post covers how to setup a SSG site on AWS via S3, CloudFront, Route53, and ACM.
S3 bucket
Create the Bucket
First create the bucket
Tags
Optional, but you can set tags. For tracking traffic per domain, it's a good idea to add a domain
tag:
Policy
Second, edit the policy to be public
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowPublicReadAccess",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::yourdomain.com/*"
}
]
}
ACM Certificates
Before setting up CloudFront, we need SSL Certificates. You can obtain a free SSL certificate from the console here
Create Domain
Enter your domain, and include *.yourdomain.com
for wildcards, or any specific subdomains you'd like to use.
DNS Validation
It's highly suggested to use Route53, and check DNS Validation for the validation method.
Create and then choose "Create record in Route 53" to begin the DNS validation.
Now just wait and the verification should be complete within a few minutes, potentially right away!
CloudFront
Create Distributions
Start by creating a distribution. You can create a distribution from the console here
- Choose Web
- For "Origin Domain Name" set
yourdomain.com.s3.amazonaws.com
- Check "Redirect HTTP to HTTPS"
- Decide your "Price Class"
- Under "Alternate Domain Names (CNAMEs)" enter your domains each on separate lines (see below image)
- Check "Custom SSL Certificate"
- "Default Root Object" set to
index.html
Then click create!
Set up Error Pages
While distribution is deploying, you can setup the error pages. Click on the distribution.
We will set this up once each for 403 and 404 errors:
- Choose 403 or 404 for "HTTP Error Code"
- Choose "Customize Error Response"
- Set "Response Path Path"
/404.html
- Choose 200 for "HTTP Response Code"
Your Next.js Package
Update your package.json
's scripts
object to contain the deploy info:
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"export": "next build && next export",
"deploy": "AWS_PROFILE=myprofile1 aws s3 sync out/ s3://yourdomain.com",
"invalidate": "AWS_PROFILE=myprofile1 aws cloudfront create-invalidation --distribution-id EEEEEEEKJCTPFA --paths \"/*\"",
"paths": "AWS_PROFILE=myprofile1 ./deploy/prepare.sh",
"deploy:all": "npm run export && npm run deploy && npm run paths"
}
CloudFront routing fix
Do make sure you can route to /some-route
and under the hood, cloudfront will be able to find the /some-route.html
, you need to setup a script.
Make sure to have this script in your deploy/prepare.sh
(and also chmod +x
it)
#!/bin/bash
export S3_BUCKET=yourdomain.com
(cd out &&
find . -type f -name '*.html' | while read HTMLFILE; do
HTMLFILESHORT=${HTMLFILE:2}
# HTMLFILE_WITHOUT_INDEX=${HTMLFILESHORT::${#HTMLFILESHORT}-11}
HTMLFILE_WITHOUT_INDEX=${HTMLFILESHORT//index.html/}
HTMLFILE_WITHOUT_HTML=${HTMLFILE_WITHOUT_INDEX//.html/}
# cp /about/index.html to /about
aws s3 cp s3://$S3_BUCKET/${HTMLFILESHORT} s3://$S3_BUCKET/$HTMLFILE_WITHOUT_HTML
echo aws s3 cp s3://$S3_BUCKET/${HTMLFILESHORT} s3://$S3_BUCKET/$HTMLFILE_WITHOUT_HTML
if [ $? -ne 0 ]; then
echo "***** Failed renaming build to $S3_BUCKET (html)"
exit 1
fi
done)
Route53
DNS Records
Setup the root record first
- Create an "A Record" (leave name blank for the root record)
- Choose yes for "Alias"
- Find your CloudFront distribution and link to it
Then setup the www and cname
- Choose "CNAME"
- Enter "www" for the name
- Enter "yourdomain.com" for the Value
When finished you should have these two records at a minimum:
yourdomain.com.
A
ALIAS d12mkko9k4qnnn.cloudfront.net.
No
-
www.yourdomain.com.
CNAME
yourdomain.com
AWS Profiles
Make use of AWS Profiles
Inside of ~/.aws/credentials
[default]
aws_access_key_id = REDACTED
aws_secret_access_key = REDACTED
[myprofile1]
aws_access_key_id = REDACTED
aws_secret_access_key = REDACTED
[myprofile2]
aws_access_key_id = REDACTED
aws_secret_access_key = REDACTED
Inside of ~/.aws/config
[default]
region = us-east-1
[profile myprofile1]
output = json
region = us-east-1
[profile myprofile2]
output = json
region = us-east-1
Sources
https://medium.com/@omgwtfmarc/deploying-create-react-app-to-s3-or-cloudfront-48dae4ce0af
https://medium.com/@serverlessguru/deploy-reactjs-app-with-s3-static-hosting-f640cb49d7e6
https://github.com/jariz/gatsby-plugin-s3/blob/master/recipes/with-cloudfront.md