Redirect www to non-www with S3/CloudFront without seperate buckets
Asked Answered
A

6

14

I'm hosting a static websites on S3 with CloudFront.

Now, both www.example.com and example.com return the same, but I only want example.com to work, and www.example.com to redirect to example.com.

I know I can create an another bucket that will redirect to the main bucket (example.com), but then I'll have two buckets and two CloudFront distributions for each website and it'll make a mess.

Is there an another way to accomplish that?

Anticathexis answered 15/4, 2017 at 14:7 Comment(1)
I voted to close this question because it is not a programming question and it is off-topic on Stack Overflow. Non-programming questions about your website should be asked on Webmasters. In the future please ask there rather than here.Distinction
D
8

Recently AWS introduced Cloudfront Functions. As you can guess it allows you to manipulate http request/response within the cloudfront using custom function code.

In their introductory blog they have covered this specific redirection use case. As per their blog Introducing CloudFront Functions – Run Your Code at the Edge with Low Latency at Any Scale:-

URL rewrites and redirects: Generate a response to redirect requests to a different URL. For example, redirect a non-authenticated user from a restricted page to a login form. URL rewrites can also be used for A/B testing.

I have experimented on this approach. What I did:-

  1. Set up a new cloudfront distribution.
  2. Mapped this distribution to the existing website bucket (doesn't really matter)
  3. Associated a new redirect_www_to_naked function with this distribution.
  4. Mapped this distribution to www subdomain in Route 53

This is how my function looks like:-

enter image description here

And this is my association settings enter image description here

Edit: I wrote a blog about it explaining in detail if you would want to learn more - Redirect WWW to Naked Domain using CloudFront Function

Driveway answered 9/5, 2021 at 17:41 Comment(4)
Every single request to the website will hit that lambda function. Unfortunately, that's a LOT of lambda calls. Is it possible to do it in the "origin response", and NOT the "Viewer Request".Devout
I can't access your article, it seems to be deadHoff
apparently the server got down because aws couldn't charge my card due to country regulations. will make it live again once I got some time. @TobiasFeilDriveway
It'll only hit when users go to the 'www' domain, subsequent hits will not hit that distribution - so no lambda calls. And unless you're site is getting millions of hits - the lambda costs wouldn't be bad... And in that case maybe a s3-bucket site isn't the right fit.. ;) Good problem to have...Assignation
C
8

After spending many hours, searching and trying different solutions, either in Cloudfront or in Route53, the solution that @Paramvir has suggested, has finally helped me figure it out.

I ended up using a Cloudfront function, that looks like this:

function handler(event) {
    var request = event.request;
    console.log(request.headers["host"]);
    if (request.headers["host"] && request.headers["host"].value.startsWith("www")) {
        var response = {
            statusCode: 301,
            statusDescription: 'Moved Permanently',
            headers: {
                'location': { value: 'https://naked_address.com'+event.request.uri }
            }
        };
        return response;
    }
    return request;
}

What it basically does is that it checks for the request address, if it starts with www, then redirects it to naked address. Otherwise it returns the untouched request.

Of course, don't forget to save your function, then publish it. After you do this, you must associate it to your distribution.

Chausses answered 24/7, 2022 at 22:54 Comment(3)
Can you please help me with how we retain the query params as well during redirect? Your function is redirecting correctly but it is ignoring the query params.Barham
@Barham That is a CloudFront parameter - in the Behavior setting, you have a dropdown to choose the query strings that you wish to forward - either None, All, or SpecifiedChausses
@Wihelm Soarban I already have "All" to forward query params. All my query params are redirecting properly but when this CloudFront redirect is happening, it isn't sending query params. The redirect URL itself is removing query params. Let alone passing it to origin.Barham
T
3

In addition to @Wilhelm Sorban

You can set location like this to not include the domain name:

'location': { value: 'https://'+request.headers["host"].value.replace('www.', '')+event.request.uri }

But i did not find any header value for protocol (http or https) in Cloudfront function docs: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/functions-event-structure.html#functions-event-structure-request

Tellurian answered 6/7, 2023 at 10:12 Comment(1)
This is generic, so the same Cloudfront function can be used for multiple Cloudfront distributions.Pliable
C
1

Small addition to the wonderful answers provided here:

I used the provided code on the original cloudfront distribution. Added the www to it so it could serve both www and naked, and the function did redirect - basically to itself.

Also changed the function a bit to redirect with the query string:

'location': { value: 'https://'+request.headers["host"].value.replace('www.', '')+event.request.uri.replace("https://","").replace("http://","").replace(request.headers["host"].value,"") }
Compost answered 7/11, 2023 at 11:28 Comment(0)
G
0

You seem to be using DNS services as you mention example.com
However, I do not know what DNS service you are doing.
Because Route 53 is commonly used, it is described on the basis of Route 53.
Domains are described on the basis of example.com.

You can code redirects from example.com to www.example.com programmatically.
However, it is common to resolve this at the AWS level.

Two buckets are required to resolve at the AWS level.

  1. example.com (content bucket)

  2. www.example.com (bucket redirected to example.com)
    S3 -> Properties -> Static web hosting -> redirect request
    Target bucket or domain: example.com
    Protocol : http
    (No files are required for buckets.)

  3. Mapping example.com to the A record on Route 53.

  4. Mapping www.example.com to Route 53's A record.

Then, if you request www.example.com, you will be redirected to example.com.

If you have any questions, feel free to ask!
Thank you.

UPDATE 1
If you activate your CloudFront CNAME for example.com and www.example.com,
You can get example.com and www.example.com requests with just one bucket.
However, it is not recommended because the consistency of URLs is not good.

Goosefish answered 21/4, 2017 at 6:43 Comment(6)
I am aware of your method, but as I mentioned in my question: "I know I can create an another bucket that will redirect to the main bucket (example.com), but then I'll have two buckets and two CloudFront distributions for each website and it'll make a mess." I am looking for a method that doesn't require the creation of 2 buckets..Anticathexis
@Anticathexis Having two buckets does not mean you're deploying two CloudFronts. Create a deployment for example.com buckets only. The www.example.com bucket is a bucket for redirecting to the example.com domain.Goosefish
do the buckets have to be publicSouza
The main bucket (with the files) has to be public ... Permissions>Bucket Policy { "Version": "2008-10-17", "Statement": [ { "Sid": "PublicReadForGetBucketObjects", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::example.com/*" } ] }Weather
This doesn't answer the question, more so, it completely ignores the request to avoid two buckets.Not to mention mapping the www to naked domain doesn't actually cause a redirect, it just serves the same content from www instead which I doubt the is what's requested. Unless Mapping www.example.com to Route 53's A record. means mapping to the bucket, it's unclear what you mean. Regardless, it's not an answer as this as I understand it the current solution without cloudfront.Kare
this gives me a ERR_TOO_MANY_REDIRECTS error when navigating to the www websiteFelonry
M
-2

here what works for me

1- created a new cloud Front distribution and make it refers to the same s3 bucket that original one refers.

2- created a new record in route 53 give it prefix www.example.com and make it refer to the newly created cloud front distribution.

then if you typed example.com or www.example.com they'll redirect to the same bucket and the two works fine

hope this is helpful.

Montespan answered 27/12, 2021 at 8:3 Comment(1)
Unfortunately, this isn't great for SEO as you'd now have two duplicate sites in the eyes of a search engine.Chirp

© 2022 - 2024 — McMap. All rights reserved.