## Summary
Replace the cv (`cv.eblu.me`) and docs (`docs.eblu.me`) minikube Deployments with indri-native ansible roles. Caddy serves the extracted release tarballs directly via a new `kind: static` service-block — no daemon, no nginx pod, no ProxyGroup ingress on the request path. Mirrors the rationale of the recent devpi migration; part of the broader minikube wind-down.
## What's in this commit
- `ansible/roles/{cv,docs}` — sentinel-gated tarball download + extract into `~/{cv,docs}/content/`
- `ansible/roles/caddy/` — new `kind: static` branch in the Caddyfile template (encoded gzip, immutable cache headers for fingerprinted assets, optional `try_html` for Quartz-style clean URLs, optional per-path `download_paths` for the resume PDF's `Content-Disposition`)
- `ansible/playbooks/indri.yml` — wires `cv` and `docs` roles before `caddy`
- `service-versions.yaml` — both services flip to `type: ansible`. `docs.current-version` stays at `1.28.2` for this commit so `container-version-check` keeps passing while `containers/quartz/Dockerfile` still exists; it moves to the docs release tag in the cleanup commit
- `.forgejo/workflows/{cv-deploy,build-blumeops}.yaml` — deploy step now bumps `cv_version`/`docs_version` in the role defaults and pushes; running ansible + purging the Fly cache is manual from gilbert (matches devpi)
- Docs: `docs/how-to/operations/{cv,docs}-on-indri.md`, updated `docs/reference/services/{cv,docs}.md`, changelog fragment
## What is not in this commit
The dead artifacts. After PR review and successful cutover, a follow-up commit deletes:
- `argocd/apps/{cv,docs}.yaml` and `argocd/manifests/{cv,docs}/`
- `containers/cv/`, `containers/quartz/`
- `CONTAINER_TO_SERVICE['quartz']` mapping in `mise-tasks/container-version-check`
- bumps `docs.current-version` in `service-versions.yaml` to the release tag
## Cutover plan (manual, from gilbert, after review)
1. **Take down old:**
- Remove the cv and docs Applications: `argocd app delete cv --cascade && argocd app delete docs --cascade`
- Verify k8s namespaces gone: `kubectl --context=minikube-indri get ns | grep -E '^(cv|docs)\\b'` (should be empty)
- Verify tailnet MagicDNS no longer advertises the VIPs: `nslookup cv.tail8d86e.ts.net` and `nslookup docs.tail8d86e.ts.net` should both fail
2. **Bring up new:**
- `mise run provision-indri -- --tags cv,docs,caddy --check --diff` (already validated on branch)
- `mise run provision-indri -- --tags cv,docs,caddy`
- `fly ssh console -a blumeops-proxy -C "sh -c 'rm -rf /tmp/cache && nginx -s reload'"`
3. **Verify:** `mise run services-check` and the curl checks listed in `docs/how-to/operations/{cv,docs}-on-indri.md`
4. **Cleanup commit + merge.**
Total expected downtime: minutes (not the few-hour budget you authorized).
## Test plan
- [ ] `mise run provision-indri -- --tags cv,docs --check --diff` clean
- [ ] `mise run provision-indri -- --tags caddy --check --diff` shows only the cv + docs blocks changing as previewed in the PR thread
- [ ] After cutover: `cv.eblu.me`, `cv.ops.eblu.me`, `docs.eblu.me`, `docs.ops.eblu.me` all return 200
- [ ] `cv.eblu.me/resume.pdf` includes `Content-Disposition: attachment`
- [ ] A clean Quartz URL (e.g. `docs.eblu.me/explanation/agent-change-process`) resolves to the right page
- [ ] `mise run services-check` clean
- [ ] `mise run service-review --type ansible` shows cv and docs
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Reviewed-on: #342
2.9 KiB
| title | modified | last-reviewed | tags | ||
|---|---|---|---|---|---|
| Docs on Indri | 2026-04-29 | 2026-04-29 |
|
Docs on Indri
How the Quartz documentation site (docs.eblu.me) is deployed on indri natively. Replaces the prior minikube Deployment; same shape as cv-on-indri with one extra wrinkle for Quartz's clean URLs.
Why native, not Kubernetes
The docs site is fully static HTML produced by Quartz. Caddy can serve the extracted tarball directly. The Quartz-specific behavior the previous nginx container provided (try_files $uri $uri/ $uri.html =404 and a custom /404.html) maps cleanly to Caddy's try_files and handle_errors.
Layout
| Concern | Path / detail |
|---|---|
| Content dir | /Users/erichblume/blumeops/docs/content/ |
| Version sentinel | /Users/erichblume/blumeops/docs/.installed-version |
| Caddy entry | docs service in ansible/roles/caddy/defaults/main.yml (kind: static, try_html: true) |
| Public URL | https://docs.eblu.me (via flyio-proxy) |
| Private URL | https://docs.ops.eblu.me (Caddy on indri) |
| Tarball source | Forgejo release asset on the blumeops repo (docs-<version>.tar.gz) |
docs_version in ansible/roles/docs/defaults/main.yml is the blumeops release tag (e.g. v1.16.0). The role's download/extract is gated by an on-disk sentinel.
Deploy
- Run the
Build BlumeOpsForgejo workflow → builds the tarball, creates a release, bumpsdocs_versionin the ansible role, pushes to main - From gilbert:
mise run provision-indri -- --tags docs - From gilbert:
fly ssh console -a blumeops-proxy -C "sh -c 'rm -rf /tmp/cache && nginx -s reload'"
The Caddy block uses try_files {path} {path}/ {path}.html and a handle_errors 404 → /404.html rewrite, matching the original nginx behavior so Quartz's clean URLs continue to work.
Verify
ssh indri 'cat ~/blumeops/docs/.installed-version'
ssh indri 'ls ~/blumeops/docs/content/'
curl -fsSI https://docs.ops.eblu.me/ # private
curl -fsSI https://docs.eblu.me/ # public
curl -fsSI https://docs.eblu.me/explanation/agent-change-process # clean URL → .html fallback
curl -fsSI https://docs.eblu.me/no-such-path-exists/ # → /404.html
Bumping the docs version
Normally driven by the workflow. If you need to pin manually, edit docs_version in ansible/roles/docs/defaults/main.yml and re-run mise run provision-indri -- --tags docs.
Backup
Content dir is not borgmatic-backed. Source is in this repo; release tarballs are on the forge.
Rollback
Set docs_version back to the previous release tag in the role defaults and re-run. Older release tarballs remain available as Forgejo release assets.
Related
- cv-on-indri — sibling service, simpler (no
try_html) - devpi-on-indri — pattern reference for indri-native services
- docs — service reference