voidq cat wiki.voidq.xyz

how to build this wiki

a minimal wiki running on openbsd using got, ssg, and lowdown. no database. no php. no runtime process at the web layer.


what you need


stack overview

tool purpose
gotd git server daemon, receives pushes over ssh
got version control client, used locally
ssg posix shell static site generator
lowdown markdown to html converter, written in c
httpd serves static html files
relayd tls termination and http redirect
cron triggers rebuild every minute

nothing runs at request time. every page is pre-built html.


step 1 — install packages on the server

only two packages needed:

doas pkg_add gotd lowdown

install ssg — a single shell script, no package required:

ftp -Vo ~/bin/ssg.sh https://romanzolotarev.com/ssg/ssg.sh
chmod +x ~/bin/ssg.sh
doas cp ~/bin/ssg.sh /usr/local/bin/ssg

verify:

ssg
# usage: ssg.sh <src> <dst>

step 2 — set up gotd

gotd(8) is the git server. it speaks ssh, uses pledge(2) and unveil(2), and requires no git package.

create the bare repository:

doas mkdir -p /var/got/wiki.git
doas chown -R _gotd:_gotd /var/got
doas -u _gotd got init /var/got/wiki.git

write /etc/gotd.conf:

user _gotd
listen on "/var/run/gotd.sock"

repository "wiki" {
    path "/var/got/wiki.git"
    permit rw yourusername
    notify {
        email to you@example.com
        email to root
    }
}

check config and enable:

doas gotd -n
doas rcctl enable gotd
doas rcctl start gotd

add to /etc/ssh/sshd_config:

AcceptEnv GOT_PROTO_VERSION

restart sshd:

doas rcctl restart sshd

step 3 — prepare directories

doas mkdir -p /var/www/wiki/src
doas mkdir -p /var/www/wiki/dst
doas chown -R _gotd:_gotd /var/www/wiki

check out the initial worktree as _gotd:

doas -u _gotd got checkout /var/got/wiki.git /var/www/wiki/src

step 4 — the rebuild script

create /usr/local/bin/wiki-rebuild:

#!/bin/sh
set -e
cd /var/www/wiki/src
got update -q
/usr/local/bin/ssg /var/www/wiki/src /var/www/wiki/dst

make it executable:

doas chmod +x /usr/local/bin/wiki-rebuild

note: this version of gotd does not support exec in notify blocks. a cron job triggers the rebuild instead.

add to crontab:

crontab -e

add this line:

* * * * * /usr/local/bin/wiki-rebuild >> /var/log/wiki-rebuild.log 2>&1

step 5 — configure httpd

write /etc/httpd.conf:

server "wiki.voidq.xyz" {
    listen on 127.0.0.1 port 8080
    root "/wiki/dst"
    gzip-static
}

step 6 — configure relayd

add to /etc/relayd.conf:

http protocol "wiki" {
    tls { no client-renegotiation }
    match request header set "X-Forwarded-For"   value "$REMOTE_ADDR"
    match request header set "X-Forwarded-Proto" value "https"
}

relay "wiki_https" {
    listen on egress port 443 tls \
        certificate "/etc/ssl/wiki.voidq.xyz.fullchain.pem" \
        key         "/etc/ssl/private/wiki.voidq.xyz.key"
    protocol "wiki"
    forward to 127.0.0.1 port 8080
}

relay "wiki_http" {
    listen on egress port 80
    protocol http
    block return 301 "https://wiki.voidq.xyz$REQUEST_URI"
}

enable and restart:

doas rcctl enable httpd relayd
doas rcctl restart httpd relayd

step 7 — local setup

install got on your local machine:

pkg_add got

set your author identity:

echo 'export GOT_AUTHOR="Your Name <you@example.com>"' >> ~/.profile
. ~/.profile

clone the repository from the server:

got clone ssh://yourusername@wiki.voidq.xyz/wiki ~/wiki
cd ~/wiki

step 8 — create the template

ssg wraps every markdown page with .ssg.template. create ~/wiki/.ssg.template:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/style.css">
<title>{{#title}}{{title}} — {{/title}}wiki.voidq.xyz</title>
</head>
<body>
<nav>
<a href="/">home</a>
<a href="/about.html">about</a>
<a href="/guides/wiki-setup.html">wiki setup</a>
</nav>
<main>
{{content}}
</main>
<footer>wiki.voidq.xyz &mdash; got + ssg + lowdown</footer>
</body>
</html>

step 9 — create style.css

create ~/wiki/style.css:

*,*::before,*::after{box-sizing:border-box}
body{
  background:#1a1a18;
  color:#b4b09c;
  font-family:'Courier New',Courier,monospace;
  font-size:15px;
  line-height:1.7;
  max-width:680px;
  margin:2rem auto;
  padding:0 1.5rem;
}
a{color:#8ab4a0;text-decoration:underline}
a:hover{color:#b8d4c0}
nav{
  font-size:13px;
  margin-bottom:2.5rem;
  padding-bottom:1rem;
  border-bottom:1px solid #2e2e2a;
}
nav a{color:#7a9e8a;text-decoration:none;margin-right:1.2rem}
nav a:hover{color:#a8c8b4}
h1{font-size:1.3rem;font-weight:normal;color:#e8e4d0;margin:0 0 1.5rem}
h2{font-size:1rem;font-weight:normal;color:#a8a494;margin:2rem 0 .75rem}
h3{font-size:.95rem;font-weight:normal;color:#8a8678;margin:1.5rem 0 .5rem}
p{margin:0 0 1rem;color:#b4b09c}
pre{
  background:#111110;
  border:1px solid #2a2a26;
  padding:1rem;
  overflow-x:auto;
  border-radius:3px;
  font-size:13px;
  color:#8ab47a;
  margin:1rem 0;
}
code{
  background:#111110;
  border:1px solid #242420;
  padding:.1em .35em;
  border-radius:2px;
  font-size:13px;
  color:#8ab47a;
}
pre code{border:none;padding:0;background:transparent}
ul,ol{padding-left:1.2rem;color:#b4b09c;margin:0 0 1rem}
li::marker{color:#4a4a42}
blockquote{
  border-left:2px solid #3a3a34;
  margin:1rem 0;
  padding:.5rem 1rem;
  color:#7a7a6e;
}
table{border-collapse:collapse;width:100%;margin:1rem 0;font-size:14px}
th{text-align:left;color:#6a6a5e;border-bottom:1px solid #2e2e2a;padding:.4rem .6rem}
td{padding:.4rem .6rem;border-bottom:1px solid #222220;color:#b4b09c}
hr{border:none;border-top:1px solid #2e2e2a;margin:2rem 0}
footer{
  margin-top:3rem;
  padding-top:1rem;
  border-top:1px solid #2e2e2a;
  font-size:12px;
  color:#4a4a42;
}

step 10 — first commit and push

cd ~/wiki
got add .
got commit -m "initial wiki"
got send

within one minute cron runs wiki-rebuild and the site goes live. visit https://wiki.voidq.xyz to confirm.


daily workflow

edit an existing page:

vi index.md
got commit -m "update index"
got send

add a new page:

vi guides/newpage.md
got add guides/newpage.md
got commit -m "add newpage"
got send

view history:

got log

see what changed before committing:

got diff

force a full rebuild on the server (if something looks stale):

doas -u _gotd rm -rf /var/www/wiki/dst/*
doas -u _gotd /usr/local/bin/wiki-rebuild

troubleshooting

check all services are running:

doas rcctl check gotd httpd relayd

check httpd error log:

doas tail /var/www/logs/error.log

check rebuild log:

tail /var/log/wiki-rebuild.log

check worktree is in sync:

cd /var/www/wiki/src && got status

check dst was populated:

ls /var/www/wiki/dst/

stale gzip files — force full rebuild:

doas -u _gotd rm -rf /var/www/wiki/dst/*
doas -u _gotd /usr/local/bin/wiki-rebuild

what runs on the server at request time

nothing. httpd serves pre-built static files directly. the only active processes are gotd (ssh), httpd, and relayd. no interpreter, no database, no application server.


see also