Using SSL with S3 + CloudFront

At XOOR we find ourselves building static websites for customers very frequently. It doesn’t matter how we implement this websites, they can be either Angular 2, React or just plain old HTML+CSS+JS. The important thing they all have in common, is that these websites are fully static. They might have a contact form, but we usually build these using an Amazon Lambda (that story is for another post).

Hosting a static website on a web server it’s quite expensive if you think you’re just serving static files. Using a static file server instead of a web server is a good ‘n cheap alternative and that’s what we’ll cover in this post.

Let’s do a quick summary of the steps we’ll follow to achieve the final goal: have a static website hosted on Amazon S3, distribute the website on multiple locations using Amazon CloudFront, serve the website securely through HTTPS and finally use a custom domain name to access it:

  1. Create and configure the S3 bucket
  2. Create an SSL certificate
  3. Create and configure CloudFront
  4. Configure Route53 to use our custom domain name
  5. Done!

To make things short I’ll assume you already have an AWS account ready to be used and have a little (tiny little) understanding of what the services we’re going to use are.

Create and configure the S3 buckets

The first task we have is to create the bucket where our static website will be residing. For the purpose of this post, I’ll use domain.com as my custom domain. I assume you already have a domain name of your own that you’ll use to load your static website.

The bucket we’ll create must have the same name as our naked custom domain, this is our domain without the www prefix. So go ahead, open the S3 console, click create bucket and use your naked domain name as the bucket name. This is the bucket that will host our website. So once you created it you can upload all your website files to it.

Once you’ve done that, go to the Properties tab. There you’ll find a box that says “Static website hosting”. That sounds quite like what we wanna do right? Go ahead and click that. The box will expand and will allow you to mark the option “Use this bucket to host a website” as selected. Then tell S3 which is your index document (usually index.html) and hit Save.

The bucket is almost ready. The last thing we need to do is create a bucket policy so that all files are accessible by anybody in the world. Head over to the Permissions tab and click the “Bucket Policy” button. In the policy editable area paste the following and replace domain.com with your bucket name.

{
    "Version": "2012-10-17",
    "Id": "PublicBucketPolicy",
    "Statement": [
        {
            "Sid": "Stmt1482880670019",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::domain.com/*"
        }
    ]
}

Basically what we say is “allow anybody to perform a GetObject operation on any of the files on this bucket”. That’s it, we already have our website hosted on Amazon S3. If you go back to the Properties tab and click again the Static website hosting box, you’ll see that it shows you the endpoint where you can reach the website. The link looks like this: http://domain.com.s3-website-us-west-2.amazonaws.com. If you click it you should see your website load. Anyways there’s still some work to do to distribute our website across multiple locations for faster loading around the world. Also it would be better to use your domain name instead of that loooong S3 URL to load your website.

Create an SSL Certificate

The next step is to create an SSL certificate so that we can secure all the communication to and from our website. This is useful in case you have a contact form or any other user input in your website. Using SSL means that all data coming and leaving our website is encrypted.

As you imagine Amazon has a service for this and it’s called “Certificate Manager”. Go to the Services menu and head over to the Certificate Manager to create our first certificate.

Please make sure you’re on the US East N. Virginia region as this is the only region supported by CloudFront for certificates. Once there click the “Get Started” button and follow the instructions. At the end AWS will tell you that you have to approve the certificate by clicking a button on an email sent to a series of emails within your custom domain. If your domain is domain.com you must have access to one of the following email addresses:

hostmaster@xoor.io
webmaster@xoor.io
postmaster@xoor.io
admin@xoor.io
administrator@xoor.io

Once you click the Approve button on the link that AWS sent you, you’re done. Your SSL certificate is ready to be used 🙂

Create and configure a CloudFront distribution

We’re getting close! Next step is to configure the CloudFront distribution. If at this point you’re asking yourself why do this? This concise StackOverflow answer will give you a reason to come back happier than ever to setup your CloudFront distribution!

In your AWS management console go to the Services list and select “CloudFront”. As always click the “Get Started” button (the one to create a Web distribution, not the RTMP one).

If I don’t mention a specific field in the process is because you should leave it as it is. Now, this is what we need to fill in:

In Origin domain name choose the S3 bucket we created to host our website files. This tells CloudFront from where it should pick the content.

In Viewer protocol policy select “Redirect HTTP to HTTPS”. This way we force our users to go always to the HTTPS version of our website.

Scroll down to the SSL Certificate field and choose the “Custom SSL Certificate” option. This will enable the dropdown below where you must choose the certificate we created on the previous step. If you don’t see your certificate listed there, my best guess is that you didn’t read the part that said you must create the certificate in US N. Virginia.

Next, your Default root object has to match the same index document you selected on your S3 bucket, most likely index.html .

Done! Click Create Distribution and go grab a coffee, watch an episode of your favorite series in Netflix and come back. CloudFront has to propagate the contents of your bucket into all it’s locations, so this can take several minutes.

Once your distribution is in Deployed status, you can try using the distribution domain name and your website will load. The domain name looks something like something.cloudfront.net . The last step is to configure Route53 and tell it to point our custom domain to the cloudfront domain name so that people can access our website using https://domain.com instead of that long and ugly URI.

Configure Route53 to use our custom domain

You probably bought your domain using a service like Google Domains, GoDaddy, etc. The thing is, if you want to point it to the CloudFront distribution we just created you must handle the DNS records through Amazon’s Route53. This is not free, but it doesn’t hurt at all at $0.50 per month per hosted zone you have.

Let’s start as always, by going to the Services list and choosing Route53 to open the service console. Once there, create a new hosted zone and use your custom domain as the domain name (the naked version, don’t put the www prefix there). Hit “Create” and your hosted zone will be ready instantly.

The first thing you’ll have to do is replace the Name Servers in your name service provider (in my case GoDaddy) with the ones that Route53 gives you in the NS record set. You’ll see them on the right side panel, it looks like this:

It gives you 4 name servers. It’s not within the purpose of this post explaining how to do that, so please go to your name service provider and find out how to replace the name servers (it’s super easy, I promise).

IMPORTANT: If you had any MX records in your domain name server provider, you’ll have to migrate them to Route53 in order to keep your email coming without issues. The same applies to any other type of record you might have configured.

Once you’ve changed that, you need to create some record sets to tell Route53 to point the domain to the CloudFront distribution domain name. So hit the “Create record set” button and on the right side panel choose A-IPv4 Address as the type. Then select “Yes” in the Alias option and set the CloudFront URI as the Alias Target. What we’re telling Route53 here is: Redirect all request to our domain domain.com to the domain name of our CloudFront distribution. Repeat the previous step but this time creating a “quad A” (AAAA) record which points to an IPv6 address.

Now we need to tell Route53 what to do when a user types our “www” prefixed domain. So far we just configured what to do with our naked domain. The process for this is almost the same. You’ll have to create 2 more records, one A and one AAAA, but this time you’ll fill in the Name as well with the value www .

This is all we need. This changes are almost instant, so you can quickly check by pointing your browser to http://domain.com and http://www.domain.com and you should see your static website loading. If you followed all the steps, you’ll even notice that when using HTTP the request will be redirected automatically to the secure HTTPS version.

Conclusion

We finally got our static website working. As you could see it’s not a super simple process but it’s not a big deal either. Once you do this one time you’ll do it much faster for other websites. This is how we configure most of the static websites we build for our customers at XOOR, including our own website :).

Hope you got something useful from this post and do not hesitate to leave any comments or questions here. Thanks for reading!