Making the Wolog
Making the Wolog
The server you’re connected to right now is my custom blog server, the Wolog. It’s written in Rust, with Tokio, Rocket, and SQLX (connecting to Postgres).
Questions You Might Have
- Why no javascript?
- I Don’t Like It
- What happened to Wologs 1 and 2?
- Wolog 1 was based on my prototyping webserver, wwebs. It was even more
Unix-y than what I have now - page rendering was a Makefile, RSS feed
generation was a Deno script, and all of my templating was done with
catandsed.- This allowed for very easy development of complex features. This version could read out posts with TTS and present them to a podcast client, render out ebooks and PDFs on the server, and even supported a minimalist tinyweb protocol called Gemini.
- Ultimately, though, the security implications of serving public HTTP requests with Bash and Make began to worry me, and the limitations of a CGI-like architecture began to rear their ugly heads.
- I still think wwebs is an excellent prototyping tool - you can count the number of lines of code required to generate QR codes from a POST request body, for example, on one hand!1
- Wolog 2 was an attempt at making a CMS with my own custom database
layer. It didn’t last long.
- The database layer was a separate service that received new updates via an HTTP endpoint. Updates were tarballs ending with a detached PGP signature of the preceding data.
- New files with the same name would replace old ones.
- Once validated, received tarballs would be written onto the end of
One Big Tarball Containing The History Of The World and files would be
mmap’d directly from that tarball in order to be served to the user. - I think this idea has merit, but not for this purpose.
- Wolog 1 was based on my prototyping webserver, wwebs. It was even more
Unix-y than what I have now - page rendering was a Makefile, RSS feed
generation was a Deno script, and all of my templating was done with
- Why no multi-user support?
- The Wolog isn’t meant to accommodate large groups of authors, but it’s possible to extend it to support a small group of trusted friends.
- Consider using tags to identify authors (or modify your templates to read an extra frontmatter field!), and use your operating system’s access control facilities to constrain access to directories and articles as needed.
- Why not sqlite?
I Don’t Like It- In all seriousness, sqlite is excellent, but rendered Wolog posts and their frontmatter are stored as arbitrary Pandoc JSON. Postgres’s rich JSON handling is critical to make this kind of data model work well.
- I could roll my own database (and that option was tempting at first!), but I want the Wolog to hold all of my public writing for the foreseeable future. Stability and longevity are important here, so I want to use something battle-tested.
- Why no built-in editor?
- Making a good text editor is hard.
- For examples, see “every text editor ever made.”
- Making one that handles hypertext gracefully without introducing formatting footguns is pretty much impossible.
- The Wolog ingests posts formatted with Pandoc Flavored Markdown. Nearly every text editor that currently exists at least has keyboard shortcuts mimicking Markdown, and there isn’t any format I’m aware of that can’t be easily converted to Markdown with one Pandoc invocation.
- Obsidian is currently my editor of choice for Markdown, but this might change in the future. Putting effort into making my own editor doesn’t make sense when I don’t know what my perfect text editor looks like, so the pragmatic choice is to open things up for any editor
- For the same reasons, I don’t have any built-in way to upload
article files.
- Managing articles is hard! Posts can have arbitrarily many attachments of any format and size, and I don’t know ahead of time what other data I want to attach.
- I already use Syncthing for all of my personal notes, and my server already runs an instance of it to allow my changes to propagate when my devices aren’t on at the same time.
- Making a good text editor is hard.
Features
The Wolog is still in development - this page will be updated as features are added.
- ✅ Core page rendering
- ✅ User-facing searches and tag browsing
- ✅ Feed generation
- ✅ toki-pona
- lipu li jo e toki pona la ilo pi toki pona li kama poka e ni. ilo ni li lawa e kepeken sitelen pona en kepeken kama Inli.
- mi pali e ni kepeken ala sitelen pi telo sona.
- nasin ni li musi tawa mi. sina o open!
- ⋯ Guestbook, Webrings
- ⋯ Indieweb Microformats
- ⋯ WebMention tx/rx
- There is an attempt, but it isn’t working yet
- ⋯ Owner-facing API for quick “replies”, “likes”, and “reblogs” of arbitrary webpages.
Page rendering
When I write software for myself, I prefer to write the smallest amount of code I can - why would I make my own tools for editing, uploading, and parsing posts, when I already have VSCode, Obsidian, SyncThing, and Pandoc? The Wolog looks in the post directory for Markdown files, calls Pandoc to convert them into an AST, runs them through some internal magic filters, and pipes them back into Pandoc to finally render to HTML.
The magic filters have access to the database, and are split into two stages: preprocessing filters run at reload-time, to make changes that solely depend on the post itself, before the post gets saved to the database, and postprocessing filters run at request-time, to make changes that depend on other posts, like filling out a feed block.
Feed generation
The Wolog has some primitive Atom feed generation now: the “search”
page and the embeddable feed widgets link to a new /feed
endpoint that accepts the same form fields that /search
does. Feeds generated in this way are forced to use descending creation
date sorting, and they’re hard-limited to 32 elements. Likes, replies,
reposts, and notes are specially formatted here, as you would expect.
RSS isn’t supported just yet, but I might add it later.
Guestbook, Webrings
I was born after these features had stopped being mainstream, but they always seemed really cozy to me, so I want to have support for them on my website.
I haven’t implemented it yet, but my plan for the guestbook is to use OAuth to get reliable proof of identity and prevent spam.
WebMention
Anyone trying to make a personal website is faced with a conundrum: most personal websites are intended to facilitate connection and communication, but static websites are tragically unidirectional. Accepting comments on your website can be a solution to this, but they raise moderation and security problems, and it’s difficult for your readers to see what you’re saying about other people’s work. I think WebMention is an excellent solution:
- Readers can submit comments on your site by posting on an account they already have, without giving you the responsibility of handling anything secret.
- There’s a higher barrier to entry for spam: you either have to post from another site and be subject to someone else’s moderation, or spin up your own site that specifically includes links to everywhere you want to spam.
- All of your interactions live on your website, and all of your
readers’ interactions live elsewhere.
- This has obvious benefits to social connection, but it also lowers your exposure to legal risk if your readers post something outrageous: you aren’t actually hosting it, just linking to it.
- If it does come to it, you can ban people at varying levels of granularity, all the way up to an entire domain.
How to Deploy
Currently, the only recommended Wolog configuration is NixOS using Flakes. No warranty or support is offered for this or any configuration. Installing the Wolog on NixOS looks like this:
# flake.nix
{
inputs.wolog.url = "github:spaghetus/wolog3";
outputs = {self, nixpkgs, wolog, ...}: {
nixosConfigurations.foo = nixpkgs.lib.nixosSystem {
system = "x86_64-linux"; # ARM linux should also work
modules = [
wolog.nixosModules.default
{
services.wolog = {
enable = true;
port = ...; # Change this
articlesDir = "...";
assetsDir = "...";
templatesDir = "...";
staticDir = "...";
envFile = "/put/oauth/config/here";
extraWologSettings = {
author = "Willow";
oauth_providers = {
providername = {
issuer = "https://example.com/";
scopes = ["profile" "email"];
};
};
};
# Potentially dangerous if you don't
# trust your authors
enableDynamic = true;
};
services.syncthing.settings.folders.wolog = {
id = "...";
devices = ["..."];
path = "...";
};
services.nginx = {
virtualHosts."..." = {
locations."/" = {
proxyPass = "http://127.0.0.1:...";
};
};
};
}
];
};
};
}Here’s the code to do this with wwebs - it can be reduced to two lines if you know qrencode is installed and you aren’t worried about weird behavior on non-POST requests.
↩︎#!nix-shell #!nix-shell -i bash -p qrencode >&2 echo "header Content-Type image/png" if [ "$METHOD" != "POST" ]; then >&2 echo "status 404" else qrencode -r /dev/stdin -o - -t PNG; fi