If you need to look for a cheap hosting for a static website AWS S3 could be a great solution for you. You won’t have to worry about scaling, server capacity… just to upload the files to a bucket.

And with the help of CloudFront we’ll end up having an awesome performance and HTTPS in place.

Create a S3 bucket

The first thing we need to do is creating the S3 bucket, if it’s available get the domain name we want to use as S3 bucket name. I.e.: example.com. Do it in the region you prefer, in my case I chose EU (Frankfurt) eu-central-1.

Go here to do it.

Activate static website hosting in S3

Open the bucket that you just have created, enter to the Properties tab, and scroll down to the end of the screen, you’ll see Static website hosting option, click to Edit.

Select the following options:

  • Static websit hosting: Enable
  • Hosting type: Host a static website
  • Index document: Normally this is index.html

Then click to Save changes.

Create a CloudFront distribution

Go to CloudFront page.

Click to Create Distribution button and Get Started for Web in the next screen.

Complete the following options:

  • Origin Domain Name: Select the S3 bucket you just created
  • Restrict Bucket Access: Yes
  • Origin Access Identity: Create a New Identity
  • Grant Read Permissions on Bucket: Yes, Update Bucket Policy
  • Viewer Protocol Policy: Redicet HTTP to HTTPS
  • Cache Policy: Managed-CachingDisabled this is just for testing so we don’t get cached responses, we’ll activate cache later
  • Default Root Object: index.html same as S3 index document
  • Comment: Set your domain name or site name so we can identify the distribuition later

After that we should see our new CloudFront distribution in the list with status Desploying, and after a while this status should be Deployed, that means that we are ready to test our distribution.

To do it CloudFront give us a URL in column Domain Name similar to: 0000000.cloudfront.net. If we haven’t uploaded any file to the S3 bucket we’ll get an error, try to upload a index.html file and check that the response is correct.

Subfolders problem

CloudFont has a problem getting the root object of subfolders. So requests like example.com will correctly load example.com/index.html. But requests like example.com/somefolder won’t load example.com/somefolder/index.html.

To solve that we have two options:

  • Give public access to the S3 bucket and change the origin of CloudFront of the distribution to Custom Origin and set the S3 URL.
  • Set a Lambda@Edge that will do that transformation.

We chose the second option because it allos us to not have the S3 bucket public so all the traffic will go through HTTPS. But if we have to handle a lot of traffic the first option could end up being much cheaper.

Create Lambda@Edge (optional)

Create a new lambda in region US East (N. Virginia) us-east-1, it’s the only region with CloudFront activated so far.

Go to lambda page.

Click to Create function.

Select Author from scratch.

Choose a name and select Node.js 14.x as runtime, then click to Create function

As Execution role select Create a new role from AWS policy tempmlates, set Role name to something like LambdaEdgeCloudFrontAccessRole, and in Policy templates search for: Basic Lambda@Edge permissions (for CloudFront trigger).

Copy&paste the following code to Function code textarea.

'use strict';
exports.handler = (event, context, callback) => {
    
    // Extract the request from the CloudFront event that is sent to Lambda@Edge 
    var request = event.Records[0].cf.request;

    // Extract the URI from the request
    var olduri = request.uri;

    // Match any '/' that occurs at the end of a URI. Replace it with a default index
    var newuri = olduri.replace(/\/$/, '\/index.html');
    
    // Log the URI as received by CloudFront and the new URI to be used to fetch from origin
    console.log("Old URI: " + olduri);
    console.log("New URI: " + newuri);
    
    // Replace the received URI with the URI that includes the index page
    request.uri = newuri;
    
    // Return to CloudFront
    return callback(null, request);

};

Click to Deploy to apply the changes.

Click to Add trigger, select CloudFront and then click to Deploy to Lambda@Edge.

Select the distribution we created from the list and check the acknowledge checkbox. Then click to Deploy.

Go back to CloudFront page and open the distribuition we created.

Go to Behaviors tab and select the one is there, and click to Edit.

Activate CloudFront cache

After doing some tests to ensure that everything is ok we can activate the cache. To do it go to CloudFront page and enter to the distribution we created. Go to the behaviors tab and edit the unique item, then change Cache Policy Name to Managed-CachingOptimized.

Remember to invalidate the cache after uploading new files to S3 after having the cache activated.

Resources