Redirect HTTP to HTTPS and WWW to non-WWW with AWS S3, Cloudfront and Route 53 with a custom domain
Overview
This guide explains how to have a custom domain with a secure connection, using Amazon services only.
After finishing the guide you will have the following:
- a static website hosted in Amazon S3
- HTTPS enabled
- all your requests redirects to the non-WWW version
https://example.com
- using Amazon’s Cloudfront CDN.
- using Route 53, Amazon’s domain name server manager
Set up S3
S3 allows you to store and retrieve any amount of data, in particular it makes it easy to set up static websites. The data hosted in S3 is saved as objects and each object can have its custom permissions.
Set up buckets
To have our website hosted in S3, we need to configure two buckets in https://console.aws.amazon.com/s3/buckets/:
non-WWW bucket
One bucket for the naked domain called: example.com
. This bucket will hold
our static website files.
Turn on the Static Website Hosting for example.com
.
Adjust permissions to allow reading your objects, go to the bucket
Permissions
tab, and then Bucket Policy
. We need to configure the
Action: s3:GetObject, then if you don’t use the generator, it
will look something like:
{
"Version": "2012-10-17",
"Id": "Policy1492008478664",
"Statement": [
{
"Sid": "Stmt1492008213599",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example.com/*"
}
]
}
WWW bucket
Another bucket for the www-version domain called: www.example.com
. This
bucket will redirect all the requests that start with WWW to the
non WWW version.
Turn on the Static Website Hosting for www.example.com
.
Go to Properties
tabs, Static Website Hosting
and select
Redirect requests with the following values:
- Target bucket or domain
- example.com
- Protocol
- https
Set up CDN
We need a CloudFront Distribution for each S3 bucket, so each website will have its own CDN.
Go to https://console.aws.amazon.com/cloudfront/ and create two distributions with just the default settings but with small changes.
CDN for example.com
The origin
setting should contain the custom URL endpoint of our S3
website, avoid selecting the one that the dropdown list suggests for
us (REST endpoint) as we need the web site endpoint, not the
bucket, it should have the following form:
<bucket-name>.s3-website-<region>.amazonaws.com
, in this case:
- Origin
example.com.s3-website-us-east-1.amazonaws.com
- Default Cache Behavior Settings / Viewer Protocol Policy
- Redirect HTTP to HTTPS
- Distribution Settings / Alternate Domain Names (CNAMEs)
- example.com
Default Root Object
property.- Distribution Settings / SSL Certificate:
- Custom SSL Certificate (example.com)
- Request or Import a Certificate with ACM
When you create the Certificate include both domains as we are going to use this in the other distribution also:
- Add domain names
- example.com
- www.example.com
And follow the instructions to validate the certificate, then make sure it is selected in the Distribution.
Leave all other setting with their default value.
CDN for www.example.com
Create another distribution for the www.example.com
domain with
these values:
- Origin
www.example.com.s3-website-us-east-1.amazonaws.com
- Default Cache Behavior Settings / Viewer Protocol Policy
- Redirect HTTP to HTTPS
- Distribution Settings / Alternate Domain Names (CNAMEs)
- www.example.com
- Distribution Settings / SSL Certificate:
- Custom SSL Certificate (example.com)
- Select our previously created certificate that includes this domain
Set up domains
We are almost there, now it is time to configure the DNS registry with Route 53.
Go to DNS management / Hosted Zones and create a hosted zone
example.com.
:
- Domain Name:
- example.com.
In this hosted zone, create a Record Set with these values:
- Name:
- (leave it empty)
- Type:
- Alias: Yes
- Select the CloudFront distribution corresponding to example.com
Then create another Record Set for www.example.com
:
- Name:
- www
- Type:
- Alias: Yes
- Select the CloudFront distribution corresponding to www.example.com
Verification
All DNS changes and CDN setup take time to propagate, you will have to wait for propagation, then verify it is all working as expected for HTTP, HTTPS and WWW, non-WWW URLs:
$ curl -sI http://example.com | grep -E '(301|Server|Location|X-Cache|HTTP)' HTTP/1.1 301 Moved Permanently Server: CloudFront Location: https://example.com/ X-Cache: Redirect from cloudfront $ curl -sI https://example.com | grep -E '(X-Cache|HTTP)' HTTP/1.1 200 OK X-Cache: Hit from cloudfront $ curl -sI http://www.example.com | grep -E '(301|Server|Location|X-Cache|HTTP)' HTTP/1.1 301 Moved Permanently Server: CloudFront Location: https://www.example.com/ X-Cache: Redirect from cloudfront $ curl -sI https://www.example.com | grep -E '(301|Server|Location|HTTP)' HTTP/1.1 301 Moved Permanently Location: https://example.com/ Server: AmazonS3
Explanation of commands:
- curl
- transfer a URL
- curl -s
- Silent or quiet mode. Don't show progress meter or error messages.
- curl -I
- (HTTP/FTP/FILE) Fetch the HTTP-header only
- grep
- print lines matching a pattern
- grep -E, --extended-regexp
- Interpret PATTERN as an extended regular expression.
Optional: Disable Direct Access to S3
A good practice is also to make your bucket accessible only from your CDN, i.e.: disable direct access to S3 bucket endpoints.
This prevents security issues, and avoid content duplication in search engines.
1. Make S3 bucket private
- Go to the non-www S3 bucket
- Select the Permissions tab / Block public access
- Press Edit button and select the most generic option
Block all public access
. - Save changes.
- Now go to the Bucket Policy tab.
- Delete the current Bucket policy.
2. In Coudfront
Set the Root Object
- Go to the non-www Cloudfront distribution.
- Press Edit and set the Default Root Object as
index.html
The object that you want CloudFront to return when a viewer request points to your root URL
- Save changes pressing Yes, Edit button.
Use Origin
- Go to Origins and Origin Groups tab.
- Press Create Origin
- In Origin Domain Name start to write the name of the non-www S3
bucket and it will appear in the dropdown list, select it.
- It will look something like
example.com.s3.amazonaws.com
- In Restrict Bucket Access select
Yes
, a new set of options appear. - In Origin Access Identity, create a new Identity or reuse an existing one.
- In Grant Read Permissions on Bucket select
Yes, Update Bucket Policy
so it will generate the appropriate S3 bucket policy for our website. - Hit Create button.
Update Behaviour
- Go to Behaviors tab.
- Select the default behavior and hit the Edit button.
- In Origin or Origin Group dropdown option list, choose the origin we have just created in the above step.
- Save changes with Yes, Edit button.
Access right files
In most cases an additional step is required, this is to correctly handle the access to the S3 bucket files.
So for example, if in your S3 bucket you have an about
file, or
about/index.html
, but in your website you have URLs like /about/
,
it won’t work. We need to process the request and route the /about/
path to correctly ask for the about
file or its index.html
. This
is done in AWS with a Lambda Edge function.
Lambda@Edge lets you run Lambda functions to customize content that CloudFront delivers, executing the functions in AWS locations closer to the viewer. The functions run in response to CloudFront events, without provisioning or managing servers.
This function does (source):
URI paths that end in
.../index.html
are redirected to.../
with an HTTP status code 301 Moved Permanently. (This is the same as an “external” redirect by a webserver).URI paths that do not have an extension and do not end with a
/
are redirected to the same path with an appended/
with an HTTP status code 301 Moved Permanently. (This is an “external” redirect)
Lambda@Edge Function
We will use the function standard-redirects-for-cloudfront, to install it via the Serverless Application Repository:
Press the Deploy button to use the application standard-redirects-for-cloudfront.
It opens a description of the app, hit Deploy again to finish deploying it.
After it has been created, locate the button View CloudFormation stack or go directly to the Cloudformation Console
In the Resources tab, locate the AWS::IAM::Role and open the Physical ID, it will open up the IAM console
Go to Trust Relationship tab and choose Edit the trust relationship to allow CloudFront to execute this function as a Lambda@Edge function., set the policy to:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com", "edgelambda.amazonaws.com" ] }, "Action": "sts:AssumeRole" } ] }
Go back to the Cloudformation’s Stack Detail page and in the Output tab, locate the key StandardRedirectsForCloudFrontVersionOutput and note down its Value (it will look something like:
arn:aws:lambda:us-east-1:XXXXXXXXXXX:function:aws-serverless-repository-StandardRedirectsForClou-XXXXXXXXXXXX:2
). We will use it in the next steps as this is the ARN (Amazon Resource Name) for the Lambda function that we will use in Cloudfront.Go back to the CloudFront console, select the non-www distribution (
example.com
)Go to the Behaviour tab and edit the default Behavior.
Now we use the Lambda function, in Lambda Function Association select Event Type/Origin Request and enter the Lambda function’s StandardRedirectsForCloudFrontVersionOutput ARN value from the previous step.
Wait for the CloudFront distribution to deploy.
All HTML to index.html
Finally, convert all your non index.html
HTML files like an about
file or about.html
into about/index.html
as a
directory/index.html scheme.
Before copying your files to the S3 bucket, use this command to
convert all the non index.html
HTML files files in a public
directory, into the above scheme of filename/index.html scheme so
they can be accessed from Cloudfront:
find public/ -type f ! -iname 'index.html' -iname '*.html' -print0 | while read -d $'\0' f; do mkdir -p "${f%.html}"; mv "$f" "${f%.html}/index.html"; done
It traverses all the HTML from the public
directory, looking for
.html
files, different from index.html
, and creates the
filename/index.html
.
or as a Makefile recipe, you need to escape $ symbol:
prettyurls:
find public/ -type f ! -iname 'index.html' -iname '*.html' -print0 | while read -d $$'\0' f; do mkdir -p "$${f%.html}"; mv "$$f" "$${f%.html}/index.html"; done
Conclusion
It may involve more steps than other deployment solutions but you will enjoy the benefits of Amazon Web Services reliability and cost effective services.
Now all the requests to example.com
will be served by https://example.com
.
References
- S3 docs https://aws.amazon.com/s3/
- Cloudfront docs https://aws.amazon.com/cloudfront/
- Route 53 https://aws.amazon.com/route53/
- RKI answer in Cloudfront redirect www to naked domain with ssl
S3 Website features can be used in conjunction with Amazon CloudFront. However, S3 Website uses a different domain name than regular S3 buckets. In this case, you’ll need to set the Origin Domain Name of your CloudFront distribution’s origin configuration to new.rdegges.com.s3 website us east 1.amazonaws.com.
- Redirect HTTP to HTTPS and WWW to non-WWW with AWS S3, Cloudfront and Route 53 with a custom domain
Articles
Except as otherwise noted, the content of this page is licensed under CC BY-NC-ND 4.0 . Terms and Policy.
Powered by SimpleIT Hugo Theme
·