jonelantha: Blog

How-To: Setup Gatsby on AWS using GitHub Actions [1/3]: Setup S3 and CloudFront

2nd May 2024 - (revised version of a post originally published 28th February 2020)

Let's take a look at how to publish a Gatsby site to AWS using GitHub Actions.

What we'll end up with:

  • A Continuous Deployment (CD) environment hosted with GitHub Actions. Merge your changes into your main branch (or master) and within minutes they'll be live for everyone to see.
  • Your site will be hosted on S3 and CloudFront. You'll get great performance, great scalability and you'll enjoy negligible (if any) costs.

NOTE: In this guide we'll setup the S3 bucket to be fully private - no need for some of the hacks and workarounds suggested by other similar guides.

Alternative deployment approaches

This guide does rely on some manual setup so it may not be for everyone. If you're unsure then you may want to consider a more managed solution, something like AWS Amplify for example - see the Gatsby deployment guide for a full list of alternatives.

However, if you're looking for a more hands-on and bare-metal approach then let's continue!

AWS Account

We'll assume you have an AWS account and you're logged into the console using an administator account (your administrator account would ideally be setup according to AWS IAM best practices).

S3 Bucket - where the site files will live

The first step is to create the S3 bucket, this is needed for storing the files which make up the site. Later on we'll setup a GitHub Actions CD workflow to automatically upload the site files to this bucket.

To setup the bucket you'll need to decide a couple of things:

  • Bucket Name: This is a unique name which is representative of your site. It can be anything but a good choice would be your site's domain name (if you have one). An example would be
  • AWS Region: This is the AWS region where the bucket will be hosted, see the AWS Region Guide for more info on choosing a region

Now to create the bucket:

  1. In the AWS console go to the S3 section
  2. Click Create Bucket
  3. In the General configuration section:
    • Enter the Bucket name and AWS region you've chosen
  4. In the Block Public Access settings for this bucket section:
    • You should see Block all public access is ticked. Keep it ticked.
  5. Other options for versioning and encryption can be left as they are
    • Scroll to the bottom and click Create bucket

So what did we do here? We created a private S3 bucket which should be locked down (and not accessible via the web). The next step is to create the CloudFront distribution so web users can access the files in the bucket.

Note it's possible to host your site directly from the S3 bucket without needing CloudFront. There are a number of disadvantages to this approach so we won't be looking at that here but take a look at the AWS S3 Static Hosting documentation for more information.

CloudFront - serve the files in the S3 Bucket

Now to create the CloudFront distribution. CloudFront is a Content Delivery Network (CDN) which will serve up the files in the bucket - for more information on the advantages of using CloudFront see the Features of CloudFront

  1. In the AWS console go to the CloudFront section
  2. Click Create distribution
  3. On the Create Distribution screen:
    • In the Origin section:
      • Origin domain: click the field and select the bucket you created earlier
      • Origin path - optional: fine to leave blank
      • Name: this should now be prefilled, it's fine to leave it as it is
      • Origin access: Select Origin access control settings (recommended), and then in the new section which appears:
        • Origin access control: Click the Create new OAC button and then in then click Create in the popup, accepting the defaults (you can change the name or accept the default name)
        • You'll see a You must update the S3 bucket policy warning, that's ok
      • Add custom header - optional: no need to do anything here
      • Enable Origin Shield: ok to leave this as No (if you'd like to learn more, please see AWS documentation on Origin Shield)
    • In the Default cache behavior section:
      • Path pattern: ok to leave
      • Compress objects automatically: leave as Yes
      • Viewer protocol policy: If you know you plan to setup https/ssl then select Redirect HTTP to HTTPS otherwise leave as HTTP and HTTPS
      • Allowed HTTP methods: leave as GET, HEAD
      • Restrict viewer access: leave as No
      • Cache key and origin requests: leave as Cache policy and origin request policy
        • Cache policy: Leave as CachingOptimized
        • Origin request policy: select CORS-S3Origin
      • Response headers policy - optional: ok to leave blank
    • In the Function associations section: No need to do anything here but we will need to setup a CloudFront Function in Part 2 of this guide
    • In the Web Application Firewall (WAF) section:
      • Enabling WAF is not essential and so it's fine to choose Do not enable security protections. To learn more read the WAF documentation and if you'd like to enable WAF then click Enable security protections
    • In the Settings section:
      • Price class: you can leave this as it is or alternatively select the first option in the list. Click the info link for more info.
      • Alternate domain name (CNAME): leave this blank for now but when setting up your own domain name you'll need to come back to this one
      • Custom SSL certificate: for now leave blank
      • Supported HTTP versions: HTTP/2 should be ticked
      • Default root object: enter index.html here
      • Standard logging: it's easiest to leave as Off for now but you may want to come back to this
      • IPv6: On should be selected
      • Description: fine to leave this blank
    • Click Create distribution
  4. Once created feel free to review this information, when you're done click Distributions on the left
    • A yellow banner will appear on this screen explaining that we need to setup the access policy on the S3 bucket, click Copy Policy and paste the copied policy (a block of JSON) to someway safe locally as we'll need it later. If you missed clicking Copy Policy don't worry, we can still copy the policy from inside Distribution screen (see below)
  5. Back on the Distributions screen:
    • you should see a list containing your new distribution
    • click the ID link for the distribution (if you have multiple distributions take a look at the Origin column to figure out the correct one)
  6. On the Distribution screen
    • Here you can view and edit the distribution you've setup
    • On the summary you'll see several fields which we'll need later on:
      • Distribution ID - The unique ID for this distribution within CloudFront, it's the 14 character string at the top
      • Distribution domain name - An auto generated domain name to access the site (consider this a temporary domain name as you'll want to setup your own domain name later on)
      • ARN - The unique ID for this distribution within the whole of AWS

So what did we setup here? For many of the fields we just selected the defaults but we also created an Origin Access Control which we'll use to grant access to the S3 bucket for this new distribution. If you're interested to see the OAC which was created click Origin access in the left hand panel of the CloudFront console.

S3 Bucket - grant access to CloudFront

Now we need to use the access policy copied from the yellow banner to allow CloudFront to access the S3 bucket.

If you missed clicking Copy Policy in the the yellow banner you can still get the same policy by going into the Distribution (see steps above), go to Origins tab, highlight the origin in the list and click edit, scroll down to the blue box and then finally click Copy Policy

  1. In the AWS console go to the S3 section

  2. Click the name of the bucket to go to the edit screen

  3. In the Permissions tab

    • Scroll down to the Bucket Policy section
    • Click Edit
    • Paste in the policy JSON copied using the Copy Policy button
    • Click Save changes

CloudFront - setup the Gatsby error pages

By default CloudFront will show some quite unfriendly messages so we'll need to tell CloudFront to use Gatsby's error pages. CloudFront serves up a 403 error when most users would expect a 404 error so we'll setup both the 403 and 404 errors to show the Gatsby 404 error.

Note at this point the 404.html page won't exist, this step is just preperation for when the Gatsby site is available in the bucket.

  1. Go to the Distribution details screen (see last couple of steps of the CloudFront setup section above)
  2. Click the Error pages tab
  3. In the Error pages tab
    • Click Create custom error response
      • HTTP error code: Choose 403
      • Error caching minimum TTL: leave as 10
      • Customize error response: set to Yes
      • Response page path: enter /404.html
      • HTTP Response Code: set to 404
    • Create a second custom error response for the 404 error by repeating the steps above but this time using 404 as the HTTP Response Code instead of 403.

Surely it would've been easier just to use a CloudFormation template?

Wow that's a lot of setup and this is only Part 1! We could've set this up using a CloudFormation template and it would've been created in seconds. Whilst a CloudFormation is very convenient, it does hide a lot of the details away and it offers very little opportunity for learning - hopefully by doing these steps manually you'll have a better grasp of the components and you'll be in a better position to maintain it in the future.

OK all done. What's next?

Next we need to setup CloudFront to correctly handle Gatsby urls.

Let's move on to Part 2: CloudFront Function for index rewrites (with optional basic authentication).

© 2003-2024 jonelantha