How to host a Static Website on AWS S3 and CloudFront with SSL

A static website contains web pages with fixed content and these individual web pages on the website include static content which might also contain client-side scripts.

But why S3 ?

Amazon Web Services (AWS) S3 Static Website Hosting is cheap, scalable, and performant. When combined with CloudFront it’s even better. Setting up an S3 bucket to function as a website is nice and simple and will support HTTPS out of the box, however, you’ll be restricted to using the bucket URL as the endpoint.

To work around this, we’re able to use CloudFront to host our website from Amazon’s edge locations with a custom SSL certificate setup for our domains.

Let’s start with the basics

Amazon S3

Amazon S3 is an acronym for Amazon Simple Storage Service. It is a typical web service that allows us to store and retrieve data via an API reachable over HTTPS. The service offers unlimited storage space and stores your data in a highly available, durable and secure way.

Amazon CloudFront

Amazon CloudFront is a content delivery network (CDN). It caches the content on Amazon’s globally distributed network of proxy servers and then intercepts user’s requests in order to route them to their closest proxy server.

AWS Certificate Manager

AWS Certificate Manager handles the complexity of creating and managing public SSL/TLS certificates for your Amazon Web Services (AWS) based websites and applications. You can use public certificates provided by ACM (ACM certificates) or certificates that you import into ACM. ACM certificates can secure multiple domain names and multiple names within a domain.

Lambda@Edge

Lambda@Edge allows running Lambda functions to customize the content that CloudFront delivers and executing the functions in AWS locations closer to the viewer. The functions run in response to CloudFront events without provisioning or managing servers. With Lambda@Edge we can add, delete, and modify headers and rewrite the URL to direct users to different objects in the cache.

We can use Lambda functions to change CloudFront requests and responses at the following points:

  • Viewer request – After CloudFront receives a request from a viewer
  • Origin request – Before CloudFront forwards the request to the origin
  • Origin response – After CloudFront receives the response from the origin
  • Viewer response – Before CloudFront forwards the response to the viewer

Thumb rule for Lambda@Edge

  • Lambda functions must be created in US-EAST-1 (Virginia) Region
  • No support for an environment variable
  • Only node Js is supported
  • Execution logs from Lambda@Edge functions go to CloudWatch. It is usually (not always) the location closest to the client

Let’s start Deploying

To explain the concept better, we will explain the process for one of our websites – Polly.

1. Creating and configuring an S3 bucket to host a static HTTP website

We start by getting our static website uploaded to Amazon’s S3 service and configuring the bucket for static website hosting.

  • Sign in to the console using this link
  • From the console select the S3 service (If you don’t see S3, just type S3 into the AWS services search bar and it should be the first result)
  • Select “Create bucket” in the S3 console to create a new bucket to hold the site
  • Next, give the bucket a name. It is important that you do not use a bucket name which contains periods. Stick to letters and dashes.  And click on “Create”
  • Enable static website hosting property. Click on “Properties” then click on the “Static website hosting” card.
  • Select “Use this bucket to host a website” and enter “index.html” as Index document
  • Click on “Save” and the window below should be visible
  • Set Bucket CORS Policy. Set a bucket policy to enable public access to all objects in this bucket. Click the ‘Permissions’ tab then select ‘Bucket Policy’
  • Paste the following policy document in the text area, ensuring that you replace ‘{BUCKET}’ with the name of your bucket

{
     “Version”: “2012–10–17”,
     “Statement”: [
     {
          “Sid”: “PublicReadGetObject”,
          “Effect”: “Allow”,
          “Principal”: “*”,
          “Action”: “s3:GetObject”,
          “Resource”: “arn:aws:s3:::{BUCKET}/*”
     }
  ]

}

2. Getting a free SSL certificate with AWS Certificate Manager

The certificate allows the user’s browser to verify that they are on a real website. It also enables the encryption of data transferred between the user and the website. We can either request the certificate in ACM or we can import the certificate in ACM.

We use the Certbot CLI Tool to create an SSL Certificate and import that in ACM. Domain registration can be done in GoDaddy, Route 53 or any other domain provider of your choice.

For importing a certificate go to “Import a Certificate” option and the below window should be displayed.

3. Configuring CloudFront

  • Select the CloudFront service from the AWS Management Console
  • On the CloudFront console, click “Create Distribution”
  • We’re going to create a web distribution, so under the section labeled “Web” select “Get Started”

  • The next screen will have several sections. Under the section for “Origin Settings”, you need to enter your bucket’s endpoint URL (the one you copied earlier when enabling static hosting) as the “Origin Domain Name”
  • You need to paste in your bucket’s endpoint URL as the Origin Domain Name
  • Selecting from the drop-down list can lead to issues with CloudFront redirecting to your bucket’s endpoint URL instead of forwarding. The “Origin ID” will be automatically populated for you after you enter your “Origin Domain Name”. You can leave the rest of the “Origin” on default values
  • In the “Default Cache Behaviour Settings” select Redirect HTTP to HTTPS to ensure all users utilize secure connections. You can leave everything else in the “Default Cache Behavior Settings” at the default setting
  • In the next section titled “Distribution Settings”, you need to enter your custom domain name. (This is the domain name that you purchased from your DNS Hosting Provider like GoDaddy, AWS Route 53)
  • Make sure to list both the www prefixed domain name and the naked domain name
  • Add an alternate domain name
  • Scroll all the way to the bottom of the page to click “Create Distribution”
  • After clicking on “Create Distribution” the distribution will be deployed in 15 minutes and is good to go

4. Adding Lambda@Edge 

 CloudFront intercepts requests and responses at CloudFront edge locations. It means you may add “intelligence” in the CDN, without having to forward the request to the backend and losing benefits of content caching and geographical proximity with the client.

  • In our scenario we are using Lambda@Edge primarily for below-mentioned use cases
    • A/B testing – Imagine you have a static website or a single page application served through the CDN. You want to experiment the two versions with actual users but you don’t want to create redirects or change the URL
    • Redirecting unauthenticated users to a sign-in page after validating the cookies
    • Using an origin-request trigger to change from an Amazon S3 origin to a custom origin
  • For setting up Lambda@Edge create a lambda function in Virginia Region (supported in Virginia only) and create a node.js lambda. 
  • Set the required IAM Permissions and roles for Lambda@Edge
  • Enable Cloudwatch trigger logs for Lambda@Edge

The complete set of examples on how we can manipulate request and response at the edge location can be viewed here.

Let’s take a look at how we suffice our use cases with the help of Lambda@Edge.

Polly has a login page for new users/logged out users and a dashboard for existing and logged in users.

In the below code we are checking whether the cookie has a token or not. If not then it should redirect to Login Page, else it should redirect to the Dashboard Page.

exports.handler = (event, context, callback) => {
   let path, request, headers, request_url;
   request = event.Records[0].cf.request;
   headers = request.headers;

if (headers.cookie) {
      for (let i = 0; i < headers.cookie.length; i++) {
          // Add logic to fetch cookie and redirect the URLs based on cookies

}}
callback(null, request);
};

After writing the code above, save and publish a version of Lambda.

Now add the Lambda to CloudFront distribution inside the behavior section. Select the behavior and edit it.

Select the trigger and add the Lambda ARN in front of it. Lastly, click “Yes Edit” and let the CloudFront be deployed and your work is done.

Lambda ARN will be displayed in the Lambda Management console at the top right side just after you publish the version.

That’s it. You did it!🥳

Aastha Gupta Written by:

One Comment

  1. John Darer
    February 12, 2019
    Reply

    This article offers a clear idea in favor of a new site hosting!

Leave a Reply

Your email address will not be published. Required fields are marked *