Adapting Ploum's sites to gwit


One of gwit's goals on its intro page claims that

> it should be easy to publish an existing static site (esp. Web and Gemini) as a gwit site.

Let's test that assertion with real stuff. We'll use Ploum's Web and Gemini sites (available at ploum.net) since their content is free/libre and Ploum created a simple script to generate both sites from the same source files, which already sit in a Git repo. This may be a little more involved than creating a pure gwit site from scratch (for that, better read Matograine's tutorial), but it's an interesting exercise nonetheless. Do keep in mind that there are no working gwit clients yet to test the results!

La fin d’un blog et la dernière version de ploum.net (Ploum)
Mettre en place GPG pour un site gwit (Matograine)

Note that each gwit site only supports a single type of index file (e.g. to get "/foo/index.html" when accessing "/foo/"); also, Ploum's script generates both Web and Gemini sites in a single run. So we have to generate content once for the HTML gwit site, then again for the Gemini one.

All instructions below are real; you may find the resulting gwit sites at the sourcehut Git repo mentioned below. Note that I had to create the extra repo and handle Git remotes more carefully since I don't have commit access to Ploum's, but doing this on your own repo should be easier; I'll note that when relevant.

First of all, we clone Ploum's repo (and check its default branch). Then we add a remote for our writable, public repo:

$ git clone 'https://git.sr.ht/~lioploum/ploum.net'
$ cd ploum.net
$ git branch --show-current
master
$ git remote add gwit-sourcehut 'git@git.sr.ht:~ivilata/ploum-gwit-unoff'

Common gwit stuff


We start with Gemini. The following steps are similar for any gwit site. First, each gwit site needs its own PGP key. We create a new one with default parameters and no expiration date (it asks for a new passphrase), and turn its fingerprint (the long string of hexadecimal digits) into lowercase.

$ gpg --quick-gen-key \
  "Ploum.net Gemini site (unofficial) <degauss+ploumgem@selidor.net>" \
  default default never
[…]

pub   rsa3072 2024-10-16 [SC]
      24860D48D3ABBB5CEFFBC5126483FD2F7B9EADDF
uid                      Ploum.net Gemini site (unofficial) <degauss+ploumgem@selidor.net>
sub   rsa3072 2024-10-16 [E]

$ echo 24860D48D3ABBB5CEFFBC5126483FD2F7B9EADDF | tr ABCDEF abcdef
24860d48d3abbb5ceffbc5126483fd2f7b9eaddf

That long string is the unique gwit site ID. Signed commits for the site belong to the "gwit-0xNNNNNNNN" branch, where NNNNNNNN are the last 8 lowercase digits of the ID. We create that branch and put the public key in ".gwit/self.key", so that gwit clients can check that signatures belong to the key matching the ID.

$ git checkout master  # ensure that we start from the right branch
$ git switch --create gwit-0x7b9eaddf
$ mkdir .gwit
$ gpg --armor --export 24860d48d3abbb5ceffbc5126483fd2f7b9eaddf > .gwit/self.key

We now add some metadata and configuration for the site in ".gwit/self.ini". We'll put generated Gemini files in "public_gemini", so we make it the site's root (e.g. "/foo/bar.gmi" in a URI maps to file "public_gemini/foo/bar.gmi"). We also want "/foo/" in a URI to map to "public_gemini/foo/index.gmi", so we set that as index file. We also want links like "gemini://ploum.net/…" to point back to this very gwit site, so we set them as alternative prefixes. The resulting configuration file may look like this:

[site "0x24860d48d3abbb5ceffbc5126483fd2f7b9eaddf"]
name = Ploum non officiel (Gemini)
title-en = Ploum's Gemini blog (unofficial)
title-fr = Le blog Gemini de Ploum (non officiel)
root = public_gemini
index = index.gmi
alt = gemini://ploum.be/
alt = gemini://ploum.eu/
alt = gemini://ploum.net/
remote = https://git.sr.ht/~ivilata/ploum-gwit-unoff

Also note how we include the public URL of the Git remote where we'll be pushing gwit site branches. Several such clones may be included for greater availability. Let's commit the common gwit stuff with a signature from the site key.

$ git add .gwit
$ git commit --gpg-sign=24860d48d3abbb5ceffbc5126483fd2f7b9eaddf \
  --message="Add gwit support files."

Site-specific stuff


The following steps are specific to Ploum's site and how to generate its content, but we'll include them for completeness. The purpose here is to make everything ready for generating content and adding it to the gwit site branch in the future.

We make the script write Gemini output to "public_gemini" in the source directory, and HTML output to a directory ignored by Git. We then link in some static files (as per the repo's ".build.yml"), and commit changes with a site key signature.

$ echo 'public_*.ignore/' >> .gitignore
$ # This just edits "publish.py" to set Gemini dir to "./public_gemini" (here)
  # and HTML dir to "./public_html.ignore" (here, ignored).
$ sed -i -E -e 's#^(geminidir *= *).*#\1"./public_gemini"#' \
  -e 's#^(htmldir *= *).*#\1"./public_html.ignore"#' publish.py
$ mkdir -p public_gemini public_html.ignore
$ ln -s ../files public_gemini
$ git add .gitignore publish.py public_gemini
$ git commit --gpg-sign=24860d48d3abbb5ceffbc5126483fd2f7b9eaddf \
  --message="Setup Gemini output support."

Updating & generating content


What do we do when new content gets added in the upstream (original) repository? We follow four steps:

* Fetch new commits from upstream.
* Merge new commits from its default branch ("master" here) into the gwit site branch.
* Generate content and commit it with a site key signature.
* Push to publish.

(For sites where content generation isn't needed, one could just sign the merge commit and push it.)

$ git fetch origin
$ git switch gwit-0x7b9eaddf  # ensure we modify the right branch
$ git merge origin/master  # accept or edit message, no need to sign
$ python3 publish.py  # Ploum's content generation script
$ git add public_gemini
$ git commit --gpg-sign=24860d48d3abbb5ceffbc5126483fd2f7b9eaddf \
  --message="Generate output from source."  # or describe site news
$ git push -o skip-ci gwit-sourcehut

The last command updates the gwit site branch at the writable remote that we created at the beginning. You may not need to indicate it if you can write to the upstream repo. The "-o skip-ci" is also specific to Ploum's site and sourcehut, since we don't want it to build the site. So for your site, it may be as simple as "git push".

That's all! These are the only commands that need to be run every now and then to update the gwit site.

Extra ball: to also publish the upstream "master" branch at the writable repo (not really needed for gwit), we run:

$ git push -o skip-ci gwit-sourcehut origin/master:refs/heads/master

The Web gwit site


The instructions above starting from "Common gwit stuff" are more-or-less applicable to the Web site as well, of course changing key IDs for its new dedicated PGP key. The repo mentioned above also contains the resulting gwit site b1f5a34aac62bfda746a3188aab4500edeaf682a (living in the "gwit-0xdeaf682a" branch).

Note here that we want to use "public_html" as the site's root, with "index.html" as index file, and "https://ploum.net/…" as alternative prefixes. Hence the slightly different site configuration file:

[site "0xb1f5a34aac62bfda746a3188aab4500edeaf682a"]
name = Ploum non officiel (Web)
title-en = Ploum's Web blog (unofficial)
title-fr = Le blog Web de Ploum (non officiel)
root = public_html
index = index.html
alt = https://ploum.be/
alt = https://ploum.eu/
alt = https://ploum.net/
remote = https://git.sr.ht/~ivilata/ploum-gwit-unoff

Of course, the generation script is tuned instead to write HTML content to "public_html" and dump Gemini content to "public_gemini.ignore".

A little addendum here is gwit's mechanism to allow discovering the gwit version of a Web site through a Well-Known URI. In the case of ploum.net, this would require "https://ploum.net/.well-known/gwit.ini" to yield at least this subset of the configuration file:

[site "0xb1f5a34aac62bfda746a3188aab4500edeaf682a"]
remote = https://git.sr.ht/~ivilata/ploum-gwit-unoff

Something similar may also be done in Gemini (with its site configuration), though Well-Known URIs are not a part of Gemini standards.

Conclusions


Converting Ploum's sites to gwit was neither trivial nor too complicated, or at least not much more than creating a pure gwit site. I actually spent more time studying and trying to adapt the content generation workflow to gwit than performing proper gwit stuff. Working with both an upstream read-only repo and a writable one sure complicates things a little regarding Git usage, otherwise operations may be doable on a simple Git UI for less techie authors. Too bad that plain Git doesn't allow configuring per-branch PGP signing keys, as that would make commands simpler!

A possible issue with gwit is site repos taking a lot of space. In the case of Ploum's, the upstream bare clone took 220 MiB. Note that the unpacked "files" directory already takes some 110 MiB. After adding Gemini and Web gwit sites with a couple of versions (one of which included a rewrite of all HTML pages to update a common footer), the bare clone grew by just 10 MiB. All in all, not super-light but neither outrageous for a site with 20 years worth of posts!

Joyeux 20e anniversaire, ploum.net !

🍃

🗒 Back to log index