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
- an openbsd vps with a domain pointing to it
- let's encrypt certificates via acme-client(8)
- nsd(8) for dns
- relayd(8) and httpd(8) already configured for tls
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 — 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.