jonelantha: Blog


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

12th April 2022 - (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 www.myblog-example.com
  • 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
      • S3 bucket access: Select Yes use OAI (bucket can restrict access to only CloudFront), and then in the new section which appears:
        • Origin access identity: Click the Create new OAI button and then in then click Create in the popup (you can change the name or accept the default)
        • Bucket policy: Select Yes, update the bucket policy
      • 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 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.
      • AWS WAF web ACL: leave as None
      • 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
  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
      • ARN - The unique ID for this distribution within the whole of AWS
      • 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)

So what did we setup here? For many of the fields we just selected the defaults but we also granted read-only access to the private S3 bucket for this new distribution. This was accomplished in two steps:

  • We told the console to create a new CloudFront Origin Access Identity, which is basically a way for that particular distribution to identity itself to the S3 bucket. If you're interested in seeing the identity which was created click Origin access identities in the left hand panel of the CloudFront console.
  • The second step was to grant access to the S3 bucket for this new identity. To see how this has was done, go to your S3 bucket in the console, click the Permissions tab, click the Bucket Policy button and you should see the bucket policy which grants access to the new CloudFront identity.

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 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-2023 jonelantha