My personal blog deployment
8 minute read
There are a lot of solutions out there for deploying blogs, from Vercel to Netlify to GitHub pages. Why would someone bother going through the effort of learning Terraform, Ansible and the basics of server administration to deploy a simple Jekyll blog with low quality content?
Because I am an engineer and I must understand how these things work.
I wanted to follow two key principles when evolving my approach to deploying this blog. These were:
- Everything was as simple as possible (confident that this was a famous quote at some point)
- To minimise dependencies on external services as much as possible
Making things simple involves using reliable, mature technology that has been used for (at least) several years and is likely not to be depreciated for a good while longer. Both in academia and in industry I’ve used tools that were “bleeding edge” and had fancy new functionality which made solving specific problems easy. However, these tools suffered from lack of support or functionality outside of a tight domain. Furthermore, the amount of time I spend working through dependency issues and undocumented bugs with my current role strongly pushes me towards working with simple tools that I can understand build myself.
Minimising dependencies on external services has a clear goal: I don’t want to build on quicksand. There is a tradeoff between using a service to reducing the time to production and the cost involved in building a bespoke solution. When it comes to supporting something I hope to have a long time in production, such as my personal blog, I want to maximise the amount of control I have over the deployment process and infrastructure. This approach also helps guarantee how much services will cost to support. I’m either paying for something that’s simple to support or use or I’ve written the automation that will solve the problem that a managed service solves for me.
First things first
How much does this all cost?
- GitHub private repos: free
- Digital ocean droplet: $6 per month
- IONOS Domain name registration: £12 per year
Total: about £70 a year.
I think I spent about 20 hours in total
developing learning about Terraform, Ansible and nginx to be able to develop some simple scripts for deploying this blog and webapps on various subdomains. Whether that’s really a cost or an investment in learning about these technologies remains to be seen.
Could this have been done cheaper? Almost certainly yes, but would it be mine?
The blog itself
The additional gems I use are:
- jekyll-paginate, a plugin to enable pagination
- jekyll-seo-tag, to add metadata to the content that I produce. One likes to think that my content might be useful for others.
- jekyll-sitemap, for generating a sitemap
- jekyll-last-modified-at, for showing when a page was last modified according to git. I often update posts content or correct spelling and it’s important to show that this process is occuring.
- rouge, for code linting
- Analytics from GoatCounter that is provided free for non commercial use. Never has looking at a zero count graph been so emotionally involving.
- Mermaid is a tool for generating diagrams from code, a few of those diagrams appear in this post! Mermaid is common across a few web based services and the syntax is portable.
- I also like being able to format maths, so MathJax was the natural option.
I then use Nginx, Lets Encrypt and a domain name purchased from Ionos and registered with Digital Ocean to serve the static content generated by Jekyll. Nginx acts as the server/reverse proxy to serve the blog at my domain and apply the right certificates that were created using Lets Encrypt, an excellent service. I used IONOS at a previous company and together with Digital Ocean provides a reliable service for making the blog widely accessible.
Getting it in the cloud
Part of my strategy (as well as to understand everything) is to reduce the number of dependencies I have on managed services. Managed services often have hidden costs/risks or functionality that could catch me out in the long run. I can avoid these by taking on the cost of implementing my own solution up-front.
I decided to choose using a Digital Ocean droplet rather than buy a domain and then use a service like GitHub pages or Netlify to handle the deployment and support. I found the Digital Ocean UI simple to use, their costs are straightforwards and there are lots of helpful tutorials to perform various tasks. I’ve professional experience with Azure, AWS and GCP now, but Digital Ocean still remains the simplest and cheapest option for me to use.
Using a service would have saved a lot of time initially but now that I’ve got the code for deploying my own website it’s not a problem I’ll have to solve again and I totally own all parts of this solution. Digital ocean goes down? Fine, just let me replace the Terraform code towards AWS/Azure/GCP etc. The redundancy I now have feels more valuable than getting something more ephemeral in the cloud even if that could have gotten me closer to my various side project goals by 20 hours.
Automating the deployment
The process for automating the deployment involved two key stages:
Terraform was the tool I used to write the process to instantiate the VPS (or Droplet) used to host my blog. I then used Ansible for automating the configuration of the server itself for building and deploying my blog.
Why bother using two different automation tools that nominally do the same thing? I was able to learn that whilst they do do the same thing they do it in different ways. As I unashamedly paraphrase from this article, it’s turns out that:
- Terraform uses declarative programming to achieve it’s vision of the world. It hides a the behind the scenes work to achieve an end goal. This is useful when a user is stating the requirement that they want one server of a specific type.
- Ansible uses imperative programming to require a specified set of steps by user dictating what needs to be achieved. In my case, a VPS with a running nginx server and a build Jekyll site.
Rightly or wrongly I found the ability to use Terraform to determine the infrastructure I needed to be quite easy to use. I toyed with the idea of running an Ansible playbook on server creation, but I ended up finding the seperation of server creation and configuration into two different processes easier to handle.
I use pass for storing the secrets I use locally for deploying and updating the blog. It’s an excellent tool and I doubt I’ll ever use a managed service for hosting my personal secrets. I could well lose my laptop, but it’s also likely that one of the many online services I might use may be hacked and we’re all back to square 1 again.
In this blog post I’ve detailed the design decisions and higher level implementation details of how I’ve created my own process for updating my personal blog. I learnt a lot about Infrastructure as Code, server configuration and the basics of static site generation. Hopefully you might have been able to get some ideas of how you might be able to solve similar problems, and if you have any questions please reach out to me.
I’ve got a few ideas for where to take this next:
- Automating the stage that points the domain to the public IP of the droplet.
- Turning this process into a service that accepts a domain name and necessary secrets then deploys a Jekyll blog.
- Extending the service above to be able to deploy two Jekyll blogs (perhaps a landing page and a documentation site) plus a node based web app. Could be useful for POCs.