Static Website with HTTPS

The Ultimate guide to gettin'er done

Let's Begin

Secure Static Website, Hosted on S3,
Served by Cloudfront
oh my...

Whether you use Jekyll, Hugo, Metalsmith, or you just create your own static html files, hosting and SSL can be a bit of a pain. While there are disadvantages to using a static website, mainly contact forms, comments, social media icons, and all those fancy Wordpress plugins that make life so easy. Some of you may know there are a lot of benefits to using a static website, mainly speed, speed speed!

I've Googled to the end of the internet and back to find a definitive guide to getting a static website up on S3, all the content served by Cloudfront and have it use https://.

Well ... I've managed to somehow piece the information together from roughly seven hundred and fifty two articles that I've gone through :P

This is quite literally the Ultimate Guide - and it's working 100%. Proof is in the pudding, so check out my demo - fencepencil.design.

Better yet, it's the most cost-effective way to do it. Enough already, let's go!

Step 1:

S3 Bucket Configuration Create an S3 Bucket (or two)

Head on over to your AWS S3 login page, and choose "+ Create bucket".

Choose a bucket name that is unique across all of S3. Yes, that means the entire planet of S3 users.

Amazon S3 creates bucket in a region you specify. You can choose any AWS region that is geographically close to you to optimize latency, minimize costs, or address regulatory requirements.

For this article, all examples will be using 'fencepencil.design'. This will be used as my bucket name, my url and everything in-between. Feel free to use your own domain, since somebody else probably (hopefully) doesn't have a bucket named "yourdomain.com".

You may be wondering why I mentioned "(or two)" up top. Let's touch on that topic for a second ...

If SEO is something you see value in, then you're going to need to setup 2 buckets, one for the non-www version and one for the www version of your website. The reason being, Google (and other search engines) is going to think those are two different websites, unless you setup a redirect - which we'll get to.

For now, just create another bucket and name it www.fencepencil.design (for this example).

Note: I am choosing the NON-www version to be my primary domain. You can do what you want, but for those of you whom are following along, I didn't want there to be any confusion :)

Public Access Setup

In order for CloudFront to be able to read from the S3 bucket and serve all those https requests from around the globe, we need to make your primary bucket publically accessible.

Click on the title of your bucket and go to "Permissions" and then click on "Bucket policy".

Copy and paste the code below into the policy editor window, replacing "fencepencil.design" with your primary bucket name, and then choose "Save".

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::fencepencil.design/*"
        }
    ]
}
Static Website Setup

Now is the time to give this fancy little bucket of yours the ability to host a website.

To the left of "Permissions", click on the tab labeled "Properties". You will then want to click on the "static website hosting" box.

From here, let's make note of the "Endpoint" address, which is where we will test things before moving on to CloudFront. Just copy/paste into a text editor, like Sublime Text.

Once done, choose the first option, "Use this bucket to host a website". For the index document, you can enter "index.html" if you'd like. This will be the home page of your static site. An optional error document is there as well, but for now just leave it all as-is and choose "Save".

The bucket will now have a little purple checkmark, letting you know static hosting has been enabled.

Let's Test

If you have already created your home page locally, you can upload it to your S3 bucket in the root folder for testing purposes.

To test if it's working, paste the content you copied from your text editor into a web browser. If your site loads up, then we're good to move on to the next section.

For my example,
http://fencepencil.design.s3-website-us-west-1.amazonaws.com loads the same page as
https://fencepencil.design.

If your website isn't showing up, contact us for assistance, and we can try and determine what went wrong.

Step 2:

Cloudfront Distribution Create a Distribution

Head on over to CloudFront, using the services menu up-top or you can return to the search to find it.

Pro Tip: There is a small thumbtack icon up top, and if you click that, you can choose and add frequently used applications for quick access.

Now let's choose "Create Distribution" and then choose "Web" as the delivery method.

For the "Origin Domain Name" copy and paste, once-again your "Endpoint" URL from your S3 bucket.

Leave the "Viewer Protocol Policy" at "Redirect HTTP to HTTPS".

Under "Object Caching", select "Customize" and set the Minimun TTL to 360 (we'll come back to this later).

Under "Altername Domain Names (CNAMEs)" type in your root URL, for this example "fencepencil.design".

Leave the default SSL Certificate chosen for now (we'll come back to this, as well).

Everything else can be left at their defaults.

Step 3:

Route 53 Configuration DNS Settings / Hosted Zones

Head over to your Route 53 Configuration Section, choose "Hosted zones" in the left tab, and then choose "Create Hosted Zone".

A menu will appear from the right, where you can type your root domain name in the "Domain Name" section. Then just click "Create" at the bottom.

There will be a total of 5 (4 NS and 1 SOA) DNS records created by default after the zone has been created. You can safely leave them where they are.

If you'd like to create and use your own DNS Servers, check out my post on White Labeling AWS Name Servers. Skip the first section of the article, because we've just created your hosted zone.

If you're satisfied with the default name servers, we can move on ... (but we'll revisit)

Step 4:

SSL Certificate Setup Incoming Email

You may be wondering why we are setting up incoming email. It'll all make sense soon, I promise.

First thing's first, go to the AWS Simple Email Service (SES). Make sure you are using the US East or US West Region (top left).

Select "Domains" on the left sidebar and then choose "Verify a New Domain" up above.

Type in your root domain and check the box labeled "Generate DKIM Settings", then click "Verify This Domain". DKIM is a method to privide proof for emails being sent, originating from your domain. In the next section you'll see the added DNS records required for this to work.

If you would like to use Route53 as your DNS solution, you can just make note of what's happening and click "Use Route 53" at the bottom. If you are using another DNS provider, you'll need to copy and paste all the DNS records manually into your zone editor.

Make sure you select the box to create the MX record. Warning - This will replace all existing MX records for your domain. Proceed with caution. Lastly, choose "Create Record Sets".

Setup a Rule Set

In order to receive incoming mail, we'll need to tell Amazon what to do with it.

Down near the bottom of the left tab list, there is a "Rule Sets", under "Email Recieving". Click this, and then choose "Create a Rule Set".

Give it any name you'd like, I am using "recieve_fencepencil_design" for mine. Then choose "Create a Rule Set".

Click the title of the newly created rule, and follow these instructions -

-Create Rule
-Add administrator@fencepencil.design for example. Use administrator@yourdomain.com
-Choose "Add Recipient", then click "Next Step" at the bottom
-Add Action and choose S3
-Choose your primary S3 bucket, and click "Next Step"
-Name your rule and click "Next Step"
-Click "Create Rule"

You should now have something that looks similar to this ...

Back to Bucket Policy

I told you we'd return to the bucket policy. Head there now; if you forgot it's under your S3 bucket, Permissions>Bucket Policy.

We now need to append the information below. Note, you'll need to replace the bucket name and the AWS Account ID with your own. Account ID can be found by clicking on your name at the top right, then choosing the first option " My Account".

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::fencepencil.design/*"
        },
        {
            "Sid": "AllowSESPuts",
            "Effect": "Allow",
            "Principal": {
                "Service": "ses.amazonaws.com"
            },
        }
    ]
}

Before we get ahead of ourselves, you're gonna notice an error when trying to apply the bucket policy, or simply don't want to count brackets. I've created a policy which allows both public access to the bucket and allows SES to send email to it, making it easy ...

Just replace everything in the bucket editor with this - then Save

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::fencepencil.design/*"
        },
        {
            "Sid": "AllowSESPuts",
            "Effect": "Allow",
            "Principal": {
                "Service": "ses.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::fencepencil.design/*",
            "Condition": {
                "StringEquals": {
                    "aws:Referer": "AWSACCOUNTID"
                }
            }
        }
    ]
}
Verify A New Email Address

Let's head back to SES and choose "Email Addresses" on the top left. We'll need to "Verify a New Email Address" located above.

Create the "administrator" account at your domain, for example administrator@fencepencil.design. Then click "Verify This Email Address".

If you head back to your S3 bucket, you'll notice a new file, with a cryptic title. This is the verification email. Click on it, download it and follow the instructions to verify.

Note: This could take a while ...

SSL Certificate Setup

Here comes the hard part - just kidding, stay with me it's almost over :P

Go to AWS Certificate Manager and choose "Request a Certificate". Note: You can only use "US East" region for this.

Add just your root domain name here. DO NOT use a wildcard, such as *.yourdomain.com, it WILL NOT WORK if you do.

Click "Review and request".

An email will be sent to you, where you will approve the request, then you will get a success message, letting you know the process is complete.

You will now be able to refresh the screen for your certificate and the Status will display "Issued" in green.

Back to CloudFront

You will now need to point your CloudFront distribution at the new certificate.

Head over to CloudFront, highlight and copy the "Domain Name" section to your clipboard (something like dkhshgrpdjr52.cloudfront.net).

Click on the "ID" to edit the distribution. Now click "Edit".

In the SSL Ceritificate section, choose the "Custom SSL Certificate" and then dropdown to the certificate we created.

Click on "Yes, Edit" at the bottom. Note: This might take 15 minutes or more to kick in.

One Last Thing

Head back to Route 53 for a second. You'll need to add an A Record for CloudFront.

Click on "Hosted Zones" and then choose your domain name.

Click "Create Record Set" and then to the right, choose Alias, and then add what you've copied to your clipboard to "Alias Target", or you can choose from the dropdown - but make sure to choose the CloudFront distribution and not the S3 bucket <-- VERY IMPORTANT.

... And BOOM - We're Done!