How to host a static website on the cheap
Static site generation can unlock some of the power of server side rendering but can be hosted very cheaply.
When building our company website, we had a few primary goals:
- High performance
- Easy to update
- Low cost
With those goals in mind, static site generation was a very good solution. Fortunately, due to the skill of our staff, many of the usual downsides of static site generation, such as the lack of a built-in wyswig content editor, were mitigated or eliminated all together. The next step was to pick a generation tool.
After evaluating a few different static site generation tools, we chose 11ty. It's simple to get started, open source, mature, and well maintained. The documentation isn't perfect, but we were able to work past that. One of the nice things about it is that it supports multiple templating languages. We went with the default templating language, which is Liquid to build the templates for the various pages and Markdown for the content. As of this writing, our site graph is as follows:
As you can see, we took advantage of the layout chaining feature to build up a stack of layouts that allow us the flexibility to create a variety of pages, which is a pretty standard practice these days. The difference here is that instead of combining these templates with the content when a user views the site (or when the cache is warmed up), the work is done before the site is uploaded to the host. We can simply serve static html and css content and the users browser has very little work to do.
Running the generation tool can be done from the command line after installing and it is very fast; less than half a second for this site.
One of our secondary goals was to have pretty url's, which is good for SEO and so is a very typical practice. Most, if not all, hosts support automatic resoluton of index.html so 11ty takes advantage of that by automatically creating a folder for each page and then saving the content as index.html. For example, the tool auotmically creates blog/how-to-host-a-static-website-on-the-cheap/index.html for this blog post.
Fortunately, there was no need for us to reinvent the wheel here as someone had already figured out how to power a serverless contact form in a secure way. The nice thing about this solution is that all submissions end up in a Google Sheet as well as your inbox, which opens up some interesting possibilities regarding data analysis and automation.
Hosting for Pennies
Since the end result is static html and css, hosting can be had for very cheap or even free. For example, it is possible to host a static website for free on GitHub and there are many other hosts that offer it for free or very cheaply. We chose to use the static hosting feature of the Azure storage account as we already had resources hosted in Azure and it is extremely cost effective at less than a dollar a month.
To achieve our final primary goal of easy to update, we wanted to be able to deploy the site in an automated way. The code for the site is stored in a private git repository hosted by Bitbucket and they have an integrated CI tool called Pipelines. The gist of the feature is that you can do things like testing, building, and deploying using Docker containers. They provide some standard containers, but we needed a container that would allow us to build the site using 11ty then deploy it to an Azure storage account using the Azur CLI.
To get the container that we were looking for, we started with the mcr.microsoft.com/azure-cli:latest image, then added git, npm, and p7zip, then used npm to install 11ty. Finally, we then created a step in our bitbucket-pipelines.yml file to run the eleventy command to generate the site, followed by a shell script that we wrote to compress the html and other static content files, upload them to our Azure storage account, and then update their metadata to indicate their content type and encoding.
The pipeline runs anytime we push to the master branch, so to add a new blog post, we make a new branch, write the markdown file and add the supporting images. Once the content has been reviewed, the branch is merged into master and pushed and Bitbucket handles the rest. The deployment isn't as fast as we would like, but it typically only takes 2-3 minutes to update the live site.