React router on Amazon S3

Not so long ago I’ve finished my React + ReactRouter project and I was looking for a neat way to deploy its production version.

Since it’s a 100% static website, the first thing that came to my mind was Amazon S3 and their website hosting. The process is very simple:

create a bucket make it publicly readable upload your html/css/js/other files enable static website hosting on the bucket change some DNS settings … you’re done - there is no point 6 ;)

To make it even simpler I used awesome s3_website tool. It required creating simple configuration file and I was able to push my work to S3.

Issues with routing

Unfortunately S3 website hosting wasn’t playing nice with ReactRouter. I typed http://my-awesome-site.com/products/cool-product in the browser’s address bar and I got 404 Not Found error code. I realized that’s completely justified on the S3 side since this file wasn’t present in the bucket.

On staging I was handling such cases with Nginx configuration:

location / { ... try_files $uri .html $uri $uri / /index.html ; ... }

This basically means: try to match the uri and if you fail just serve index.html from the root directory.

Thanks to above directive routing was done by ReactRouter and site was working perfectly on staging.

Intermediate solution

One possible workaround was to switch ReactRouter to use createHashHistory and setup redirect rules on S3 bucket like this

<RoutingRules> <RoutingRule> <Condition> <HttpErrorCodeReturnedEquals> 404 </HttpErrorCodeReturnedEquals> </Condition> <Redirect> <HostName> my-awesome-site.com </HostName> <ReplaceKeyPrefixWith> #/ </ReplaceKeyPrefixWith> </Redirect> </RoutingRule> </RoutingRules>

That way when I typed http://my-awesome-site.com/products/cool-product I was redirected to http://my-awesome-site.com/#/products/cool-product . My site worked again but with ugly urls that were neither user nor google friendly.

Cloudfront

I was looking through Amazon Management Console, hoping I could find some solution, and I noticed Error Pages section in my Cloudfront distribution. It turned out that I was able to override default behaviour of 404 http error and that was what I needed. I set Response Page Path to /index.html and HTTP Response Code to 200

Since this is essentially the same configuration that I had in Nginx I was able to access my site through normal url again :)