Redirect All Routes to index.html When Hosting a React/Angular Webapp on S3

If you’re using S3’s static website hosting feature to host a React or Angular webapp, the URLs in the URL bar of a browser running your webapp are essentially pseudo URLs. There’s no HTML page at the end of any of those URLs. Client-side JavaScript in your webapp handles all URLs & displays the appropriate page. In such cases, if a user types-in or visits 1 of the sub-URLs of your webapp, maybe via a bookmark, S3 will simply return a 404.

To avoid this, you must set up redirection of all URLs to index.html, which will load your webapp, which in-turn will handle the URL. In the server world, this would be easily accomplished by a redirect rule:

Apache
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.html$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.html [L]
 </IfModule>
Nginx
rewrite ^(.+)$ /index.html last;

There are many ways to handle this redirection for a static webapp hosted on S3:

Using CloudFront

Create a CloudFront distribution with your S3 bucket as the origin, index.html as the default root object, “<your-bucket>.s3-website-us-east-1.amazonaws.com” as the origin domain name, & a custom error response to redirect everything to index.html:

Using S3 Redirection Rules

Using advanced redirection rules, you can route requests conditionally according to specific object key names, prefixes in the request, or response codes.

β€” Configuring Advanced Conditional Redirects β€” S3 Documentation

In our case, use this redirection rule:

<RoutingRules>
  <RoutingRule>
    <Condition>
      <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
    </Condition>
    <Redirect>
      <HostName>yourdomainname.com</HostName>
      <ReplaceKeyPrefixWith>#!/</ReplaceKeyPrefixWith>
    </Redirect>
  </RoutingRule>
</RoutingRules>

There are a few problems with this approach though:

  • Multiple redirects happen as your app’s paths are resolved.
  • There is a flicker in the url bar as the ‘#’ comes & goes due the action of your SPA framework.
  • SEO is impacted.
  • Safari support is broken!

Using S3 Error Document

Set the S3 error document to index.html:

In this case, even though the user gets the webapp, the status code is still 404, which isn’t good for SEO.

Using Lambda@Edge

Use the compute power at the CloudFront edge to inspect the request as it’s coming in from the client. Then re-write the request so that CloudFront requests a default index object (index.html in this case) for any request URI that ends in β€˜/’.

β€” AWS Compute Blog

Lambda Code:

'use strict';
exports.handler = (event, context, callback) => {

    // Extract the request from the CloudFront event that is sent to Lambda@Edge 
    var request = event.Records[0].cf.request;

    // Extract the URI from the request
    var olduri = request.uri;

    // Match any '/' that occurs at the end of a URI. Replace it with a default index
    var newuri = olduri.replace(/\/$/, '\/index.html');
    
    // Log the URI as received by CloudFront and the new URI to be used to fetch from origin
    console.log("Old URI: " + olduri);
    console.log("New URI: " + newuri);
    
    // Replace the received URI with the URI that includes the index page
    request.uri = newuri;
    
    // Return to CloudFront
    return callback(null, request);

};

See full article here β€” AWS Compute Blog.

Using Amplify Redirects

If your webapp is built at the AWS Amplify console, use this:

Most SPA frameworks support HTML5 history.pushState() to change browser location without triggering a server request. This works for users who begin their journey from the root (or /index.html), but fails for users who navigate directly to any other page.

β€” Redirects for Single Page Web Apps (SPA) β€” Amplify Documentation

Copy the regex from here β€” Redirects for Single Page Web Apps (SPA).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.