This guide provides a complete workflow for deploying a static Gatsby website on AWS. The architecture uses a private S3 bucket for storage and a CloudFront distribution as a global Content Delivery Network (CDN) for high performance and low latency.
Note: the steps below work for the output of any static site generator. Gatsby development has slowed since Netlify acquired it in 2023, so if you are starting a new project, compare it with the alternatives first.
Architecture Benefits
- Performance: CloudFront caches site assets at edge locations worldwide, drastically reducing load times for global users.
- Scalability: The serverless nature of S3 and CloudFront handles traffic spikes automatically without server management.
- Cost-Efficiency: You pay only for S3 storage and CloudFront data transfer, which is typically much cheaper than traditional server hosting for static sites.
- Security: The bucket stays private and is only readable through CloudFront. CloudFront also integrates with AWS Certificate Manager (ACM) for free SSL/TLS certificates and with AWS WAF for application-layer protection.
Prerequisites
- An AWS Account with access to S3, CloudFront, Route 53, and ACM.
- A finished Gatsby project ready for deployment.
- Node.js and the Gatsby CLI (
npm install -g gatsby-cli) installed locally. - AWS CLI installed and configured with your credentials.
1. Create a Private S3 Bucket
The S3 bucket will store the static assets generated by the Gatsby build process.
- Navigate to the S3 console in AWS.
- Click Create bucket.
- Enter a globally unique bucket name.
- Select an AWS Region.
- Leave Block all public access enabled. CloudFront will read the objects through Origin Access Control (OAC), so the bucket does not need to be public.
- Click Create bucket.
You do not need to enable static website hosting.
2. Build and Deploy to S3
First, generate the production build of your Gatsby site. This compiles all necessary files into a public directory.
# From your project's root directory
gatsby build
Next, use the AWS CLI to sync the contents of the public directory to your S3 bucket.
# Syncs the build output to S3
aws s3 sync public/ s3://YOUR_BUCKET_NAME --delete
- The
synccommand is efficient, only uploading new or changed files. - The
--deleteflag removes files from the S3 bucket that are no longer in your local public folder.
3. Create a CloudFront Distribution
CloudFront will serve your site's content from its global network, pulling from the S3 bucket as its origin.
- Navigate to the CloudFront console and click Create distribution.
- For Origin domain, select your S3 bucket from the dropdown (it looks like
your-bucket-name.s3.your-region.amazonaws.com). - Under Origin access, choose Origin access control settings and create a new OAC with the default settings.
- Under Viewer protocol policy, select Redirect HTTP to HTTPS to enforce secure connections.
- In the Settings section, set the Default root object to
index.html. - (Optional) To use a custom domain, add it under Alternate domain name (CNAMEs). For SSL, you must first request a public certificate from AWS Certificate Manager (ACM) in the
us-east-1region. Once issued, select it from the Custom SSL certificate dropdown. - Click Create distribution.
After the distribution is created, CloudFront shows the bucket policy it needs. Copy it into your bucket under Permissions > Bucket policy. It should look like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::YOUR_ACCOUNT_ID:distribution/YOUR_DISTRIBUTION_ID"
}
}
}
]
}
The distribution will take several minutes to deploy. Once its status is "Enabled," you can access your site via the provided distribution domain name (e.g., d123abcde.cloudfront.net).
4. Handle Subdirectory URLs and 404 Pages
CloudFront only applies the default root object to the root URL (/). Gatsby pages such as /about/ live at /about/index.html in the bucket, so they need a rewrite.
- In the CloudFront console, go to Functions and create a new function.
- Paste the following code and publish the function:
function handler(event) {
var request = event.request;
var uri = request.uri;
if (uri.endsWith('/')) {
request.uri += 'index.html';
} else if (!uri.includes('.')) {
request.uri += '/index.html';
}
return request;
}
- Associate the function with your distribution's default behavior as a Viewer request function.
- Under Error pages, add custom error responses for HTTP 403 and 404 that return
/404.htmlwith a 404 response code. A private bucket returns 403 for missing files, so both codes are needed.
5. Map a Custom Domain via Route 53 (Optional)
If you configured a custom domain (CNAME) in CloudFront, you must update your DNS records to point to the distribution.
- Navigate to the Route 53 console and select your domain's Hosted zone.
- Click Create record.
- Enter the subdomain (e.g., www) or leave it blank for the root domain.
- Set the Record type to A.
- Enable the Alias toggle.
- For Route traffic to, choose Alias to CloudFront distribution and select your distribution from the list.
- Click Create records.
DNS propagation may take some time. Once complete, your Gatsby site will be live on your custom domain, served securely and globally by CloudFront.
Conclusion
S3 and CloudFront are a cost-effective way to host a Gatsby website. A private bucket behind CloudFront keeps the setup secure, and the global cache keeps it fast.
CloudFront also helps with cost. With a high cache-hit ratio, most requests are served from the CDN's cache instead of S3, which reduces S3 request and data transfer charges. For a small or low-traffic site the monthly bill is usually small.
AWS free tier terms and pricing change, so check the current AWS Free Tier details and the S3 and CloudFront pricing pages before you rely on any free allowance.
