Skip to Content

My Blogging Flow - Part 1 - Under the hood

Several people have asked me how my blog works and how it gets written, so here’s a blog post about how I blog (so meta).

Let’s start at the beginning.

The history of dmerej.info/blog #

Buying a DNS domain #

The first step was to buy a domain name. I chose gandi.net because I only heard good things about their registration service. I like the “retro” feel of the .info TLD, and the dmerej prefix is the one I use to shorten my name. Wether it’s a good thing or not, it’s too late to change it now, so there.

Getting my own machine #

I always wanted to control all aspects regarding the hosting of my blog, so I started by looking for a dedicated machine.

If you’re not familiar with the concept, having a dedicated machine means that you pay for the hardware and ssh access to a server owned by soneone else. In exchange, you get to install and configure everything by hand. If it sounds like a loosy deal to you, remember that I value control over convenience :)

Anyway, I bought a server at a company called dedibox. (For the sake of completeness, I must say I’m now hosted by the nice people at Digital Ocean).

But enough speaking about hosting services, let’s talk about blog engines!

Static or dynamic #

There are two types of blog engines: static and dynamic. It has to do with what happens when a visitor requests the article’s URL.

In a dynamic blog engine, the contents of each article is typically stored in a database, and the HTML is generated by the engine for each visitor. This means the server has to run some code for each visit.

On the other hand, a “static” engine typically generates a bunch of HTML files from sources written in a markup language (often Markdown) beforehand. Then all the server has to do is to present the correct file when a visitor wants to view a page.

Both of them have pros and cons:

  • Dynamic blog engines can handle comments, compute statistics (like view count), and so on. But because they require a database and some programming language support, they can get hard to deploy. Finding a way to do backups properly can get tricky, too.

  • Static blogs cannot handle comments or anything like that, but they are very easy to deploy: you can simply use existing web servers (like nginx or apache) directly. Also, backup is easy - you just need to backup the source files, and a git repository is more than enough.

Finding a blog engine #

I must say I spent way too much time finding the engine I would use for my blog.

My guts told me I wanted a static engine, so I started fiddling with many static blog generators. Alas, they are tons of static engines out there, and I almost gave up on finding the one I would use - there were simply too much choice.

That’s when I realized I was not tackling the problem correctly: I was worried on how to publish contents, but said content was yet to be written!

So I took a look at dynamic blog engines (less choice there), found Dotclear almost by chance, and started to write.

Finally, my articles were online and publicly readable by anyone on the world. What a joy!

Advice to my dear readers: if you want to publish something online, don’t make my mistake: make sure you have some contents before worrying about its publication.

The Dotclear period #

Configuring php for Dotclear was a bit tedious, but once it was done I must admit it was quite pleasant to use. The admin view is rich and featureful, and the editing form is ergonomic. Comments are supported out of the box, and they are easy to moderate.

But I still I had a problem: I was receiving many notifications about comments but almost all of them were spam :/

This was depressing, so I shut down the comment service and started looking for an alternative.

The Hugo period #

I went back looking for static engines, and found Hugo on the StaticGen engine comparison website.

I immediately liked it:

  • There are many beautiful themes available. (Dotclear themes are nice too, but they look a tad outmoded to me).
  • Hugo is easy to install (just one binary)
  • Its documentation is complete and easy to follow
  • I no longer had to setup php on my server. Just a few lines of nginx configuration was enough.
  • Plus it is ridiculously fast. It can build more than one hundred pages in less than one second.

To work, Hugo need a theme. A Hugo theme is made of various templates, which control how the HTML gets produced, and some static files (like CSS or images) that needs to be copied along the generated files.

Hugo does not come with a default theme, so after a few tries, I settled on blackburn.

Writing my own shortcode #

The nice thing about Hugo is that you can customize the look and feel of your blog as much as you like. I still remember fondly the day I managed to implement the “movie script look” for the short scenes I wrote in Heard and Seen at FOSDEM 2017.

Here’s how it works.

First, I have custom scene shortcode inside the layouts/shortcode directory of the theme:

<div class="scene">
<h1>
  {{ .Get "title" }}
</h1>
<p>
{{ .Inner | markdownify }}
</p>
</div>

This allows me to write things like this in the Markdown source 1:

{{〈 scene title="Resurrecting Dinosaurs" 〉}}
SPEAKER: I did *not* expect to have a win32 architecture slide here at FOSDEM
{{〈 /scene 〉}}

When Hugo sees the scene directive it will generate HTML code containing:

  • The <div> and its special scene class
  • The title inside the h1 tag
  • And the text inside the scene directive, interpreted as Markdown too:
<div class="scene">
<h1>
  Resurecting Dinosaurs
</h1>
<p>
SPEAKER: I did <em>not</em> expect to have a win32 architecture slide
here at FOSDEM.
</p>
</div>

Finally, I have a bit of CSS to render the div properly:

.scene {
  font-family: monospace;
  line-height: 1.2em;

  h1 {
    line-height: 1.5em;
    font-size: 1.2em;
    font-style: bold;
    text-align: center;
  }
}

And that’s all there is to it :)

Switching to a new theme #

After a while, I was getting tired with blackburn. Its CSS files were not easy to edit, it also had big dependencies like font-awesome or Yahoo’s Pure CSS.

So I switched to minio, which is the theme I still use today. It uses Sass instead of pure CSS, and its sources are neatly organized. Plus, it comes with a nicely configured toolchain, which allows to get feedback on changes made to the theme instantly.

Source organization #

If you take a look at the sources of the blog you will find posts are numbered chronologically:

0001-hello-world.md
0002-i-use-vim-and-so-should-you.md
0003-finding-a-good-project-name.md
...

I like this scheme because posts are naturally sorted by time, and because I know immediately know how much articles I’ve written. (More than 100 today!)

Since I don’t really want the internal number to be seen outside, all the articles have a slug in the “front matter”:

# In 0042-foo.md
---
slug: "foo"
date: "2016-03-31T13:00:19+00:00"
draft: false
title: "..."
---

This means the 0042-foo.md file will get written as foo/index.html.

I also told nginx that blog/post/foo correspond to blog/post/foo/index.html:

location /blog {
  try_files $uri $uri/index.html =404;
}

This is called pretty URLs in Hugo’s documentation.

Comments #

The last piece of the puzzle is the comments system.

I use isso, a self-hosted comment service.

First, I’ve patched the Hugo template to add a tiny bit of JavaScript at the bottom of every article:

<!-- in layouts/entry.html -->
<div>
  <script data-isso="//dmerej.info/isso/"
            src="//dmerej.info/isso/js/embed.min.js"
  >
  </script>
  <section id="isso-thread">
  </section>
</div>

Then I made sure the isso service was reachable at https://dmerej.info/isso, with help from nginx:

# In /etc/nginx/conf.d/blog.conf
location /isso {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Script-Name /isso;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://localhost:1234;
}

and systemd:

# In isso.service
[Unit]
Description=isso comments service
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
ExecStart=/srv/isso/.local/bin/isso -c /srv/isso/isso.conf run
User=isso

[Install]
WantedBy=multi-user.target

Some notes:

  • The comment form does not show if the visitor has disabled JavaScript. I find that a bit sad, but on the other hand it keeps robots from posting spam (at least so far).
  • All the comments are stored in a SQLite database. I have a systemd timer to back it up every day.
  • People can opt-in to leave their e-mail in the form. Isso does nothing with it but store them in its database. I sometimes use them to send them private messages.

So that’s how the blog works under the hood! Stay tuned for part 2, where I’ll explain how new articles get written and published.


  1. I’m using unicode character RIGHT ANGLE BRACKET to prevent Hugo from expanding the shortcode in this article … ↩︎


Thanks for reading this far :)

I'd love to hear what you have to say, so please feel free to leave a comment below, or read the contact page for more ways to get in touch with me.

Note that to get notified when new articles are published, you can either:

Cheers!