Skip to content

Deploying the documentation

The docs are five MkDocs static sites, one directory per audience under docs/, each with its own markdown and mkdocs.yml. Each builds into a gitignored site/, and serving one is serving static HTML — there is no application involved. Authoring them is covered in development practices → Documentation.

One-time toolchain setup

Ubuntu marks its system Python externally-managed (PEP 668), so pip install and even pip install --user are refused. The toolchain therefore lives in a repo-local virtualenv, pinned by docs/requirements.txt:

sudo apt install -y python3.12-venv      # the only step that needs root
python3 -m venv docs/.venv
docs/.venv/bin/pip install -r docs/requirements.txt

docs/.venv is gitignored and per-machine. Nothing else on the box is touched, and the system mkdocs on PATH — if there is one — is not what builds these.

Local: read them in a browser

docs/build.sh                 # all five sites
docs/build.sh zf-general      # or just one

It builds each site into its own site/ directory and then prints, for each one, the command that serves it in a browser:

docs/.venv/bin/mkdocs serve -f docs/zf-deployment-docs/mkdocs.yml

That starts a small web server for the one site, prints the address it answers at, and rebuilds the site as you save. Stop it with Ctrl-C. One site at a time, on one port: a second one at the same time takes --dev-addr localhost:8001.

build.sh passes --strict, which makes a nav entry or link pointing at a missing file a build failure. That is how these sites break — a page is renamed, the nav still names it, and nothing says so until a reader clicks — so build before committing a page rename. mkdocs serve alone does not fail on that, which is why the build is the check and the serve is the reader.

Live

Three of the sites are public, and they travel two different ways.

The guides and the home site are published from a development machine, by one command, whenever they change:

docs/publish.sh

It builds them, then copies them to the host over ssh with rsync, as static files. The production and development guides land at https://deployment.zebrafishfacilitymanager.com, behind a landing page that asks which of the two you are setting up, with the production guide under /production/ and the development guide under /development/. The home site, what ZFM is, who uses it, the terms and how to get in touch, lands at https://home.zebrafishfacilitymanager.com. Each copy is a mirror, so a page deleted here is deleted there, and every page's footer says which build of the repository it describes. The host does nothing but serve two directories: it has no Python, no MkDocs and no checkout.

The host side is set up once. Each directory belongs to the account the publish logs in as, so that publishing needs no root, and Caddy serves each from one file in /etc/caddy/conf.d:

sudo install -d -o <your account> -g <your account> -m 755 /var/www/zfm/docs/deployment /var/www/zfm/docs/home
sudo install -m 644 deploy/caddy/deployment-docs.caddy deploy/caddy/home.caddy /etc/caddy/conf.d/
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy

The site addresses in those files are https://, so Caddy obtains each certificate itself at the first request, once the name resolves to the host.

The usage guide ships inside every release. It is built with the installation artifact and served by each facility's web server at /usage-guide/ on the facility's own address, from the release that facility runs, so what a user reads describes the version in front of them. Nothing publishes it separately; it reaches a facility the way the rest of a release does.

The development-practices and data-migration sites are not published. They are read from a checkout.