3 xmlns:awol="http://bblfish.net/work/atom-owl/2006-06-06/"
4 xmlns:dc11="http://purl.org/dc/elements/1.1/"
5 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
6 xmlns:sioc="http://rdfs.org/sioc/ns#"
8 <dc11:title>Running a Wiki with a Server and Git</dc11:title>
9 <dc11:date>2023-07-29T14:19:48-07:00</dc11:date>
10 <dc11:abstract rdf:parseType="Markdown"><![CDATA[
11 Forum software can be intimidating, but a wiki is something you can set
12 up easily and trivially—so long as you are fine with the editing
13 interface just being a Git repository.
15 <sioc:content rdf:parseType="Markdown"><![CDATA[
16 In the past few days I’ve set up a new domain here at <cite>Lady’s
17 Computer</cite>: [`wiki.ladys.computer`][Wiki]. The goal of this site
18 is to be a public, easily‐editable forum (a <dfn>wiki</dfn>) for myself
19 and friends to document our thoughts and feelings. This blogpost exists
20 to formally announce the project, describe its underpinnings, and
21 describe how you can set one up on your own.
25 In order for this post to make any sense at all, it’s probably first
26 necessary for me to digress into a bit of wiki philosophizing. Because
27 [wiki is not Wikipedia][WikiIsNotWikipedia], and a lot of people don’t
28 really understand what a wiki is *for*.
30 What I want to emphasize in this post is that a wiki is not a
31 reference material. *A wiki is a social space.* The etymological root
32 for <i>wiki</i>, [<i lang="haw">wikiwiki</i>][wikiwiki], is a Hawaiian
33 word meaning “quick”; the goal of the wiki is to *lower the bar for
34 social interaction* to be as “quick” as possible. What distinguishes
35 the wiki from other forms of social media is the form this social
36 interaction takes. Where·as on a traditional forum, social behaviours
37 are purely additive, the wiki adds a subtractive component: On a wiki,
38 you engage in the social practice of *revision* or *refinement*.
40 Put simply, you write on a wiki **because you want somebody to edit
41 it.** Editing means deleting the part that is bad and expanding on the
42 part that is good. Editing can mean taking a page with just a title and
43 filling it with words. Editing can mean adding a dissenting opinion to
44 make a strong claim appear more qualified. Editing can mean adding
45 hyperlinks, both internally (to other wiki pages) and out to the
48 In all this, there is nothing *preventing* a wiki from taking on the
49 shape of more traditional social media, writing in what is called
50 “thread mode”. Discourse on a wiki can and probably should begin, in
51 many cases, as a thread of members posting their thoughts and opinions
52 to each other on a page. It is common to sign statements which have a
53 personal component or which one feels particularly strongly about.
54 But threads also don’t have to *remain* threads. On a wiki, there is
55 nothing stopping someone from going through and structuring the
56 conversation into a more coherent, and readable, argument at a later
59 All wikis keep a log of edits, so nothing is ever lost.
61 My hope is that the above points make clear the practical utility of a
62 wiki space for *dialectics*, for critical conversations and discourse,
63 for evolving development of communal thought, and for a kind of
64 participatory dialogue which it is harder to make manifest on other
65 platforms. This *radical* potential of the wiki is completely lost in
66 sites like Wikipedia and also in the sorts of reference sites that
67 contemporary big‐name static site generators are typically geared
68 towards. [Docusaurus][], as one completely arbitrary example, is
69 entirely lacking in social features for editors to communicate *with
70 each other*, which, after all, is a wiki’s entire *point*.
71 (Contemporary static site generators *also*, I think, have failings
72 which limit their utilities as reference texts, but I will save *those*
73 thoughts for a different blogpost.)
75 ## Technological Underpinnings
77 When I first mentioned to my partner that I was « trying to write a
78 wiki generator », their immediate response was « dont like any of the
79 existing ones? ». I then had to explain the following points :—
81 1. The kind of thing I’m trying to do *mostly* doesn’t exist in any
82 broadly‐acknowledged, existing form, and
84 2. If I’m doing this right, the end result should be maybe a thousand
85 total lines of code, so I might as well just write it exactly how I
88 To be entirely clear about this, I am not the first person to have this
89 idea and I am absolutely certain that, for example, the Emacs folks
90 have been doing this sort of thing with Org Mode for probably decades.
91 But there are a few *recent* technological developments which I think
92 have made now a *very good time* for this sort of project, and whose
93 recency also means that, of course, I will have to write the actual
94 code to make use of them.
98 Well, Git is not new. People have been using Git for a long time, and
99 people have been building wikis on top of Git as well for a long time.
100 John MacFarlane’s [Gitit][] is I think a reasonable example of the sort
101 of thing I am interested in, in terms of its general approach.
103 What I think *is* relatively new, or at least growing, is the idea that
104 Git is *sufficient*, that a commandline git interface is *the only
105 editing interface one needs* for a website of content, especially one
106 containing zero code. We are in a moment where *nontechnical* use of
107 Git, Git for writers and not just for programmers, and Git for human
108 text and not just computer code, seems within reach. This drastically
109 lowers the bar for what might be considered a reasonable wiki
110 interface, from a web application to a simple repository which trusted
111 individuals can access over S·S·H.
113 This is not at all difficult to set up, and can be done without the
114 need for *any* additional tools on virtually any server that one might
119 Using a Git repository as a backend means it is desirable to have the
120 wiki generator be something which can be called as a simple shell
121 script in a post‐receive hook. Ideally, this script would be something
122 located and tracked in a different repository, and a single file which
123 can easily be grabbed and run even if that other repository is bare.
125 There are of course a great many scripting languages out there which
126 one could use for this task, but for most of them a problem immediately
127 emerges in the form of dependency management. [Deno][] is notable, and
128 extremely favourable for this kind of use·case in my opinion, because
129 in Deno the problem of dependency management simply does not exist.
130 Every Deno dependency can be specified as simply a U·R·L, and a single
131 script file with numerous dependencies can be straightforwardly run
132 with no external configuration or prerequisite setup or package
133 installation. And Deno is a fully‐featured Javascript (or, if you
134 prefer, Typescript) runtime, so you still have all the strengths and
135 conveniences of a modern programming language, which you wouldn’t have
136 trying to write this, as some have doubtlessly done, in a Lisp or in
141 Because the goal of a *wiki* is to be *quick*, it is a fact
142 generally‐accepted that the markup language it uses must be
143 *lightweight*. Because we will be taking the approach of static site
144 generation, this markup language needs to be trivially, and quickly,
145 parse·able into an A·S·T which can be easily inspected and transformed
146 by our generation script. The best‐in‐class for lightweight markup
147 transformation today is [Pandoc][], whose A·S·T [I have worked with
148 before][BookGen] and which has a [variant of Markdown][Pandoc/Markdown]
149 that is highly feature·ful and welsuited to transformation.
150 Unfortunately, Pandoc is written in Haskell, filters for it are
151 typically written in Python or Lua, and it both more heavyweight and
152 more of a dependency nightmare than would really be ideal for this sort
155 Fortunately, the creator of Pandoc, the afore·mentioned John
156 MacFarlane, has developed another markup language with all the
157 strengths of Pandoc’s Markdown but none of its weaknesses, and has
158 written a parser implementation for this markup language in Typescript.
159 It’s called [Djot][]. Djot is still extremely beta software, but it
160 meets all of our requirements: It is lightweight, fast to process, and
161 trivially importable in Deno. It has a straightforward A·S·T and was
162 designed with script‐based transformation explicitly in mind.
166 Having decided on the above, I spent a couple of days and threw
167 together [a wiki‐generation script][GitWikiWeb] which, while messy and
168 not exactly feature·ful right now, is a usable minimum viable product.
169 I won’t go into the design decisions of that script here, but I do want
170 to enumerate how one might *use* it to set up their own wiki site. The
171 following explanation assumes you have a box running something
172 relatively unixy and are logged in as a root user.
174 The first step is to clone the GitWikiWeb repository locally, so that
175 you aren’t waiting for the network every time you want to build your
176 wiki. This also enables you to make modifications to the template and
177 stylesheet, which will almost certainly be necessary. (I recommend
178 maintaining your changes as a set of patches on top of the upstream
179 repository, but do whatever you feel most comfortable with.)
181 The following clones it into `/srv/git/GitWikiWeb` :—
184 git clone --bare https://git.ladys.computer/GitWikiWeb.git /srv/git/GitWikiWeb
187 Next, you will want to set up a wiki user on your server, which all of
188 the editors to your wiki will have access to. The <cite>Pro Git</cite>
189 book has [a very good explanation of how to create a shared Git
190 user][GitBook-4.4], so I will just summarize it here.
192 This adds a `wiki` user and creates its `.ssh` directory :—
199 mkdir .ssh && chmod 700 .ssh
200 touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys
203 This sets up the `Wiki` repository which will store your wiki
215 To prevent wiki users from changing other aspects of the server, set
216 the login shell for `wiki` to be `git-shell` :—
220 chsh wiki -s $(which git-shell)
223 Now you can add the S·S·H public keys to
224 `/home/wiki/.ssh/authorized_keys` for everybody you want to be able to
225 edit your wiki. It is recommended that you prefix these keys with
226 `no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ` to
227 further restrict what capabilities `wiki` users have on your server.
229 Once you do this, users should be able to clone and contribute to the
230 wiki from `wiki@yourcomputer.example:/srv/git/Wiki`.
232 The only thing left to do is to add a `post-receive` hook to
233 `/srv/git/Wiki/hooks` which will build the site every time somebody
234 pushes new content. Naturally, this file must be executable. Mine looks
235 like the following :—
239 export GITWIKIWEB=/srv/git/GitWikiWeb
240 while read oldrev newrev refname
242 if [ $(git name-rev --name-only --refs=live $refname) = "live" ]
244 git archive --remote=$GITWIKIWEB ladys build.js \
246 | deno run -A - ~/public $GITWIKIWEB ladys
251 To take this line‐by‐line :—
253 - `#!/usr/bin/env -S sh` simply runs the file with `sh`.
254 I use `/usr/bin/env` here because `sh` is in a different place on my
255 local and remote computers.
257 - `export GITWIKIWEB=/srv/git/GitWikiWeb` provides the location to the
258 GitWikiWeb repository that we cloned earlier.
260 - `while read oldrev newrev refname` loops over all the refs which were
261 pushed (there can be multiple) and assigns `$refname` to the name of
264 - `if [ $(git name-rev --name-only --refs=live $refname) = "live" ]`
265 checks to see if the pushed ref was equivalent to the `live` branch.
266 `git name-rev` tries to provide a name for its argument, and with
267 `--refs=live`, it will prefer `live`. Change “live” to whatever the
268 default branch for your wiki is, or edit the file at
269 `/srv/git/Wiki/HEAD` to be `ref: refs/heads/live` if you like that as
270 the name for the default branch.
272 - `git archive --remote=$GITWIKIWEB ladys build.js` requests an archive
273 of the file `build.js` from the `ladys` branch of the GitWikiWeb
274 repository. You will probably want to specify a different branch
275 name. By default, this is a Tar file.
277 - `tar -xO` untars the Tar to standard output.
279 - `deno run -A -` runs the piped script with full permissions. The
280 GitWikiWeb script takes three arguments: ① the location to which the
281 wiki should be built, ② the location of the GitWikiWeb repository,
282 so that it can request template and configuration files, and ③ the
283 branch in the GitWikiWeb repository which files should be requested
284 from (this should match the branch name you gave to `git archive`).
286 …and that’s it! Assuming there is a webserver hosting the content at
287 `/home/wiki/public/`, the wiki should be live as soon as someone posts
290 My hope is that the above steps make this feel reasonable, and bring
291 the idea of small, community‐run wikis into a space where they feel
292 like something one could conceivably do. There has been a lot of noise,
293 with social media these days being what it is, about bringing back
294 forum culture, but forum hosting is often complex and involves a
295 nontrivial amount of sysadminning work. I think bringing back wiki
296 culture in a limited, low‐tech, grassroots sort of way is a viable
297 alternative and can satisfy a lot of the same use·cases, sometimes even
300 It’s only been up for a few days, but so far my wiki at
301 [`wiki.ladys.computer`][Wiki] has proven this to be an idea with
304 [Wiki]: <https://wiki.ladys.computer> "Lady’s Wiki"
305 [WikiIsNotWikipedia]: <https://wiki.c2.com/?WikiIsNotWikipedia> "Wiki Is Not Wikipedia"
306 [wikiwiki]: <https://en.wiktionary.org/wiki/wikiwiki> "Wiktionary: wikiwiki"
307 [Docusaurus]: <https://docusaurus.io/> "Docusaurus: Build optimized websites quickly, focus on your content"
308 [Gitit]: <https://github.com/jgm/gitit> "Gitit"
309 [Deno]: <https://deno.land/> "Deno: A modern runtime for JavaScript and TypeScript"
310 [Pandoc]: <https://pandoc.org> "Pandoc: a universal document converter"
311 [BookGen]: <https://github.com/BookGen/BookGen> "BookGen"
312 [Pandoc/Markdown]: <https://pandoc.org/MANUAL.html#pandocs-markdown> "Pandoc User’s Guide § Pandoc’s Markdown"
313 [Djot]: <https://djot.net/> "Djot (/dʒɑt/)"
314 [GitWikiWeb]: <https://git.ladys.computer/GitWikiWeb> "🐙🕸️ GitWikiWeb: A Git‐backed wiki"
315 [GitBook-4.4]: <https://git-scm.com/book/en/v2/Git-on-the-Server-Setting-Up-the-Server> "Pro Git: 4.4 Git on the Server – Setting Up the Server"
316 [Caddy]: <https://caddyserver.com> "Caddy: The Ultimate Server with Automatic HTTPS"
318 <dc11:rights rdf:parseType="Markdown"><![CDATA[
320 <a href="https://www.ladys.computer/about/#lady">Lady</a>
321 <small>[Web Socialist]</small>.
322 Some rights reserved.
324 This blogpost is licensed under a <a rel="license"
325 href="http://creativecommons.org/licenses/by/4.0/"><cite>Creative
326 Commons Attribution 4.0 International License</cite></a>.