{"id":3764,"date":"2023-06-02T13:56:13","date_gmt":"2023-06-02T13:56:13","guid":{"rendered":"https:\/\/geekmungus.co.uk\/?p=3764"},"modified":"2023-06-02T13:56:13","modified_gmt":"2023-06-02T13:56:13","slug":"set-default-root-object-for-statically-hosted-website-on-aws-cloudfront-aws-cloudfront-functions","status":"publish","type":"post","link":"https:\/\/geekmungus.co.uk\/?p=3764","title":{"rendered":"Set Default Root Object for Statically Hosted Website on AWS CloudFront (AWS CloudFront Functions)"},"content":{"rendered":"\n<p>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.\u00a0<a rel=\"noreferrer noopener\" href=\"https:\/\/www.domain.com\" target=\"_blank\">https:\/\/www.geekmungus.co.uk<\/a> and does not specify any specific file or file within a sub-directory.<\/p>\n\n\n\n<p>However in certain instances your clients may request a page as follows e.g:\u00a0<a href=\"https:\/\/www.geekmungus.co.uk\/studies\">https:\/\/www.geekmungus.co.uk\/studies<\/a> 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 &#8220;Functions&#8221;. In such instances you&#8217;ll see an issue like the below, the index.html file exists, its just that the AWS CloudFront is not using it!<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/geekmungus.co.uk\/wp-content\/uploads\/2023\/06\/image-1.png\" alt=\"\" class=\"wp-image-3765\" width=\"714\" height=\"171\" srcset=\"https:\/\/geekmungus.co.uk\/wp-content\/uploads\/2023\/06\/image-1.png 714w, https:\/\/geekmungus.co.uk\/wp-content\/uploads\/2023\/06\/image-1-300x72.png 300w\" sizes=\"auto, (max-width: 714px) 100vw, 714px\" \/><\/figure>\n\n\n\n<p>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.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"SetDefaultRootObjectforStaticallyHostedWebsiteonAWSCloudFront(AWSCloudFrontFunctions)-ApplyviaAWSConsole\">Apply via AWS Console<\/h2>\n\n\n\n<p>1. AWS CloudFront \u2192 Functions<\/p>\n\n\n\n<p>2. Create a function and provide it with a name and description. e.g.<strong>&nbsp;index-rewrite<\/strong>&nbsp;and&nbsp;<strong>Handler for index.html in subdirectories.<\/strong><\/p>\n\n\n\n<p>3. Enter the following code under &#8220;Development&#8221; and then click &#8220;Save Changes&#8221;.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>function handler(event) {\r\n    var request = event.request;\r\n    var uri = request.uri;\r\n     \r\n    \/\/ Check whether the URI is missing a file name.\r\n    if (uri.endsWith('\/')) {\r\n        request.uri += 'index.html';\r\n    }\r\n    \/\/ Check whether the URI is missing a file extension.\r\n    else if (!uri.includes('.')) {\r\n        request.uri += '\/index.html';\r\n    }\r\n \r\n    return request;\r\n}<\/code><\/pre>\n\n\n\n<p>4. Click &#8220;Publish&#8221; tab, then click &#8220;Publish Function&#8221;.<\/p>\n\n\n\n<p>It is recommended to test your function before you apply it, see the section\u00a0<strong>Testing your Function Ahead of Deployment<\/strong>\u00a0for full details. It is possible that your function could break some or all of your website, so verifying it works as expected is essential.<\/p>\n\n\n\n<p>5. Now associate the function with your desired CloudFront distribution.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"888\" height=\"669\" src=\"https:\/\/geekmungus.co.uk\/wp-content\/uploads\/2023\/06\/image-3.png\" alt=\"\" class=\"wp-image-3767\" srcset=\"https:\/\/geekmungus.co.uk\/wp-content\/uploads\/2023\/06\/image-3.png 888w, https:\/\/geekmungus.co.uk\/wp-content\/uploads\/2023\/06\/image-3-300x226.png 300w, https:\/\/geekmungus.co.uk\/wp-content\/uploads\/2023\/06\/image-3-768x579.png 768w, https:\/\/geekmungus.co.uk\/wp-content\/uploads\/2023\/06\/image-3-136x102.png 136w\" sizes=\"auto, (max-width: 888px) 100vw, 888px\" \/><\/figure>\n\n\n\n<p>6. Wait for the CloudFront distribution to converge and update its configuration.<\/p>\n\n\n\n<p>7. Test the behaviour of the site with the function enabled.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"SetDefaultRootObjectforStaticallyHostedWebsiteonAWSCloudFront(AWSCloudFrontFunctions)-ApplyviaCloudformationTemplate\">Apply via Cloudformation Template<\/h2>\n\n\n\n<p>To create within the CloudFront template.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>IndexHandlerFunction:\r\n    Type: AWS::CloudFront::Function\r\n    Properties:\r\n      AutoPublish: true\r\n      FunctionCode: !Sub |\r\n        function handler(event) {\r\n            var request = event.request;\r\n            var uri = request.uri;\r\n     \r\n            \/\/ Check whether the URI is missing a file name.\r\n            if (uri.endsWith('\/')) {\r\n                request.uri += 'index.html';\r\n            } \/\/ Check whether the URI is missing a file extension.\r\n            else if (!uri.includes('.')) {\r\n                request.uri += '\/index.html';\r\n            }\r\n                return request;\r\n        }\r\n      FunctionConfig:\r\n        Comment: \"Handler for index.html in subdirectories.\"\r\n        Runtime: cloudfront-js-1.0\r\n      Name: !Sub \"${AWS::StackName}-IndexHandlerFunction\"<\/code><\/pre>\n\n\n\n<p>Within the CloudFront Distribution declaration under the &#8220;DefaultCacheBehaviour&#8221; section you need to add the below to associate the function with your distribution and therefore activate it.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FunctionAssociations:\r\n  - EventType: viewer-request\r\n    FunctionARN: !GetAtt IndexHandlerFunction.FunctionMetadata.FunctionARN<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"SetDefaultRootObjectforStaticallyHostedWebsiteonAWSCloudFront(AWSCloudFrontFunctions)-TestingyourFunctionAheadofDeployment\">Testing your Function Ahead of Deployment<\/h2>\n\n\n\n<p>Click the &#8220;Test&#8221; tab, then input your test harness information, in this example, i&#8217;m testing the\u00a0<a href=\"https:\/\/www.geekmungus.co.uk\/studies\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/www.geekmungus.co.uk\/studies<\/a>\u00a0URL, which was originally failing because of the issue identified above. Once the harness is ready click &#8220;Test Function&#8221; to observe the results, when you are happy it works as expected, you can then proceed to making it live.<\/p>\n\n\n\n<p>In the example below you&#8217;ll note the URI has been changed from the requested path\u00a0<a rel=\"noreferrer noopener\" href=\"https:\/\/www.geekmungus.co.uk\/studies\" target=\"_blank\">https:\/\/www.geekmungus.co.uk\/studies<\/a>\u00a0to <a href=\"https:\/\/www.geekmungus.co.uk\/studies\/index.html\">https:\/\/www.geekmungus.co.uk\/studies\/index.html<\/a> by the function.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"876\" height=\"955\" src=\"https:\/\/geekmungus.co.uk\/wp-content\/uploads\/2023\/06\/image-4.png\" alt=\"\" class=\"wp-image-3768\" srcset=\"https:\/\/geekmungus.co.uk\/wp-content\/uploads\/2023\/06\/image-4.png 876w, https:\/\/geekmungus.co.uk\/wp-content\/uploads\/2023\/06\/image-4-275x300.png 275w, https:\/\/geekmungus.co.uk\/wp-content\/uploads\/2023\/06\/image-4-768x837.png 768w\" sizes=\"auto, (max-width: 876px) 100vw, 876px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"SetDefaultRootObjectforStaticallyHostedWebsiteonAWSCloudFront(AWSCloudFrontFunctions)-AdditionalInformation\">Additional Information<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/docs.aws.amazon.com\/AmazonCloudFront\/latest\/DeveloperGuide\/example-function-add-index.html\">https:\/\/docs.aws.amazon.com\/AmazonCloudFront\/latest\/DeveloperGuide\/example-function-add-index.html<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/gist.github.com\/mikebroberts\/09e8c8b4aaac6e26149c4622fd492414\">https:\/\/gist.github.com\/mikebroberts\/09e8c8b4aaac6e26149c4622fd492414<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/docs.aws.amazon.com\/AmazonCloudFront\/latest\/DeveloperGuide\/functions-tutorial.html\">https:\/\/docs.aws.amazon.com\/AmazonCloudFront\/latest\/DeveloperGuide\/functions-tutorial.html<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>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.\u00a0https:\/\/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:\u00a0https:\/\/www.geekmungus.co.uk\/studies within which an index.html &#8230; <a title=\"Set Default Root Object for Statically Hosted Website on AWS CloudFront (AWS CloudFront Functions)\" class=\"read-more\" href=\"https:\/\/geekmungus.co.uk\/?p=3764\" aria-label=\"Read more about Set Default Root Object for Statically Hosted Website on AWS CloudFront (AWS CloudFront Functions)\">Read more<\/a><\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[28,3],"tags":[],"class_list":["post-3764","post","type-post","status-publish","format-standard","hentry","category-aws","category-cloud"],"_links":{"self":[{"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/3764","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3764"}],"version-history":[{"count":1,"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/3764\/revisions"}],"predecessor-version":[{"id":3769,"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/3764\/revisions\/3769"}],"wp:attachment":[{"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3764"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3764"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3764"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}