My photo portfolio is implemented as SPA (Single Page Application) using React, so all routing is happening on the client. And it worked fine, until I did hard refresh of the page or wanted to share direct link to one of the pages (for example https://www.adragunov.com/ethiopia). In this case users saw 404 error page produced by Amazon S3 as it tried to find object with key ethiopia in the bucket, which obviously did not exist as it only existed as client route.
My first solution was to simply set index.html as error page under S3 bucket static website hosting configuration. It worked fine from end user perspective, the page was displayed correctly. But when I checked network, actually the page content was returned with 404 Not Found status code, not with 200 OK. This means that this solution was not good for indexing and crawlers.
The other solution that I found was to create Custom Error Response in Amazon CloudFront distribution. As long as I already used CloudFront for content delivery using https, this was exactly what I needed.
And now client side routing works perfectly with 200 OK status code. Simple and elegant.