Default Document For Cloudfront Folders with S3 Origin

Problem

When you deploy a CloudFront S3-backed website, you can set a default document at the site’s root. But you cannot carry that behavior into subfolders related to the site. For instance:

/index.html - will be displayed when you go to http://domain.com

but:

/test/index.html - will not be displayed when you go to http://domain.com/test

Solution

To work around this issue you can use Lambda@Edege to alter the request URI to the origin to specifically request the default (index.html) document if a document is not specified. This post will show how to do that.

Credit

Some sites I used in setting this up for refernce were:

Method

First create a new Lambda Function:

Lambda Function

Then you need to create a role that has access to Lamda at edge:

Lambda@Edge Role

The code for the function:

def lambda_handler(event, context):
    
    request = event['Records'][0]['cf']['request']
    old_uri = request['uri']
    new_uri = old_uri
    is_file = len(old_uri.split('.'))>1
    if not is_file:
        new_uri = f"{old_uri}{'' if old_uri[-1] == '/' else '/'}index.html"
    
    request['uri']=new_uri
    return request

This function is straightforward. It gets the Uri from the request, and if the request appears to include a filename, it returns the same Uri as part of the re-written request. If it does not, it will return the Uri and append /index.html.

After the function is written and deployed, it must be saved to a version. Cloudfront will require a versioned ARN.

To modify the distribution you need to edit the associated behavior as such:

Lambda@Edge Behavior

That is really all there is to it. Once you save the behavior changes they will be deployed and now your website will respond with default documents in folders, just like it does at the top level.