Redirect to index.html for S3 subfolder
Solution 1
No need for a lambda function adding expense and complexity to your project.
The following answer is quoted from https://stevepapa.com/
https://stevepapa.com/my-great-new-post/
would be expected to work the same way as:https://stevepapa.com/my-great-new-post/index.html
There’s a clever little way to get these flowing through to the Cloudfront distribution, and it involves changing the source origin from the one that Cloudfront presents to you by default.
When selecting the origin source Cloudfront will show you a list of S3 buckets.
Instead of setting the source from the bucket shown in the dropdown list, you’ll need to grab the static web hosting endpoint for that resource from its S3 settings page and pop it in manually.
Using the static source for the Cloudfront distribution origin means any request to that distribution will be using the S3’s root object lookup, and your 404 responses should disappear as the references flow through.
Important
After doing this:
- Clear your browser cache
- Devalidate the items in your Cloudfront distribution
Otherwise, the changes you made won't go live immediately.
Solution 2
So I had this problem last night too.
The issue is as follows:
S3 when configured as a website bucket is forgiving and has the index document setting, set to index.html
and this gets applied at the root, ie, example.com
actually gets redirected to example.com/index.html
, and it also gets applied at the subfolder level, so example.com/new
or example.com/new/
should both redirect to example.com/new/index.html
, where there would be an object in the bucket. (If not, you'd get a NoSuchKey
error instead.)
However you then "upgrade" yourself to CloudFront, likely for HTTPS, and this feature goes away. CloudFront instead makes explicit API calls to S3 and therefore doesn't trigger the index document concession. It does work for the root, but not for subfolders.
The RoutingRules
solution doesn't look clean to me because by specifying KeyPrefixEquals
rather than key exactly equals (which doesn't exist) I think you'd get unintended matches.
I instead have implemented a Lambda@Edge rule that rewrites the request that CloudFront makes to S3 to have a proper key value in it.
Start with the Lambda docs and the A/B testing example here: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-examples.html#lambda-examples-general-examples
Change the code to:
'use strict';
exports.handler = (event, context, callback) => {
/*
* Expand S3 request to have index.html if it ends in /
*/
const request = event.Records[0].cf.request;
if ((request.uri !== "/") /* Not the root object, which redirects properly */
&& (request.uri.endsWith("/") /* Folder with slash */
|| (request.uri.lastIndexOf(".") < request.uri.lastIndexOf("/")) /* Most likely a folder, it has no extension (heuristic) */
)) {
if (request.uri.endsWith("/"))
request.uri = request.uri.concat("index.html");
else
request.uri = request.uri.concat("/index.html");
}
callback(null, request);
};
And publish it to your CloudFront distribution.
Solution 3
There is even easier way to accomplish this with an HTML redirect file
Create a plain file named my-great-new-post (don't worry there won't be a name conflict with the folder in the same bucket)
Write a meta-redirect code in that file (I pasted the code below)
upload file to root bucket (where my-great-new-post folder lays)
modify metadata of the new file and make Content-Type:text/html
Here lays the content of the file:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="refresh" content="0; url=/my-great-new-post/index.html">
</head>
<body>
</body>
</html>
Solution 4
When you enable and configure static hosting with S3 you need to access the site via the bucket website endpoint. You can find this URL in the bucket properties in the Static website hosting section.
The URL of the website endpoint will look like this:
http://example-bucket.s3-website-eu-west-1.amazonaws.com/example-folder/
However (confusingly) objects stored in S3 are also accessible via a different URL, this url does not honour the index rules on subfolders. This URL looks like this:
https://example-bucket.s3-eu-west-1.amazonaws.com/example-folder/
g3blv
Updated on July 09, 2022Comments
-
g3blv almost 2 years
I have a domain
example.com
. I have a S3 bucket namedexample.com
setup with anindex.html
file that works. Now I like to create two subfolders calledold
andnew
, each containing a separate version of a single page application. Requestinghttps://example.com/old
(I like to omit theindex.html
when entering the request in address bar for browser) would open theindex.html
file in theold
subfolder and requestinghttps://example.com/new
would open theindex.html
. What is the best way of doing these redirects? Should I set something up in Route 53example.com/old
->example.com/old/index.html
or is there a better way of doing it? -
g3blv about 6 yearsThanks. That is the guide that I have followed and that is the setup I have in CloudFront but that doesn't work for
example.com/old
orexample.com/new
. It results in access denied whileexample.com/old/index.html
responds with the contents of theindex.html
in theold
folder. Requestingexample.com
should keep responding with theindex.html
underexample.com
. -
g3blv about 6 yearsThanks. I tested it but I still end up at access denied rather than the
old/index.html
ornew/index.html
-
yaliceme almost 6 yearsI had the exact same issue as OP, and this worked! thank you
-
VsMaX over 5 yearsWorked for me!!! Thousands of thanks!!!! You saved my day of time because of thi s article.
-
djuth over 5 yearsWorked for me as well.
-
Dan Parker about 5 yearsWorked great, this should be marked as answer, so I don't have to read the other stuff on top
-
Nogwater about 5 yearsHere's an AWS blog post with a similar solution aws.amazon.com/blogs/compute/…
-
Thomas Amar over 4 yearsThis is the best, simplest answer.
-
101010 about 4 yearsAfter a years (read: years) of messing with S3 redirect rules, I'm done. This works best. "Best" meaning: I do this every few months over years and I appreciate that it "just works".
-
Leonardo Romanello about 4 yearsWould there be a way to achieve the same for
https://stevepapa.com/my-great-new-post
without the trailing/
? -
Askdesigners almost 4 yearsAgreed. The documentation on redirect rules is really not great and there are no examples at all.
-
Michael Schmid over 3 yearsThis does’t work for me. When I enter the endpoint URL, it puts it back to the bucket name upon bluring the input field.
-
Daniel Apt over 3 years@LeonardoRomanello - THis worked without any trailing
/
(it specifically routedhttps://example.com/blog
tohttps://example.com/blog/
automatically) -
michaelosthege over 3 yearsThank you for this simple solution. I appreciate not having to learn what AWS Lambda functions are - let alone how to write them.
-
Charles Fulton over 3 yearsA downside to this approach is that the objects in the S3 bucket must be publicly accessible, otherwise, CloudFront will show a 403 forbidden error.
-
pat-s over 3 yearsUsing the REST API endpoint is preferred over using the website endpoint as otherwise you have two endpoints with different permissions. These might be indexed twice in web searches and the non-SSL endpoint might be vulnerable to potential attacks. See the AWS docs for more info. Therefore I'd highly recommend jkingok answer which uses the Lambda@Edge approach.
-
Hoon over 3 yearsI was browsing for this solution for days! Thanks!
-
baduker about 3 yearsThat is so much better than the official AWS documentation!
-
piyush sachdeva almost 3 yearsThis was the only option that worked for me! Thank you very much for the great workaround
-
diegodsp over 2 yearsThis cause too many redirects.
-
bjovanov over 2 yearsLove you so much!
-
thedanotto over 2 yearsthis is still legit!
-
thapakazi almost 2 yearsManish brought me here... I owe you a beer/coffeee. Thanks mate