(Click here to skip to the tutorial.)

I knew I wanted to make a blog, and frankly I would have preferred that I didn’t have to make it myself from scratch. I thought about making a Substack, but it’s completely bogged down by trackers, accessibility fails, and JavaScript code that’s doing god-knows-what-else. Seriously, what is all this crap?

Dozens of HTTP requests being sent by Substack, including lots of third-party trackers

I’m not a web developer by trade, but this network log seems like an awful lot of bullshit and not a whole lot of “blog.” Sure, Substack has fun features like paywalls and an “explore” page where you can find new blogs about topics you like, and that’s nice. But, I fully intend on using this blog as a soapbox to complain about the overabundance of invasive tracking on the web. The accessibility problems are a deal-breaker on their own, but using Substack would just be hypocritical.

Pretty much every Vercel template is off the table, too, since those all seem to use VDOMs, which are unnecessary in any context (cough cough Svelte) but are particularly heinous in the context of blogs. Wix and Wordpress would be an option, but I hate Wordpress’s UI and I can’t imagine Wix is any better.

I realized I could scour the internet for a simple, accessible, aesthetically-pleasing blogging platform and pray it works the way I want it to, or I could just make one myself.

Say hello to µstack (pronounced “microstack”).

What µstack is

µstack is a tiny self-hosted markdown blogging platform. It allows writers and creators to serve content directly to their audience, without a third party in the middle. µstack’s goals are as follows:

  1. Do not require the writer to have any coding skills whatsoever. Every post shall be written in markdown. Zero JavaScript, HTML, or CSS should be required. I write enough code at work. Writing a blog post shouldn’t feel like work.
  2. Commit no accessibility fails. Use semantic HTML. Do not use a virtual DOM. Every HTML tag should have a clear purpose.
  3. Look nice. Match the user’s dark/light theme preference. Keep a nice, compact floating header at the top for convenient navigation. Employ a minimal aesthetic that allows my words to do the talking.
  4. Load fast. Be JavaScript-free whenever possible. Render everything on the server. Cache aggressively.

What µstack isn’t

µstack isn’t Patreon or Substack. You can’t paywall stuff. I don’t want to paywall my blog, though, and even if I did, I doubt enough people are interested in what I have to say that it would amount to meaningful income anyway. You can buy me a coffee, though.

µstack isn’t JavaScript-free. On some posts, highlight.js is loaded to do code syntax highlighting. µstack requires the writer to manually enable this feature for each blog post where they want syntax highlighting, so it is minimally invasive.

µstack isn’t complete, at least not yet. I figure the best way to make a blogging platform is to make a blog with it. Seeing as this is my very first post on Hard Fault Life, I still have quite a bit of blogging to do before µstack is complete.

How to use µstack

1. Installation

µstack can be installed via Cargo:

cargo install --git https://github.com/ryukoposting/ustack.git

2. Create an empty blog

Create a new folder where you want your blog to live. Inside that folder, run this command:

ustack init

This will create a new µstack blog in the current directory. You will see that there is already one post, an example post located in posts/sample-post.md.

3. Run the server

Run this command:

ustack serve -c 5

This will start the µstack server. Open your web browser, and go to localhost:4198. Ta-daa! A blog!

That -c 5 piece sets µstack’s cache timeout to 5 seconds, so it will check the filesystem for updates to your blog posts regularly. This is nice while we’re writing a blog post, so we can quickly see what the post will look like.

In production, you won’t want to use -c 5, or anything lower than roughly -c 300. This helps prevent spammers from bogging down your server. If you have a very popular blog with lots of posts, you might want to make it even higher, like -c 1800.

Also note that µstack’s server doesn’t support HTTPS; in production, you’ll want to put it behind a reverse proxy like Nginx. In the future, µstack will be able to dump your whole blog into a bunch of HTML files, and you’ll then be able to simply point a static file server at those files.

You can keep the server running for the rest of this tutorial.

4. The preamble

Every post has a YAML preamble at the top, which tells µstack some basic information about the post. Because the SEO overlords have deemed it so, this preamble actually matters a lot (I think?) if you want to reach a large audience. The fields in the preamble are pretty simple, and the only required field is the title:

  • title: Obviously, every blog post needs a title!
  • author: Although it is not required, it is a good idea to mention the author of every blog post.
  • summary: The summary appears in your blog’s index, and it also is used in the “description” <meta> tag. Social media sites may also show this text in their preview bubbles, if someone decides to share one of your blog posts.
  • highlight: As mentioned before, set this field to enable syntax highlighting for a particular blog post. For posts that don’t have a lot of code snippets, leave it disabled to keep the post as lightweight as possible.
  • tags: This field contains a list of keywords you want to associate with your post. These keywords will appear in the “keywords” <meta> tag. Eventually, I will also create a search tool that allows readers to search through your blog using these tags.

That includes the post’s author, a brief summary of the post, and whether or not syntax highlighting should be enabled.

title: This is the post's title.
author: Your name goes here.
summary: A quick description of this blog post.
highlight: true # this is false by default
   - hello
   - world
   - blog

5. The post itself

After the preamble comes the blog post itself. µstack supports standard Markdown features, plus tables, strikethrough, tables, and task lists. It also supports raw HTML; if you need to include something in a post that’s simply not possible with plain markdown, just write it in HTML instead.

Every markdown heading is assigned an anchor that allows you to directly link to it. For example, a heading like this:

# Hello, world!

…can be linked with the anchor #hello-world. As another example, here’s a link that goes back to the header “What µstack isn’t.”

6. The index

When you created your blog using ustack init, you may have noticed an index.md file in the root of the blog, outside the posts/ folder. This is your blog’s index. The YAML preamble works similarly to the posts’ preambles, but the index title is the blog’s title, not any particular post’s title. There are also a few extra fields to consider:

url: https://yourblog.com # Required - canonical base URL of your website
lang: en                  # Required - the blog's language in ISO639 form
twitter: true             # Adds a "share on twitter" link below each blog post

That url tag is pretty important - it’s used to form the canonical URL <meta> tags demanded by the SEO overlords, and it’s also used to construct social media sharing links.

7. The public folder

The public/ folder contains static files that are served by the µstack server. The stylesheet public/styles.css is the only thing that must be in this folder, since that’s the stylesheet for your whole blog. The public folder is a good place to put pictures, videos, and fonts used in your blog. If you put an image in the public folder, you can use it in a blog post like so:

![A very cool picture](/public/picture.png)

There are some simple rules to follow with the public folder. First off, the server will never expose a file containing the string “id_rsa” or the extension .pem. Furthermore, symlinks are not allowed inside the public folder.

8. Creating a new post

You could edit the sample post, or just delete it. You can generate a new post by running this command:

ustack generate post $POST_ID

where the new blog post will be located at posts/$POST_ID.md. µstack will insist that you only use ASCII alphanumeric characters and hyphens in your post’s ID, but the server is more flexible than that.

Contributing to µstack

Please, PLEASE do. There is much to be done. µstack can be cloned from this GitHub repository.