Route your S3-served static HTMLs beautifully 
Tags: aws, s3, html
Published: 2019-02-18 10:00:38

---
title: Route your S3-served static HTMLs beautifully 
published: true
description: In this article I'll show you how to route your static HTML files with S3. Your users don't have type again ".html" at the end of their request!
tags: aws, s3, html
---

If you are that developer how doesn't play with the big boys and you don't have a fancy React, Angular or *insert any fancy frontend framework here which is popular when you read this article* site, which supports client-side routing, but you have some static HTML files (for whatever reason) and you'd like to host it in AWS S3, this article is for you!

What I'll show you is how to do some basic routing through S3. Your users don't have to add the ugly *.html* postfix to the end of their request if they want to reach the */products.html* page, but they will be able to type */products*. 

🙀🙀🙀 

How cool is that? Less typing, more revenue! Let's implement it!

But first, the boring task:
* create a bucket in S3, with the default settings. We'll adjust everything later. Upload your static files into the bucket (or [mine](https://github.com/mpxr/s3-routing)).

## Configuring the permissions

1. In order for your customers to access content at the website endpoint, you must adjust the public access settings of the bucket.
    * Go to **Permissions** > **Public access settings**
    * Click Edit and make sure that the following 2 options are **unselected**: 
        * *Block new public bucket policies*: this allows you to add a new public policy into your bucket. We will do this in the next step.
        * *Block public and cross-account access if bucket has public policies*: this allows users to access the content of a public bucket. If you have this option set only the creator of the bucket and other AWS services have access to this bucket. This is a pretty new feature of S3 (late 2018).

2. Now we are able to add a bucket policy to our bucket.
    * Go to **Permissions** > **Bucket policy**
    * Add the following policy document, which allows you to request every object from the bucket: 
```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<YOUR_S3_BUCKET_NAME>/*"
        }
    ]
}
```

## Configuring the static website hosting

Now that we have every permissions setting, let's do the interesting part! Assume that I have the following HTML pages:
* *index.html*, which is my landing page
* *about.html*, *products.html*
* and *error.html*, which is my error handling page

I want to have the following routing set:
* `/` -> `index.html`
* `/about` -> `about.html`
* `/products` -> `products.html`
* everything else -> `error.html`

The first and last rule is easy to set up because S3 supports it from out-of-the-box with the *Static website hosting* feature. On your bucket page go to **Properties** > **Static website hosting**. Set the *Index document* field to index.html and the *Error document* to error.html (or howsoever you named your these files). And now the trickier part: you have to set up some *Redirection rules*. 

It's configured via XML... 😬

But it's not that bad. Bear with me.

You have to set up *RoutingRules*, which consists of 2 things: 
* a *Condition* where we provide that what kind of request do we want to catch, eg. `/products`
* and where this request will be *Redirected*, eg. to `/products.html`.

You will have a *RoutingRules* parent and as many *RoutingRule* as the number of HTML sites you want to redirect. So this is how it will look like in the end if I add routing to my two static files:
```xml
<RoutingRules>
  <RoutingRule>
    <Condition>
      <KeyPrefixEquals>about</KeyPrefixEquals>
      <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
    </Condition>
    <Redirect>
      <ReplaceKeyWith>about.html</ReplaceKeyWith>
    </Redirect>
  </RoutingRule>

  <RoutingRule>
    <Condition>
      <KeyPrefixEquals>products</KeyPrefixEquals>
      <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
    </Condition>
    <Redirect>
      <ReplaceKeyWith>products.html</ReplaceKeyWith>
    </Redirect>
  </RoutingRule>
</RoutingRules>
```

The most important part in this is the `HttpErrorCodeReturnedEquals` element. When you require a resource from an S3 bucket with a key like "products", S3 won't find it because it doesn't exist (obviously we only have HTML files in our buckets) and it will return a 404 (Not Found) error, which will be propagated to the client, and we won't even access the *Redirect* rule.

That's all. But do not forget, at last in your URL, your users will still see that they're browsing the `products.html` and not `/products`. But it will ease their user experience with eliminating the need of typing `.html` after every request.

### Routing to external sites

With S3 routing rules, you have the ability to route your request to external websites. If your users request the `/facebook` resource from your page, you can redirect them to your Facebook page, https://facebook.com/YOUR_FACEBOOK_ACCOUNT_POSTFIX. This is how you can set up rules like this:
```xml
<RoutingRule>
  <Condition>
    <KeyPrefixEquals>facebook</KeyPrefixEquals>
    <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
  </Condition>
  <Redirect>
    <HostName>facebook.com</HostName>
    <ReplaceKeyPrefixWith>/YOUR_FACEBOOK_ACCOUNT_POSTFIX</ReplaceKeyPrefixWith>
  </Redirect>
</RoutingRule>
```

## Postscript

I hope this article helped you to do basic routing with S3. When I had to do the same thing, I spent a couple of hours while I found the best solution. I wish you won't have to spend that much time on it. You can find every code I pasted above in a Git [repo](https://github.com/mpxr/s3-routing).

If you find any error in the above-written stuff, please blame me publicly in the comment section. Or if it helped you, just drop a "thanks". I'll appreciate it.

See ya. 👋