10
votes

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?

1
I think you need to add multiple origins (one for each folder) for your distributionKhalid T.
@KhalidT. ah yes that is exactly how I am attempting to set this up, it is only the redirect issue I'm having when omitting slash in URL's for sub-foldersChristian Westman
Since S3 is an object-based storage, it does not differentiate between files and folders (they are all objects). So, omitting the trailing slash could cause such behavior, I assumeKhalid T.
I'm struggling with the very same issue and I'm in touch with AWS Support but so far their suggested solutions haven't given much. I have managed to solve this by omitting the prefixes in the bucket and not setting an Origin Path in CloudFront. Basically this means one bucket per website which is a bit cumbersome to manage. I'm still trying to work on a solution which would allow multiple websites in a single bucket but I'm not hopeful. In the meantime, the single website/bucket approach is a feasible workaround combined with a few scripts to manage the creation ond deletion on buckets.Carl
If you analyze the network traffic you'll see what happens, if you want to understand the issue at hand. CF will take your /about request and append the Origin path: /websites/website1/about. S3 will respond with a 302 and a Location header: /websites/website1/about/. The client then calls CF with /websites/website1/about/ and CF will again append the Origin Path making the final S3 call /websites/website1//websites/website1/about/ -> 404 (or 403). The problem is that CF and S3 behaves as they are told only their behaviours are incompatible.Carl

1 Answers

11
votes

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>