Today, I finally got around to migrating my website to use HTTPS and SSL - something that will go under-the-hood to nearly everyone, but is becoming more and more important to do as a foundational internet thing.
Here’s a blurb from Namecheap in response to the question “Do I need an SSL certificate?”
We’ll just say it: yes. Your website needs any SSL certificate If you’re asking for any personal information. But that’s not all there is to it. Search engines are cracking down on perceived ‘non-secure’ websites. Any websites without the SSL certificate will remain http while those with encryption will show https in users’ browsers. Chrome, Firefox and other browsers have began issuing warnings that non-https sites are insecure. Additionally, Google recently announced SSL is a ranking signal, so unless you have SSL your site will be harder to find, impacting on your traffic and revenue.
While my site doesn’t handle any user logins, transactions, or other actions users might need to keep protected, a desire to follow best engineering practices has finally outweighed my reticence of making structural changes to the site (you never know what will unexpectedly take down the whole thing!)
Getting this Working in AWS
My existing website is a static website built by Hugo and deployed on AWS S3 - a terrific solution for cheap, serverless hosting. However, AWS S3 hosting currently does not support SSL certificates, and thereby HTTPS connections. Because of this, we need to plop one more bit of computing on top of our stack - an AWS CloudFront distribution.
CloudFront is Amazon’s content delivery network (CDN) offering, which allows internet content to be served more quickly to end users by optimizing the distribution of data across many data centers around the world. CloudFront also allows users to secure their content with SSL certificates - exactly what we need to get HTTPS live for the site.
It’s not super hard to get a CloudFront distribution up and running - there are a ton of good guides - so just wanted to share some quick notes on the setup below:
Create an SSL Certificate to Use
- Create a certificate covering both domains (
conormclaughlin.net
andwww.conormclaughlin.net
) - Must be in same region as S3 bucket and CloudFront distribution
Set up a Cloudfront Distribution
- Source the distribution from the S3 bucket containing the website
- Configure the distribution
CNAMES
to cover the website and aliases- I set
conormclaughlin.net
andwww.conormclaughlin.net
- I set
- Configure the Viewer Protocol Policy to
Redirect HTTP to HTTPS
Route53
- Point DNS
A Records
for the domains (conormclaughlin.net
andwww.conormclaughlin.net
) to the CloudFront Distribution
Issue - The Site is Now Partly Available, but Broken
At this point, I thought I would be done! SSL cert active, connections via HTTPS, etc. However, you can see in the screenshot below that the site is clearly not loading properly!
Note that in addition to the funky style sheets on the primary page, I also was not able to navigate to other links on the page - getting an accessdeniedaccess
error message from CloudFront each time.
Two Critical Fixes
Hugo Setup
We need to modify the baseURL
field in the config.toml
file so that our static site sets URL paths in a way that is generalized from the type of HTTP/S service being used.
baseURL = "http://conormclaughlin.net/"
Remove the protocol prefix to match the following, to support HTTP/HTTPS redirects.
baseURL = "//conormclaughlin.net/"
CloudFront Object Redirects
Most importantly, we need to fix a huge issue with CloudFront’s default behavior: it does not handle URLs of directories or subpages well.
Essentially, Cloudfront does not route do any work to reconcile URL paths to the target HTML files they point at:
- On my site, that means that loading
https://conormclaughlin.net/categories/
will result in anaccessdeniedaccess
error message - While loading
https://conormclaughlin.net/categories/index.html
works perfectly
Fortunately there is a pretty clear fix to this issue! Here’s a really good description of exactly what needs to be implemented:
Create and Deploy CloudFront Function
Fortunately for us, we can add a small function to CloudFront which can help us dynamically re-write the URL requests so that they reconcile to the appropriate index.html
files in each path.
function handler(event) {
var request = event.request;
var uri = request.uri;
// Check whether the URI is missing a file name.
if (uri.endsWith('/')) {
request.uri += 'index.html';
}
// Check whether the URI is missing a file extension.
else if (!uri.includes('.')) {
request.uri += '/index.html';
}
return request;
}
Modify CloudFront Distribution Behavior
Once the function is set up, we just need to tweak our CloudFront distribution to add a Viewer Request function, so that all views will trigger our “redirect_to_index_html” function.
Now everything should load perfectly on the deployed version of your site!