How to host a static website with https using Amazon S3

Ali Hamza
10 min readJun 18, 2020

--

You might have your application running in Java, PHP, or Ruby but you might not want to convert and include your static content for a specific module into your application by varieties of reason. In my case, I have a sample landing page for my company’s product that has nothing to do with dynamic content which makes Amazon S3 the best place to host it to save my time.

Requirement:

  • You must have your static website ready
  • You must have an AWS account
  • Amazon services: Amazon S3, Amazon Cloudfront, Amazon Certificate Management (ACM)
  • A valid domain and DNS management access

Tip

Before you have your static website uploaded to with S3, make sure your static website works correctly. You can use the Node package http-server from NPM to run your static website to check the functionality. Now let’s go start the configuration.

Now let’s go start the configuration.

Amazon S3 setup

Go to amazon web service console here: https://aws.amazon.com/console/, then choose: Sign In to the Console button on the top right.

After successful login, click on the Services menu. Amazon has a ton of services, so you just need to enter the name in the search box to search for the service you are looking for, in our case enter S3.

Click on the S3 result to go to the S3 console screen. S3 is a storage in the cloud that works just like files and directories in our local computer, but S3 extends far beyond a storage engine.

Now click on the Create bucket Button to create a bucket for your site. A bucket is just like a root directory in our local file system. If you have more than 1 website you may have to create several buckets — one bucket for one website. I prefer to name my bucket to the domain name of the website.

In my case, I enter dev.uct.iddigital.com.au as the bucket name for my static website. Once you created the bucket you need to set permissions for it. Because it is stored in the cloud you need to control the permission. In Amazon permission can be handled in different ways, you can learn more about the permissions with IAM (Amazon Identities Management).

Click on the Permission tab and then choose the Policy generator.

The generator page shows up. Choose the following:

  • In Select Type of Policy, choose S3 Bucket Policy
  • In effect chose Allow
  • In Principal enter * ( * = anything ).
  • In Action select S3:GetObject (Files uploaded to s3 are considered as objects, thus GetObject here means allow to read files )
  • In ARN (Amazon Resource Name ) enter your bucket name. In my case dev.uct.iddigital.com.au/*. Every resource in Amazon has a unique ARN as an Identifiers for Amazon services to communicate. For S3 service, the ARN starts with arn:aws:s3:::[your_bucket_path_to_resources]. e.g: arn:aws:s3:::dev.uct.iddigital.com.au/* Click on Add Statement and then it will show a result summary of the policy.
  • If everything is ok then Click Generate Policy button and then it pops up the policy like this:

Copy the JSON generate policy then go back to the S3 permission tab and paste it in the Bucket Policy Subsection and click on the Save button.

Now click on the Properties tab on the left of the Permissions tab and then choose the Static website hosting tab.

  • Enter the root document of your website (entry point ) for example when people type https://yourdomain.com/ without the path it will run this file. In my case my root document is index.html ( I have not uploaded the file yet ) I will explain later why.
  • If you wanna handle the error document enter your HTML file. In my case, I just send it to index.html too.
  • Before you click on the button Save, don’t forget to copy the Endpoint for your website. It is the URL you will use to access your website. In my example http://dev.uct.iddigital.com.au.s3-website-ap-southeast-2.amazonaws.com/

After setting all the permission, it is time to upload your content. Go back to the bucket list and then click your previously created bucket. In my case, I click on dev.uct.iddigital.com.au. Click on the Upload button in the Overview tab to upload.

Make sure you have the index.html ( configured previously in the static website card) at the root of your bucket.

If you happen to change the bucket permission, after uploading the files the existing files/directories inside the bucket will not update the permission. you need to update permission for each file and directly manually. I usually manage permission before uploading to avoid this. In case of small size upload, I might clean up my bucket and re-upload.

Now we are done with the setup.

Testing the Website

Enter your website endpoint in the browser

Great!. Simple and easy. You have only a few steps left to complete the setup with your domain and https.

Link to your Domain and secure it with a valid https cert

I will show you how to link this with AWS DNS Management service Route 53, however, it can be any domain from any registrar with option to manage DNS.

The magic happens here is another 2 services from Amazon: Cloudfront and ACM.

  • ACM will be used to generate a valid SSL cert for your domain
  • Cloudfront will be used to serve the traffics accessed through your domain

Without any further due let’s dive in the ACM.

Generate SSL Cert for your domain

Go back again to the Services menu item on the top and type ACM

then select the result. It will bring you to cert lists or a landing page to get started.

Click on Request a certificate button

Make sure you choose US based region in my case US East (N. Virginia) us-east-1. My AWS infrastructure is based in Sydney. At the moment of writing this, Cloudfront is not possible to link to ACM generated in Sydney yet.

And then choose Request a public certificate option and next click on Request a certificate.

Next, enter your domain. for example *.yourdomain.com

yourdomain.com is the domain(e.g. https://yourdomain.com ) is not part of *.yourdomain.com subdomains(e.g. https://www.yourdomain.com is one of a subdomains) In case you want your cert to handle both the main domain and subdomain,for example, https://yourdomain.com and https://www.yourdomain.com or https://mobile.yourdomain.com you must add two entries (yourdomain.com and *.yourdomain.com. The good news is ACM validations for both of them are the same.

then click Next. To be able for Amazon to issue an SSL cert for you, you need to verify that you own the domain entered above. Choose a method of verification: (DNS validation )

then Next the rule to validate and then confirm.

then Review the rule to validate and then confirm.

Next click on Continue. ACM will show the status of validation like below

Go to your domain DNS manager and create a CNAME record. for example in my case, domain DNS is managed by Amazon Route 53:

and hit Create. Now go back to ACM console and ACM passed the validation.

If your domain registrar is GoDaddy, when you create a CNAME record, Don’t copy the .(dot) at the end of value given by ACM — …aws without the dot at the last characters. The value with the Dot means the it is an absolute value for DNS record.

If you are using AWS Route53 to manage your domain, ACM will automatically create the record for you automatically if you choose DNS validation. However, some DNS registrars have weird behavior and restriction on characters you can use in CNAME. You might choose between DNS and Email validation according to your scenario.

Create Distribution in Cloudfront

Now it is time to link the cert with S3. Go back to Services and search for Cloudfront and click on the result to go to the Cloudfront page.

Click on Create Distribution as indicated below

In the Create distribution page, enter the following:

  • Origin Domain Name: choose your bucket name from the autocomplete list. Cloudfront discovers the bucket names existing in your AWS account.
  • Origin ID: it will be auto-filled after choosing the first step. No need to change.
  • Click on Redirect HTTP to HTTPS to have just one domain avoiding duplicate content with non-http and https.

Scroll down a bit and then keep entering:

  • In Alternate Domain Names ( CNAMES ) enter your domain and subdomains name in the list line by line. these are the URLs you will use to access your website. for example product1.mydomain.com, xyz.mydomain.com
  • Choose Custom SSL and select your Certs from the list generated by ACM. Be careful here, Cloudfront might not support certs generated by ACM in your region.
  • Enter index.html in Default Root Object
  • And last enter a name in the Comment.

Now click on Create Distribution. Cloudfront will take a few minutes to do this. After finishing it your distribution will look something like this:

Find a distribution with your comment and then copy the URL value from the Domain name column.

Setting DNS to point to your website

Go to your domain DNS manager and create a CNAME point to the Cloudfront URL from the previous step.

Example for subdomain dev.uct.iddigital.com.au you add a new CNAME like this:

It might take a while for your DNS to broadcast the change. you can debug this with dig command if you are in Linux or Macosx something like this:

dig dev.uct.iddigital.com.au

Once it responds it is ready to test your website. Open your browser and type

http://dev.uct.iddigital.com.au it will redirect you to the https versions https://dev.uct.iddigital.com.au

Prevent public/direct access to S3 (optional but recommended)

Now you have Cloudfront working, you might want to make sure your contents can only be served from your domain only. To do this we need to disable direct access to S3.

Why you should to use Cloudfront over S3 URL? Cloudfront is seemlessly integrated with Amazon Web Application Firewall (WAF) that allows you to prevent malicious or unwanted traffics.

Now go to your Cloudfront distribution and click to edit.

In the distribution edit page, Select Origins and Origin Groups to go to Edit Region page

In the Edit Origin page

  • In the Restrict Bucket Access, select Yes, then option Origin Access Identity starts to appear.
  • In the Origin Access Identity, select Use an Existing Identity
  • In the Grant Read Permission on Bucket, Select Yes

Then Save. Wait for the distribution to propagate its update.

Now let’s remove public access from the S3 bucket.

Go to your AWS console and choose S3 → Your bucket → Permissions → Bucket Policy. You will see a new statement added by Cloudfront as follow

The first part of the statement is our generated policy at the beginning. Now remove the first section to remove the direct access to S3.

Click Save. Now go to your browser and past the S3 URL and then it’s shown 403 forbidden.

Conclusion

It is very easy to deploy a static website with S3 and with more advanced domain and SSL cert with the help of Amazon Cloudfront and Amazon ACM. Amazon S3 is very cheap and easy to set up without worries about the server infrastructure and after all, you win time and resource so your teams can focus more on building great things for your apps.

S3 for static content is awesome, however, if your pages involve dynamic content or analytics data S3 is not the right choice. In my use cases, I use S3 for product landing pages, Product docs, API docs, and so on.

--

--