I read many answers to this question but for some reason neither of them works for me. I have static website served by S3 with static website feature enabled and index document set to index.html. And there is CloudFront distribution pointing to that static S3 website. In my bucket I have following files, each of them with public access:
file1.html
file2 (with Content-Type: text/html metadata)
file3/index.html
I tried visiting following pages:
https://example.com/file1.html => works
https://example.com/file2 => 404
https://example.com/file3 => 404
https://example.com/file3/index.html => works
404 response returns this:
<Error>
<Code>NoSuchKey</Code>
<Message>The specified key does not exist.</Message>
<Key>index.html</Key>
<RequestId>02KPT6454CMB1D5M0</RequestId>
<HostId>pxZgtslx4ddbSh645ZiYxlLWEg6xxGLjxlwZNO+JzjFb4eu1/kp4SYZoMFXZO7muXtZ/iJZ9g=</HostId>
</Error>
I am struggling with this for several hours and can't make it work. From what I read I should either upload (or rename through S3 console) file without extension and add Content-Type: text/html metadata to it or I should create folder named like a file without extension and put file named index.html inside. Neither of those options works.
Let's say I have an S3 bucket named example.com and I want to serve its content through CloudFront using an alternate domain example.com.
I've added a CNAME record to direct example.com to the CloudFront endpoint, and secured the domain using an AWS SSL Certificate.
In CloudFront, when I go to select the Origin, it shows my bucket. For example: example.com.s3.amazonaws.com
If I choose this origin, and I browse to https://example.com/my-bucket-item.jpg, I get redirected to https://example.com.s3-us-east-2.amazonaws.com/my-bucket-item.jpg and a "Connection not secure" SSL error appears.
If I set the origin to just the domain example.com then I get a 403 Bad Request error from CloudFront.
From what I understand, my bucket has to share the name of my domain, otherwise I get a "bucket does not exist" error.
I've followed the AWS documentation on this. What I'm doing wrong here?
Update
I successfully got CloudFront to recognize my alternate domain by changing my origin policy to Managed-CORS-S3Origin.
New problem: even though I've selected 'Yes' to 'Restrict Bucket Access', I'm still able to access files via the S3 url. Do I need to turn off public access to my bucket? If I do this, it seems to override my CloudFront policy...
I had to change my origin request policy to Managed-CORS-S3Origin - this solved the general problem for me.
I have a Vue.js application up and running with Amazon S3 and Cloudflare.
When I open the index and browse to /dashboard, everything works fine. But when I open a route like dashboard directly in a new tab or refresh the page, I get the following error back from S3:
404 Not Found
Code: NoSuchKey
Message: The specified key does not exist.
Key: unternehmen
RequestId: 6514F8A1F4C29235
HostId: +BVrPLJSGdzSYogzWZ4GMBXkgkdSJWRVJVhcSs4EI/lmMUR422aCtCxpBGU6AMe5VkS1UbEn/Lc=
Just read that the problem is Vue.js history mode: https://router.vuejs.org/de/essentials/history-mode.html
I would like to solve the problem with a routing rule in my Amazon S3 Bucket. How would the Apache RewriteRule look for S3?
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
Tried the following but it does not work:
<RoutingRules>
<RoutingRule>
<Condition>
<HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
</Condition>
<Redirect>
<HostName>domain.com</HostName>
<ReplaceKeyWith>index.html</ReplaceKeyWith>
</Redirect>
</RoutingRule>
</RoutingRules>
If I do it like that I just get my Header and Footer rendered but nothing more.
Thank you!
I know this answer comes late but in case someone else is looking for another way to solve this in cloudfront, there's no need to create custom pages on s3 redirecting users when pages are not found. Instead of doing it, custom error responses can be created in cloudfront for the distribution.
This will always redirect to /index.html in case a file is not found and that will make the app route trigger.
If you use static hosting on AWS S3 and this is SPA app (React, Vue, Angular etc) you should set index.html as error page:
I'm hosting a static PWA made in Vue on S3 using "Static website hosting" and it works as expected.
What I did was quite simple - I've added this:
<RoutingRules>
<RoutingRule>
<Condition>
<HttpErrorCodeReturnedEquals>403</HttpErrorCodeReturnedEquals>
</Condition>
<Redirect>
<ReplaceKeyWith></ReplaceKeyWith>
</Redirect>
</RoutingRule>
</RoutingRules>
To the Properties of the S3 bucket. See image below:
For my S3 bucket, everytime you try to access a file that doesn't exist you will receive a 403 (forbidden) instead of a 404. That is why I've changed the HttpErrorCodeReturnedEquals to 403. I've also replaced the ReplaceKeyWith with an empty string as "index.html" as not triggering the correct route.
I hope it helps.
Cheers,
Alex
I think this problem has two components:
1.
If a request is made directly (outside of the Javascript App) to a sub path such as /jobs then S3 returns a 404, because the path/object doesn't exist. The simplest way to fix this is from within S3 itself, where you redirect all error pages back to index.html.
However this doesn't work from a CDN such as Cloudfront, and presumably Cloudflare.
A good trick is to use files inside S3 that redirect users like this:
jobs/ -> /index.html
jobs -> /index.html
For example if someone makes a request to site/ they will get the following html file:
"redirect":"<html><head><meta http-equiv=\"refresh\" content=\"0; url=http://example.com/site/index.html\" /></head>
<body>Redirecting to Home</body></html>"
Secondly...
If I do it like that I just get my Header and Footer rendered but
nothing more.
This is a problem I've had where the router-view doesn't initialise properly, even though the component that contains the router-view has loaded.
What I have done for now is redirect my router when the main "App" component is created:
created () {
console.log('route', this.$route.path)
this.$router.replace(this.$route.query.redirect || '/')
}
This has the added bonus of removing the index.html from your path (Which was put there by your new redirections) whilst forcing your router-view to render...
My #app component is the parent component, with a navbar, footer, and the router-view that renders all of the sub pages/components.
One way to make this work in with routing in history mode and without using CloudFront is to create the files that your URIs would point to. So let's say you use index.html as your entry point and have only one other page which you give path page2.html.
Then you should adapt your build and deploy process to do the following:
Build your source into a production distribution (E.g. using npm run build)
Make sure that for your router links you create a file per path that is a copy of the original file. In case of the example I mention it would be creating a copy of 'dist/index.html' to 'dist/page2.html'
Copy the dist folder contents to your S3 bucket
Note that the order of step 1 and 2 is important.
This can be easily done in a script that publishes your website.
I have just used this approach with the result I wanted; allowing refreshinag a page and opening links in a new tab.
Drawbacks I see is:
- overhead of storing the copies of the files
- have to make sure if you add a page not to forget to update your build and deploy scripts.
The selected answer (403 and 404) did not work for me.
It was only after I added a similar 400 rule did my VUE app function in history mode.
for anyone using an AWS SAM template:
CloudFront:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
...
CustomErrorResponses:
- ErrorCode: 404
ResponseCode: 200
ResponsePagePath: /index.html
- ErrorCode: 403
ResponseCode: 200
ResponsePagePath: /index.html
- ErrorCode: 400
ResponseCode: 200
ResponsePagePath: /index.html
I'm having some difficulties setting up static website hosting using Amazon S3 and Cloudfront.
We have many websites that we would like to serve as static websites using Amazon S3 + Cloudfront and we would prefer to host them all in a single S3 bucket.
Initial setup is pretty straight forward but we are having issues with sub-folder redirects if omitting trailing slash in the URL.
example, setting up a single website from the bucket:
bucket contents for website1:
s3://bucket-name/websites/website1/index.html
s3://bucket-name/websites/website1/about/index.html
I have enabled static website hosting for this bucket with default document set to 'index.html'
I have created a Cloudfront web distribution to serve this single website, default root object is set to 'index.html'.
The distribution has a custom origin pointing to the static website url 'bucket-name.s3-website-us-east-1.amazonaws.com' with Origin Path set to '/websites/website1'
When navigating to the distribution url 'http://example.cloudfront.net' it correctly serves the 'index.html' document from 's3://bucket-name/websites/website1/index.html'
When navigating to 'http://example.cloudfront.net/about/' it also correctly serves the 'index.html' document from 's3://bucket-name/websites/website1/about/index.html'
But, if I omit the trailing slash like 'http://example.cloudfront.net/about' S3 redirects me to 'http://example.cloudfront.net/websites/website1/about/', since I have Origin Path set to '/websites/website1' Cloudfront will request index.html from 's3://bucket-name/websites/website1/about/websites/website1/about/index.html' which does not exist.
Am I missing something here? Is this an impossible setup using only Cloudfront and S3?
I ended up solving it by using routing rules for the S3 bucket
https://docs.aws.amazon.com/AmazonS3/latest/dev/how-to-page-redirect.html
the problem is the redirect caused by omitting a trailing slash results in the Orgigin Path being appended to the full S3 bucket path ("example.cloudfront.net/about" redirects to "example.cloudfront.net/websites/website1/websites/website1/about/" that fails because the path is invalid)
The below routing rule solves this by triggering on the faulty path pattern prefix and redirecting back to the Cloudfront distribution with the prefix stripped from the request, i.e ("example.cloudfront.net/about" redirects to "example.cloudfront.net/websites/website1/websites/website1/about/" that redirects to "example.cloudfront.net/about/")
The downside is that you need to remember to modify the routing rules when adding new distributions
<RoutingRules>
<RoutingRule>
<Condition>
<KeyPrefixEquals>websites/website1/websites/website1/</KeyPrefixEquals>
</Condition>
<Redirect>
<HostName>example.cloudfront.net</HostName>
<ReplaceKeyPrefixWith></ReplaceKeyPrefixWith>
</Redirect>
</RoutingRule>
</RoutingRules>
I'm currenly trying to use amazon s3 as image hosting through cloudflare.
I would like to use my subdomain as image url.
I set CNAME in cloudflare like below.
image.domain.com CNAME image.domain.com.s3.amazonaws.com
my bucket name in s3 is image.domain.com
But I got error below when I go to image.domain.com
<Error>
<Code>InvalidArgument</Code>
<Message>Unsupported Authorization Type</Message>
<ArgumentValue>Basic dGFiaXBlZGlhc3RhZmdedaefaeeYW5jZQ==</ArgumentValue
<ArgumentName>Authorization</ArgumentName>
<RequestId>4EEDAB31EAD3C24F1</RequestId>
<HostId>
DbqMpmzTxU4c/gE4uC6fadaebwtb35wtggtbrtbtt vIm5IZC9lg1xDoixF
</HostId>
</Error>
I have to use website hosting in s3 for this setting? or I missed some configurations..?
That looks like more of an issue with S3, from what I can see. Some general tips about S3 and CloudFlare.