2020-06-29
In my continuing journey to learn more about Gatsby, React, and all things serverless and single page app I hosted the prototype of my latest project1 using AWS Amplify. The Amplify service, among other things, promises to simplify hosting with continuous deployment by monitoring a git branch in your repository and automatically deploying whenever changes are pushed to it. In my case the repository is hosted on Github. Setting up the continuous deployment went pretty smoothly, there are very clear instructions both in Amazon's Amplify tutorial and in the Gatsby documentation.
However, after the build process completed, instead of my website I was greeted with an Access Denied error. Not fun. It ended up being a combination of errors that took some careful searching to puzzle out.
First I came across this issue on the aws-amplify github page. It talks about Angular and I'm using React / Gatsby, but the error is the same. The Gatsby starter I'm using does use a custom router. Down at the end of the page I find this snippet:
[
{
"source": "</^[^.]+$|\\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf|map|json)$)([^.]+$)/>",
"target": "/index.html",
"status": "200",
"condition": null
}
]
So, I add that to the Rewrites and Redirects settings in AWS Amplify. Still no dice. Access still denied. I spent a couple hours going down dead ends messing with S3 bucket policies, nothing seems to make a difference. Finally I came across this StackOverflow question which references the guide for manual deploys and the note at the bottom makes it click:
When you create the zip folder, make sure you zip the contents of your build output and not the top level folder. For example, if your build output generates a folder named “build” or “public”, first navigate into that folder, select all of the contents, and zip it from there. If you do not do this, you will see an “Access Denied” error because the site's root directory will not be initialized properly.
It occurs to me to look at the build output from Gatsby and see where it actually puts the index.html
file. It turns out it's not in the root of the build directory, but in a subfolder. Changing the redirect setting above to point to where the index file is located fixes everything.
[
{
"source": "</^[^.]+$|\\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf|map|json)$)([^.]+$)/>",
"target": "/app/index.html",
"status": "200",
"condition": null
}
]
So hopefully this helps anyone else having the same issue. The two things to keep in mind are:
If you're using a custom router, you want every request sent to your main index page, so your router can handle it from there. Add a redirect to send requests to the page. The regex above sends anything that isn't a static file to the root index page.
Make sure you're pointing to where the index page actually is. It may be in a
subfolder of the build output directory. For Gatsby this directory is named
public
unless you've set it to be something else. Run gatsby build
and check the output for the location of the index.html
file. Then add
the path relative to the root build directory to the rewrite above, in the field
target
.