{"id":20284486,"url":"https://github.com/artyom/cloudfront-autoindex","last_synced_at":"2025-04-11T08:25:13.223Z","repository":{"id":66758953,"uuid":"334173473","full_name":"artyom/cloudfront-autoindex","owner":"artyom","description":"AWS Lambda to work around index.html S3/CloudFront mess","archived":false,"fork":false,"pushed_at":"2022-01-19T16:27:52.000Z","size":10,"stargazers_count":25,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-25T05:53:13.383Z","etag":null,"topics":["aws-lambda","cloudfront","s3-website"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/artyom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-29T14:45:41.000Z","updated_at":"2023-01-02T08:14:39.000Z","dependencies_parsed_at":"2023-03-13T20:29:35.536Z","dependency_job_id":null,"html_url":"https://github.com/artyom/cloudfront-autoindex","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artyom%2Fcloudfront-autoindex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artyom%2Fcloudfront-autoindex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artyom%2Fcloudfront-autoindex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artyom%2Fcloudfront-autoindex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/artyom","download_url":"https://codeload.github.com/artyom/cloudfront-autoindex/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248361101,"owners_count":21090818,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws-lambda","cloudfront","s3-website"],"created_at":"2024-11-14T14:19:55.272Z","updated_at":"2025-04-11T08:25:13.185Z","avatar_url":"https://github.com/artyom.png","language":"Go","readme":"# No more index.html mess with AWS CloudFront/S3\n\n## Problem\n\nConsider you have a statically generated site — a bunch of usual resources, including html files.\nYou test this site locally with a development web server for convenience, and everything works.\nYou set up a private S3 bucket plus a CloudFront distribution authorized to access this bucket to expose site at your domain and get caching benefits.\n\nBut once you upload your resources, you run into an issue: your site relies on relative links like `/section/`, expecting that you'll get contents of `/section/index.html` file in response — after all, lots of web servers implement this logic as their default behavior — but accessing such relative link over CloudFront returns a 403 error page.\nAfter some troubleshooting you figure out that configuring `index.html` as a default root object on the CloudFront distribution only really works for *root object*, and [does not work with subdirectories](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DefaultRootObject.html#DefaultRootObjectHow).\n\nIf this scenario looks familiar, then this tool can help you.\n\n## Solution\n\nCommand cloudfront-autoindex is an AWS Lambda that processes S3 `ObjectCreated` events looking for objects with `/index.html` suffix in their name, and makes copies of those objects with `/index.html` and `index.html` suffixes stripped.\n\nThis way if you have a directory `doc` with an `index.html` file in it, and you upload that directory to an S3 bucket fronted by CloudFront, you can then see your page not only by accessing `https://example.org/doc/index.html`, but also at `https://example.org/doc` and `https://example.org/doc/`, as this Lambda creates two copies of `doc/index.html` key under `doc` and `doc/` keys.\n\n## Setup\n\nBuild and compress:\n\n    GOOS=linux GOARCH=amd64 go build -o main\n    zip -9 lambda.zip main\n\nCreate a new AWS Lambda, picking the \"Go 1.x\" runtime. Change its handler name from default \"hello\" to \"main\" (binary name you built above), and upload lambda.zip file.\n\nIt requires the usual permissions, e.g. `AWSLambdaBasicExecutionRole` AWS-managed role, plus these permissions to work with S3 (optionally limit with your bucket names):\n\n    {\n        \"Version\": \"2012-10-17\",\n        \"Statement\": [\n            {\n                \"Sid\": \"CopyObject\",\n                \"Effect\": \"Allow\",\n                \"Action\": [\n                    \"s3:PutObject\",\n                    \"s3:GetObject\"\n                ],\n                \"Resource\": \"arn:aws:s3:::*/*\"\n            }\n        ]\n    }\n\nOnce Lambda is created and configured, go to S3 bucket settings, Properties → Event notifications → Create event notification. Enter `index.html` as a *Suffix*, and select `s3:ObjectCreated` events except for the `s3:ObjectCreated:Copy`. Pick your Lambda function created above as event destination.\n\n## Caveats\n\n### Relative Links\n\nIf an index.html page has relative links to other resources, such links may appear broken depending on which path you access such a page.\n\nFor example, if you have an `/years/index.html` page that links to a `2021.html` file, such link will be resolved to `/years/2021.html` when you access the page `/years/index.html` or its automatically created copy at `/years/`. But if you access an automatically created copy at `/years` path, the browser will resolve such a relative link to just `/2021.html`.\n\nConsider using the [`\u003cbase\u003e` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) to lock the base path for relative links.\n\n### Canonical Path\n\nSearch engines may get confused on which page address is the primary one in the presence of such multiple copies. Their primary source choice may be different from yours.\nUse the [canonical link element](https://en.wikipedia.org/wiki/Canonical_link_element) on your page to set its main address, like `\u003clink rel=\"canonical\" href=\"…\"\u003e`.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fartyom%2Fcloudfront-autoindex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fartyom%2Fcloudfront-autoindex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fartyom%2Fcloudfront-autoindex/lists"}