Hosting a static website in an S3 bucket with SSL gotchas

I recently deployed a static website to AWS using S3, CloudFront, Route 53 and the AWS Certificate manager. There we a few 'gotchas' in there so I thought I'd outline by process here for others:

Certificate Manager

Firstly, I created a free AWS SSL Certificate. It's pretty straight forward, just go to the 'Certificate Manager' service in AWS then:

  1. Make sure you change regions to US East (N. Virginia) irrespective of which region you're setting anything else up in. CloudFront is 'regionless' and this is the region CloudFront uses for it's certificates.
  2. Click 'Request Certificate'
  3. Add the apex domain for the certificate (ie example.com)
  4. Add an additional domain and use a 'wild card' (ie *.example.com)
  5. Review and request, just follow the prompts and make sure you have access to one of the required email addresses so you can validate the request (which you should also do).

S3

  1. Go into S3 and create a new bucket, using your site's apex domain as the bucket name (ie example.com).
  2. Make sure it's publicly accessible.
  3. Upload your files
  4. Go to the bucket's 'Properties' and select 'Static website hosting'
  5. Select 'Use this bucket to host a website' and add an index document (usually index.html)
  6. Take note of the Endpoint URL on this screen, that's your CloudFront endpoint (not the one that auto-completes for you in CloudFront).
  7. Create an empty S3 bucket with a 'www' subdomain (ie www.example.com).
  8. This bucket should be empty, however under Properties > Static website hosting you should select 'Redirect requests' and point it to the first bucket you made with the 'Protocol' set to 'https'.
  9. For bonus points, select all the files you just uploaded to the first S3 bucket, and click 'Add meta data' in the 'more' dropdown. Select
    'Cache-Control' as a key and add a value of max-age=7776000 (90 days or whatever value you want)

Of course you can do this the other way around with the 'www' bucket being the main one and the apex domain one redirecting to it.

CloudFront

Now over to CloudFront:

  1. Click 'Create Distribution'
  2. Select 'Get Started' under 'Web'
  3. Set 'Origin Name' to the URL you made note of earlier for your S3 bucket.
  4. Set 'Viewer Protocol Policy' to 'Redirect HTTP to HTTPS'
  5. Under 'distribution settings' add 'Alternate Domain Names' with a comma separated list of your two domain names (ie example.com,www.example.com)
  6. Set the 'Default Root Object' to index.html
  7. Finally, enable Gzip by going to 'behaviours' for your distribution and make sure that 'Compress Objects Automatically' is set to 'yes'

Every other setting can be left as the default.

It can take a good 20 mins to half an hour for CloudFront instances to become available. When it does though, your CloudFront domain will work (ie d2srergsg4h3ts.cloudfront.net)

Route 53

Last step is your DNS configuration. You can just make a CName entry and point it to your CloudFront domain. However DNS will not allow you to make a CName entry for an Apex record. Route 53 will however.

  1. Go into Route53 and click 'hosted zones' then 'Create Hosted Zone'
  2. Enter URL and hit 'create'.
  3. Go into your hosted zone and click 'Create Record Set'.
  4. Leave 'Name' blank and 'Type' 'A - IP Address', then 'Alias' should be 'Yes'
  5. In 'Alias Target' your CloudFront distribution should be available in the alias dropdown list. Select 'Create'.
  6. Create another record set, but this time the 'Name' should be 'www', the 'Alias' should be 'yes' and the Alias target should be the record your just created in step 5 under the heading 'Records set in this hosting zone'.
  7. Click create.

Now you just need to make the appropriate adjustments to you Nameservers so they point to the Route53 Nameservers and you've got a very cheaply hosted website that is super fast and secure.

Big thanks to this article which got me 90% of the way.