Set Default Root Object for Statically Hosted Website on AWS CloudFront (AWS CloudFront Functions)

AWS Cloud

A standard AWS CloudFront distribution is set to automatically serve the index.html file of a website when a client requests the root of the site, e.g. https://www.geekmungus.co.uk and does not specify any specific file or file within a sub-directory.

However in certain instances your clients may request a page as follows e.g: https://www.geekmungus.co.uk/studies within which an index.html file exists, however AWS CloudFront by default does not cope with this and offer the root object for a subdirectory. There are a number of ways to deal with this and put in place the desired behaviour, the simplest and most supportable is the use of CloudFront “Functions”. In such instances you’ll see an issue like the below, the index.html file exists, its just that the AWS CloudFront is not using it!

The configuration assumes that you have a pre-created AWS CloudFront distribution because the Function needs to be attached to an existing CloudFront distribution to take effect.

Apply via AWS Console

1. AWS CloudFront → Functions

2. Create a function and provide it with a name and description. e.g. index-rewrite and Handler for index.html in subdirectories.

3. Enter the following code under “Development” and then click “Save Changes”.

function handler(event) {
    var request = event.request;
    var uri = request.uri;
     
    // Check whether the URI is missing a file name.
    if (uri.endsWith('/')) {
        request.uri += 'index.html';
    }
    // Check whether the URI is missing a file extension.
    else if (!uri.includes('.')) {
        request.uri += '/index.html';
    }
 
    return request;
}

4. Click “Publish” tab, then click “Publish Function”.

It is recommended to test your function before you apply it, see the section Testing your Function Ahead of Deployment for full details. It is possible that your function could break some or all of your website, so verifying it works as expected is essential.

5. Now associate the function with your desired CloudFront distribution.

6. Wait for the CloudFront distribution to converge and update its configuration.

7. Test the behaviour of the site with the function enabled.

Apply via Cloudformation Template

To create within the CloudFront template.

IndexHandlerFunction:
    Type: AWS::CloudFront::Function
    Properties:
      AutoPublish: true
      FunctionCode: !Sub |
        function handler(event) {
            var request = event.request;
            var uri = request.uri;
     
            // Check whether the URI is missing a file name.
            if (uri.endsWith('/')) {
                request.uri += 'index.html';
            } // Check whether the URI is missing a file extension.
            else if (!uri.includes('.')) {
                request.uri += '/index.html';
            }
                return request;
        }
      FunctionConfig:
        Comment: "Handler for index.html in subdirectories."
        Runtime: cloudfront-js-1.0
      Name: !Sub "${AWS::StackName}-IndexHandlerFunction"

Within the CloudFront Distribution declaration under the “DefaultCacheBehaviour” section you need to add the below to associate the function with your distribution and therefore activate it.

FunctionAssociations:
  - EventType: viewer-request
    FunctionARN: !GetAtt IndexHandlerFunction.FunctionMetadata.FunctionARN

Testing your Function Ahead of Deployment

Click the “Test” tab, then input your test harness information, in this example, i’m testing the https://www.geekmungus.co.uk/studies URL, which was originally failing because of the issue identified above. Once the harness is ready click “Test Function” to observe the results, when you are happy it works as expected, you can then proceed to making it live.

In the example below you’ll note the URI has been changed from the requested path https://www.geekmungus.co.uk/studies to https://www.geekmungus.co.uk/studies/index.html by the function.

Additional Information

Leave a Reply

Your email address will not be published. Required fields are marked *