The Cheapest, Simplest Personal Website

Akbar Nurlybayev
3 min readMar 9, 2020

After procrastinating for a very long time, I finally launched my family website. With so many available technology options, I’ve decided to narrow down the choices by creating the following constraints. First, the website has to be easy to maintain. I want to maximize the amount of time spent writing content and minimize the amount of time spent on hardware, software maintenance and deployment. Secondly, it has to be cheap. And by cheap, I mean cheaper than AWS Lightsail.

The rest of the post explains how I built this site. In short, here are the steps I took:

  1. Build a static website
  2. Deploy the static website on AWS S3
  3. Automate the deployment using Github Actions
  4. Add HTTPS support

Build a static website

My research narrowed down the choices to two popular static blogging solutions: Jekyll and Hugo. I chose Hugo mainly because I liked the documentation better, and it seemed that getting started was marginally more straightforward.

The actual website consists of three different Hugo sites: the root, /akbar/ and /akbar/cv/. The reason for this is because I was not able to figure out how to use different templates for different sections of the site.

/ is built using Vanilla Bootstrap.

/akbar is built using Pixyll.

/cv is built using DevResume.

Deploy the static website on AWS S3

AWS S3 is probably the most reliable service that Amazon offers. On top of that, it is incredibly cost-effective.

I followed the Setting Up a Static Website Using a Custom Domain Name Registered with Route 53 tutorial from AWS documentation. The only difference in my case is that my domain registrar is Hover.

Why not Route 53, you ask? Kay Rhodes outlined several reasons in his essay, Never register a domain name with your hosting provider, from a few years back.

Automate the deployment using Github Actions

Github relatively recently launched a cool feature called Github Actions.

I’ve followed Jake Jarvis’ action workflow with minor modification. I had to add a build step to install the Hugo on the container. Essentially my workflow.yml has something like this:

...
steps:
- uses: actions/checkout@v1
- name: Install Hugo
run: |
HUGO_DOWNLOAD=hugo_extended_${HUGO_VERSION}_Linux-64bit.tar.gz
wget https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/${HUGO_DOWNLOAD}
tar xvzf ${HUGO_DOWNLOAD} hugo
mv hugo $HOME/hugo
env:
HUGO_VERSION: 0.62.2
- name: Hugo Build
run: |
$HOME/hugo -s root/ -d `pwd`/public
$HOME/hugo -s akbar/ -d `pwd`/public/akbar
$HOME/hugo -s akbar-resume/ -d `pwd`/public/akbar/cv
...

Add HTTPS support

By this point, we probably have the cheapest hosting solution out there. However, in this day and age, to protect their users, everyone should use HTTPS even on static websites. Here are some risks that you expose your users to if you don’t: Here’s Why Your Static Website Needs HTTPS.

I briefly considered the Cloudflare because of how easy it is to configure. However, it does have one downside the traffic between CDN, and the origin is not encrypted. Cloudflare points to the S3 website endpoint, which by default, doesn’t support SSL. So AWS CloudFront it is.

There are few things involved with this:

  1. Setup CloudFront distribution
  2. Point it to S3 REST API endpoint
  3. Disable public access to the S3
  4. Deploy AWS Lambda@Edge to support default directory indexes

I followed the Ly Channa’s excellent How to host a static website with https using amazon s3 tutorial. Below are some of the things I had to do differently, perhaps because the AWS has evolved since he wrote his article.

Since I used Route 53 as DNS, I could not add CNAME record to point to the CloudFront distribution. So I had to create an A record. The relevant section of the AWS documentation is here.

If you’re creating a record for the apex domain to point to AWS resources, you can use an alias record instead of CNAME.

Removing S3 public bucket permissions was not enough. I did disable Static website hosting on the bucket.

To support default directory indexes, i.e. URL like

https://nurlybayev.family/akbar/

instead of

https://nurlybayev.family/akbar/index.html

I followed Implementing Default Directory Indexes in Amazon S3-backed Amazon CloudFront Origins Using Lambda@Edge. This tutorial is complete with the exception of the additional role that you need to set for CloudFront to be able to execute Lambda@Edge function. For that, here is the relevant section of the AWS documentation: Function Execution Role for Service Principals.

Final thoughts

So the website now has end-to-end encryption. The cost, as a result, is a bit higher than hosting an HTTP website on S3, but the risks are not worth it.

I’ve also decided against using Google Analytics and removed or disabled the relevant footers of Hugo sites. I’ll be relying on CloudFront default metrics for now.

Originally published at https://nurlybayev.family/akbar/.

--

--

Akbar Nurlybayev

Father. Husband. Software Engineering Manager at TradeRev. We are hiring! Toronto, 🇨🇦