infrastructure.md links to incidents/ the way Gitea renders directories. A static site has no directory listing, so the build now generates a small landing page (with each document's own title) for any documented directory that lacks an index. Build artifact only — no document is touched.
Publishing the documentation site
The Markdown in this repository is the single source of truth. This directory is the publishing layer that turns it into a member-readable static site and puts it on the co-op's Surfer app. Documents are never edited here — a change to a document is a normal commit or pull request against the Markdown at the repository root.
What is built
| File | Purpose |
|---|---|
../mkdocs.yml |
Site configuration (MkDocs + Material for MkDocs) |
brand.css |
Co-op palette + self-hosted Figtree webfont (SIL OFL 1.1) |
fonts/ |
Figtree woff2 files and the OFL licence text |
logo.svg |
Co-op logo (shared with the website repo) |
build.sh |
Stage the Markdown into .site-src/, render to .site-build/ |
deploy.sh |
Push the build into the Surfer app container |
poll-watcher.sh |
Polls Gitea main every 60s; deploys on change (agent host) |
docs-deploy-poll.service |
systemd unit for the poller |
webhook-receiver.py |
Gitea webhook → pull → build → deploy (agent host) |
webhook-receiver.service |
systemd unit for the receiver |
requirements.txt |
Pinned Python build toolchain |
Nothing external is loaded by the site: no CDN, no third-party font service. Fonts are served from this repository's own output.
Build
publishing/build.sh # creates .venv-docs on first run
Output lands in .site-build/ (gitignored). mkdocs build --strict is what
CI-style runs should use, so broken links fail the build.
Deploy
CLOUDRON_TOKEN=... publishing/deploy.sh
Writes the build into the Surfer app (Cloudron app inference.coop) at:
/app/data/public-docs/— served at https://docs.inference.coop//app/data/public/docs/— served at https://inference.coop/docs/
Both are written so the site stays reachable either way; the hostname is the canonical one.
Automatic rebuilds (push to main)
Two mechanisms keep the site in step with main; both run on the agent host
and neither adds a Cloudron app.
Polling (running now). docs-deploy-poll.service polls Gitea every 60
seconds and deploys whenever main moves. A push appears on the site within
about a minute, with no human action. The Gitea webhook alone was not enough
because the agent host's cloud firewall only admits inbound SSH — a webhook
POST is silently dropped — while outbound access to Gitea works.
Webhook (wired, waiting on one port). A Gitea webhook is registered on
co-op/docs (push events, branch main) pointing at the receiver below. The
moment the Infomaniak panel allows inbound TCP to the agent host — port 8787
from the Cloudron box 179.237.86.116 is enough — start the receiver and pushes
deploy instantly instead of within a minute:
sudo systemctl enable --now docs-deploy-webhook
tail -f /home/ubuntu/docs-deploy.log # what both mechanisms are doing
The receiver authenticates webhooks with an HMAC-SHA256 shared secret
(DEPLOY_WEBHOOK_SECRET in the agent host's env file) and only accepts pushes
to main of co-op/docs from the Cloudron box. Woodpecker CI (Cloudron
catalog) could do the same job inside Cloudron, at the cost of running another
app; the agent-host mechanisms were chosen because they add no new Cloudron app.
Each deploy writes meta.json into the site with the commit it was built
from, so a deploy can be verified from the served site itself:
https://docs.inference.coop/meta.json