How this blog is made

📅 2021-08-17🔃 2024-10-21⏳ 9 min read

A brief overview of how this blog works under the hood.

TL;DR:

🔗Prehistory / Why?

It all started when I was writing a travel blog (in Russian). After some time, it evolved from just a stream of photos to more deep and thoughtful content, which required some thought put in it as well as editing, planning, drafts and formatting. The natural way to keep these drafts was in Markdown, and generating a static website was in a stone’s throw from here.

Also, I was thinking about a place to dump my developer’s notes. All in all, I started looking into static site generators and decided to go with…

🔗Zola

Unlike Hugo , Zola is much younger, and thus its community is much smaller. There are no myriads of fancy pre-made themes that look awesome. But for me, this turned out to be a perfect match.

I started with Hugo, but quickly got overwhelmed by its complexity. I picked up a good-looking theme and tried to hack on it, but OMFG that was tough! Lots of JavaScript everywhere, weird templates, TONS of CSS… It was unbearable to change anything: things just kept falling apart. At this point, I realized that the only possibility to make things look the way I wanted them was to create a theme from scratch.

Looking around, I found Zola and decided to try it (yeah, because of Rust). And it was so much more sensible! I started hacking on one of the default themes but quickly rewrote it all from scratch.

The basic idea is simple:

  • You write your posts in Markdown (e.g. this page looks like this)

  • You have templates that explain Zola how to build a web page from it:

    • index.html - the front page. I just symlinked it to section.html, since they are the same
    • section.html - a template for a page with post list
    • page.html - a template for a page with a post itself
  • The template language (Terra) is very similar to Jinja2, which should be familiar to all Ansible users

  • Templates can extend other pages, e.g. I use a base.html template that contains header and other common stuff

  • Sass is supported out-of-the-box!

  • To extend Markdown syntax, you can use shortcodes. Shortcode is also a template that can be inserted from Markdown, e.g. templates/shortcodes/hint.html:

    <span
      class="has-tooltip-arrow {% if hint | length > 20 %} has-tooltip-multiline {% endif %}"
      data-tooltip="{{ hint }}">
      {{ text }}
    </span>
    

    will allow you to create tooltips like this :

    {{ hint(text="like this", hint="hint text goes here") }}
    

    How awesome is that? I use shortcodes to insert:

    • Google Maps iframes
    • Open Street Maps iframes
    • YouTube iframes
    • Images and videos with nice-looking comments
    • Katex formulas

🔗Kroki

I like keeping diagrams in plain text format. It makes them easy to edit, read and share. It also improves collaboration, since you can now make readable Pull/Merge Requests.

A good tool for such task is PlantUML. It even provides an API to render images. However, you need to send your diagram in GET request, using special encoding, which Zola doesn’t support. POST requests are implemented, but not enabled on the public server.

Luckily, there is Kroki! It wraps a lot of tools under a unified API: you just send POST requests with your diagram data and get SVG or PNG back. We only need to write a shortcode:

{% set postdata = load_data(
    url="https://kroki.io/plantuml/svg",
    format="plain", method="POST",
    content_type="text/plain",
    body=body,
    required=true
	)
%}
<figure class="image">
  {{ postdata | safe }} {% if comment %}
  <figcaption class="comment">
    <em>{{ comment | markdown | safe }}</em>
  </figcaption>
  {% endif %}
</figure>

So now this section in Markdown

{% plantuml(comment="simple diagram") %}

participant Zola
participant Kroki

Zola -> Kroki: POST /plantuml/svg\nContent-type: text/plain\n<diagram_data>
activate Zola
Kroki -> Zola: SVG image
deactivate Zola
Zola -> Zola: embed SVG into HTML

{% end %}

… renders into this:

ZolaZolaKrokiKrokiPOST /plantuml/svgContent-type: text/plain<diagram_data>SVG imageembed SVG into HTML

simple diagram

The rendering happens only once - during the site generation step. A diagram then exists as SVG image embedded right into HTML. A cool feature with such approach is that users can copy text from diagram labels, but a downside is that you can’t just download an image. However, you can extract SVG code from the DOM and put it into a file.

🔗Bulma

It’s hard to create a good-looking site with plain HTML nowadays. I use Bulma as my CSS framework, and I am mostly happy with it:

  • No JavaScript required
  • Modularity, meaning smaller asset size
  • Sane configuration

Downsides:

  • Has some rough edges, when you need to hack some styles with custom overrides. Not many, but still.
  • Isn’t developed very actively. But maybe that’s an advantage in the modern world, who knows? :)

The whole Bulma repo is added as a git submodule to the blog. Then from sass/site.scss I can import the required components, and Zola will compile them into a single CSS file.

The result is pretty awesome: I maintain only ~250 LOC SCSS stylesheet, most of which is a custom table of content implementation . This file is rendered into a ~200KB CSS file, which is a bit too much, but not drastically.

🔗GitLab

I use Gitlab as a hosting service for the code, because it’s the only non-GitHub option available in Cloudflare Pages. The CI setup is pretty straightforward:

  1. Install Zola
  2. Render the blog
  3. Copy it to the /public folder

The artifacts are not actually used, since Cloudflare Pages run their own pipelines on every push. But it’s nice to have a historical backups, I guess.

🔗Cloudflare Pages

CloudFlare is nice, because it’s EVERYWHERE, which means the best experience for the end user. It also supports Zola, though it’s not documented anymore for some reason 🙂

Also it gives some analytics, even though it’s very highlevel (for the best).

Cloudflare_analytics

🔗Namecheap

As the name suggests, it’s a cheap domain registrar. That’s it.

I decided to go with d .net domain, because I liked the idea of having a network of my own. There are just 2 services on it, but I plan to expand it in the future.

🔗Hacks

One last problem is that by the web standards, any website should have a www. resource, but GitLab doesn’t provide it. The solution is to host a web server somewhere that will do just one thing: redirect www.your-blog.com to your-blog.com. Not having this resolution will make your site even less favorable by search engines, so it’s a good idea to have it.

Once you have a web server, you could add a www A-record to a DNS service that will point to that web server. But where to find it?

Luckily, I was already running a server for my Telegram Bot (the post about it is coming soon!), so all I had to do is to change the Caddy’s configuration file a bit to add the redirect.

The server runs on Oracle Cloud, which gives you two VPSes for free. Take a look at my terraform scripts, which create these resources.

🔗JavaScript 🙅

You might have noticed that I try to avoid JavaScript as hard as I can. JS is a cool language with lots of great features, but using it on a simple static website seems like an overkill to me. I advocate for using it when it really makes sense: dynamic applications with intensive user interactions. My blog is definitely not in that category 🙂

Unfortunately, nowadays, JS sticks out of everywhere, even CSS frameworks tend to depend on it, which is bizarre in my opinion. You still need to have JS enabled to view the blog properly, since iframes use it a lot (e.g. Google Maps, YouTube), but it is not required for the basic functionality.

This also means that I have no trackers and I don’t know how popular this blog is, which posts are interesting and which need improvement. However, I consider this a good thing. I (imagine that I) write content mostly for myself and a few people that I’m familiar with. This takes a lot of pressure off, so I can relax and not think about views and being 100% accurate all the time.

🔗Conclusion

Overall, I’m pretty happy with the setup right now. The blog is lightweight enough to my taste, easy to maintain and hack on. It also costs absolutely nothing.

The editing process is enjoyable: markdown allows me to focus on writing and not spend too much time on technicalities. Once the post is pushed and draft is set to false in a preface, the job is done.

🔗Services used in the past (left for historical reasons)

🔗Freenom

Freenom is a (free) domain registrar, which serves .tk, .ml, .ga, .cf and .gq zones. For free, you can get a domain only for a year, and then you are required not forget to renew it. The other downside is that there are plenty of scam sites in these zones, so search engines do not even try to index anything there.

You won’t find my blog on Google because of that :)

The other problem is that it is not quite stable: even the front page doesn’t respond sometimes. Also, one of my domains got deregistered for no reason, and I can’t get it back as it entered some weird state and disappeared from their system completely a few years ago 🤷

If you are willing to live with these handicaps, welcome!

Update: The ml domain was taken back from FreeNom by the government of Mali. I should have been able to still renew it, but FreeNom didn’t allow me to do so for unknown reasons. Welp, I’m on .net now.