Skip to content

Fresh Start: Modern, Low-Cost Infrastructure

Leveraging modern public cloud infrastructure to host a secure and scalable solution doesn't have to be expensive.

Andrew Moore Dec 26, 2021
Information

This article is the second of a multi-part series on the redesign and reengineering of this website:

In the previous post, I went over the reasons why I felt the need to build a new website from scratch, and the requirements I had written down for the new solution. Notably:

  • Hosting must be cheaper than the previous WordPress solution
  • The website must be fast and fluid to navigate, with sub-200ms response times for most pages
  • The website must be SEO-friendly
  • The authoring experience must use Markdown or a Markdown variant
  • Maintenance/upkeep must be easy
  • Deployment of code and content must be possible using CI/CD pipelines

Those objectives were the key factors in the design process that led to the architecture I ended up settling on. The first decision was perhaps the most important one…

Going Static

As I stated previously, my old website was built on top of WordPress. It provided some niceties like a WYSIWYG editor experience, and a rather complete administrative interface. I personally rarely used them. The reality is that most of my articles back then were written in a Markdown editor, and then adapted to fit within the theme I was using at the time. Essentially, I was renting a server to run a WordPress installation, had to secure it properly, maintain it through WP updates; and I wasn’t even using it.

Back when I launched my original site in 2013, static site generation was still a hassle. Projects like Jekyll did exist, but didn’t provide any features beyond generating pages from template files.

This all changed a few years later when Gatsby released their first stable release. From one generator, you could query data from any source (filesystem or otherwise); transform, and optimize images on the fly at build time; and create SEO-friendly static pages tht can be rehydrated with React components at runtime. After using it professionally on a few projects, I quickly realized that it was a perfect fit: I could have the Markdown editing experience I wanted; and generate a fast, SEO-friendly website that’s cheap to host.

Astro Rewrite

In July 2023, this website was rebuilt using Astro and is no longer using Gatsby. You can read more about this transition in New Foundations: Rebuilding with Astro.

The infrastructure mentioned in this article however was unchanged, as Static Site Generation (SSG) is still used to build the website.

There’s one feature of the site, however, that did require a backend to work…

Serverless Backend

In order to simplify the process of contacting me and to reduce the amount of email spam I received, I needed to have a contact form on specific pages. To have a contact form, you obviously need a backend. Looking at the traditional options:

The first option was to pay monthly for a provider that offers Forms as a Service. I ruled that one out fairly quickly as I had no intention of having people’s information transiting through a third-party I didn’t trust.

The second option was to abdicate and go back to a more traditional hosting scenario where I paid for infrastructure to serve both dynamic and static requests. Contact forms are used very infrequently on a site like mine. Paying for server infrastructure that would sit idle for most of the time and that would require regular maintenance didn’t seem like the best investment.

However, the scale of public cloud offerings allows for a third option: serverless compute. Since the use of a contact form is fairly infrequent, having on-demand compute resources when needed was the perfect solution to my specific use case. It required very little additional consideration code-wise: all major cloud providers have first-class support for ASP.NET Core. I ended up developing a simple ASP.NET Core API application that suited my needs.

That said, do take into consideration that when using serverless compute, your application is not always ready to receive requests. Cold Starts will increase your application’s latency, and your choice runtime will have a huge impact on the cold start delays. Java and .NET do very poorly in that department. However, it is possible to improve start-up times for those languages, with GraalVM and NativeAOT respectively.

Final Architecture

AWS Cloud Visitors Amazon S3 Bucket (Static Website) Amazon CloudFront Distribution Amazon API Gateway Endpoint AWS Lambda (Backend) Amazon Route 53 Hosted Zone ACM Certificate

Completely due to personal bias, I’ve decided to deploy everything on Amazon Web Services. AWS’s Simple Storage Service (S3) allows me to deploy a static website a very low cost, and Lambda’s support for .NET gave me a cost-effective solution for my contact form’s backend (which rarely sees any traffic).

As I wanted to automate as much as possible the deployment of my website, all the infrastructure is provisioned using Terraform. If you wish to deploy a website using this same infrastructure stack, the Terraform module I developed is available on GitLab under the MIT License.

Using my module, deploying the infrastructure required for a website without any lambda is simple. If you wish to deploy a Lambda function as well, an example is provided in the project’s README.md.

module "static_hosting" {
  # Alternatively, you may use
  # source = "git::https://gitlab.com/finewolf-projects/terraform-aws-lightweight-hosting.git?ref=v2.0.0"
  source  = "gitlab.com/finewolf-projects/terraform-aws-lightweight-hosting/aws"
  version = "2.0.0"

  domains  = ["example.org", "www.example.org"]
  zone_ids = ["Z00000000000000000000", "Z00000000000000000000"]

  index_document = "index.html"
  error_document = "404.html"
}

It really is the perfect way to host a personal website. Those usually have fairly low traffic. If you recall, in Part 1 I revealed that I used to pay US$25.00/month for a server that was hosting a WordPress instance that I was barely updating, and that was seldom receiving traffic.

Well, I can now proudly say that it now costs me less than US$1.00/month. Here’s the cost breakdown for three months:

ServiceSept 2021Oct 2021Nov 2021
Route 53US$0.53US$0.53US$0.52
CloudFrontUS$0.05US$0.04US$0.05
S31US$0.04US$0.10US$0.14
API GatewayUS$0.00US$0.00US$0.00
LambdaUS$0.00US$0.00US$0.00
Total CostUS$0.63US$0.67US$0.71

Conclusion

Leveraging public cloud infrastructure and migrating to a static site generation pipeline allowed me to host this website for a very low cost. I also get to benefit from worldwide content delivery acceleration via CloudFront, and I do not have to set aside some time to maintain and update infrastructure, since the public cloud provider manages them.

Footnotes

  1. S3 costs are increasing each month due to CloudFront’s standard logging. This is not enabled by default in the Terraform Module. ↩︎