Glossy New Blog

Posted on .

It's a rite of passage for a programmer to write a blog engine. It's lunacy to keep writing blog engines when there was nothing wrong with the previous ones. This blog is now in its fifth incarnation, if I have kept count correctly. Starting in 2015 with a couple of JavaScript based no-backend engines, following up with the Elixir & Phoenix based Mebe, and then with Elixir & Raxx based Mebe 2. Now it's time for Scriptorium.


Aside: The title of this post is "Glossy New Blog" because the blog generator was named Gloss at first. It was renamed to Scriptorium as the package Gloss is squatted on Hex.pm.


Shortly put, there were three reasons for the change:

  1. I was fed up with running Mebe 2 for a few reasons, but mostly because it was quite outdated, meaning a simple template change would require a lot of update work first, and then a new release (which I couldn't build on my ARM Mac for the target amd64 environment). Additionally, writing posts required manually uploading files via SFTP and then SSHing into the VPS to run an update command – which is not Mebe's fault, I just never automated this.
  2. For the past year or so I've been learning Gleam, and I've been having so much fun. It's like back when I first discovered Elixir, and the community has been so welcoming and great all around. So what a better way to learn things than by redoing the same project you've redone over and over again?
  3. I wanted to lessen the runtime complexity of the blog, so I wanted to get rid of the backend, again.

Scriptorium uses Lustre for its templates, constructing static HTML with lustre_ssg. The blog post format is the same as before, meaning I could keep all my files. Marked is used for processing the Markdown syntax of the posts themselves. Everything else is custom code.

Scriptorium is still a work in progress. I believe the base is now usable and releaseable to a wider audience, although I'll need to document everything first. There are still some things missing that I'd like to add in later releases, like syntax highlighting for code blocks (preferably generated beforehand and not in the browser).

On another note, this blog is also running on a new server. It's the same server that hosts my fediverse instance, a tiny Lenovo M710q with an added external HDD. In another first for me, it's running Caddy, which has felt pretty nice thus far, and allowed me to get rid of my hacky hand-built Let's Encrypt certificate renewal system. Less work means happier me.

Since this is now just static HTML files, some Caddy config is needed to support URLs without the .html extension (allowing me to keep all old URLs valid), but also to redirect users from the .html versions if they happen to stumble upon them. Additionally I also made 404 errors render the /404.html page, which to Scriptorium is just another page, rendered from pages/404.md. Here's the config in its entirety:

blog.nytsoi.net {
  # Matcher for .html extension paths
  @htmlext {
    path *.html
  }

  encode gzip
  root * /var/www/blog/output

  # Redirect .html hits to path without .html
  redir @htmlext https://blog.nytsoi.net{dir}{file.base}

  # Try path as .html and .xml file first
  try_files {path}.html {path}.xml

  # Otherwise serve as regular file
  file_server

  handle_errors {
    # When error occurs, check if there is an HTML file with that status code as name
    @custom_err file /{err.status_code}.html

    # If there is, serve that file
    handle @custom_err {
      rewrite * {file_match.relative}
      file_server
    }

    # Otherwise respond with just the status code and text
    respond "{err.status_code} {err.status_text}"
  }
}

This is from a Caddy noob, a pro could probably clean it further.

Now, I'm not promising that this will make me write more blog posts. But I must admit there have been some ideas floating around in my head and they've been waiting for me to rewrite the engine first. Perhaps now I can offload some of them for your reading pleasure.

Oh, looks like my raspberry pi tag isn't working, probably due to the space. Oh well, can't get it all right the first time. :)