11

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?

Theodore
  • 1,683
  • 2
  • 12
  • 13
  • 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.se]. In the future please ask there rather than here. – Stephen Ostermiller Nov 19 '21 at 01:55

5 Answers5

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

Paramvir Singh Karwal
  • 597
  • 1
  • 10
  • 24
  • 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". – grayaii May 17 '22 at 12:06
  • 1
    I can't access your article, it seems to be dead – Tobias Feil Jul 05 '22 at 12:16
  • 1
    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. @TobiasFeil – Paramvir Singh Karwal Jul 06 '22 at 05:16
  • 1
    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... – Dan G Sep 02 '22 at 16:30
5

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.

Wilhelm Sorban
  • 1,012
  • 1
  • 17
  • 37
  • 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. – Prateek Nov 27 '22 at 23:14
  • @Prateek 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 Specified – Wilhelm Sorban Nov 30 '22 at 23:29
  • @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. – Prateek Dec 04 '22 at 13:35
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.

HEEWON
  • 21
  • 2
  • 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.. – Theodore Apr 21 '17 at 18:52
  • @Theodore 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. – HEEWON Apr 23 '17 at 09:18
  • do the buckets have to be public – Glen Thompson Mar 16 '18 at 22:53
  • 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/*" } ] }` – fencepencil May 12 '18 at 00:38
  • 3
    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. – Seivan Mar 09 '20 at 04:19
  • this gives me a ERR_TOO_MANY_REDIRECTS error when navigating to the www website – Maurice Oct 20 '22 at 19:56
0

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

Off Axis
  • 11
  • 3
-1

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.

Alaa Moneam
  • 509
  • 5
  • 10
  • 2
    Unfortunately, this isn't great for SEO as you'd now have two duplicate sites in the eyes of a search engine. – tyirvine Mar 22 '22 at 02:30