platform/docs/05-provisioning-workflow.md
Bart Van Geyt 9f819df4d9 Phase 0: architecture docs, ADRs, and repo scaffold
Establish the design foundation for the heleosv2 multi-tenant hosting
platform before any implementation code:

- Monorepo skeleton: docs/, platform-infra/, site-templates/,
  deployments/, control-panel/ with orientation READMEs.
- docs/: roadmap index, architecture + threat model, naming conventions,
  site profiles, provisioning workflow, backup & DR runbook, repo/GitOps
  layout, and the approved architecture plan.
- docs/adr/: 9 ADRs recording the rationale for single-host Compose,
  Traefik edge, nginx+fpm split, shared MariaDB, ZFS-per-customer,
  decoupled backup streams, Forgejo, CLI-first, and SFTP-only.
- Secrets hygiene: .gitignore (only *.enc.* committed) and .gitattributes
  (LF for scripts/Dockerfiles/YAML run on the Linux host).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 12:26:00 +02:00

77 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 05 — Provisioning Workflow
How a site goes from request to live, and back off again. All steps are
operator-driven via the `control-panel` CLI in Phase 07; the customer panel
(Phase 8) calls the same operations.
## Design principle
The CLI is **declarative and idempotent**: `site.yaml` is the source of truth,
everything else is rendered from it, and re-running a command converges to the
desired state rather than erroring. Each step is individually re-runnable so a
failed provision can be resumed.
## New site — `provision`
Input: `slug`, `profile`, `domains`, profile options (see
[04](04-site-profiles.md) `site.yaml`).
1. **Validate** — slug charset/reserved-word check
([03](03-naming-conventions.md)), domains resolvable/owned, profile known.
2. **ZFS** — create `tank/customers/<slug>/web` (and `db-backups/<slug>` if the
profile uses a DB).
3. **Database** (DB profiles) — create `db_<slug>` + `u_<slug>` with least
privilege on shared MariaDB; generate password; write to `secrets.enc.yaml`
(SOPS/age).
4. **Render** — produce `deployments/<slug>/docker-compose.yml` + `.env` from the
profile template and `site.yaml`.
5. **SFTP** — create chrooted `sftp_<slug>` account bound to the web root.
6. **Commit** — commit `deployments/<slug>/` to the `deployments` repo (audit
trail; secrets committed only in encrypted form).
7. **Deploy**`docker compose up -d` in `deployments/<slug>/`. Traefik
discovers the route from labels; ACME issues the certificate.
8. **Verify** — HTTPS reachability + valid cert; for WordPress, run WP-CLI
install. Print access details.
DNS: the operator ensures the domain points at the host (pre- or post-provision;
the cert completes once DNS resolves).
## Change a site — `reconfigure`
Edit `site.yaml` (e.g. add an alias domain, bump PHP version, adjust limits),
then re-run: the CLI re-renders, re-commits, and `compose up -d` applies the
delta. TLS for new domains is automatic.
## Remove a site — `deprovision`
1. `docker compose down` (optionally `--remove-orphans`).
2. **Final backup** — take a last ZFS snapshot + final DB dump, retained per the
deprovision retention policy before deletion.
3. Drop `db_<slug>` + `u_<slug>` (after the final dump).
4. Remove the SFTP account.
5. Destroy `tank/customers/<slug>/web` (and `db-backups/<slug>`) **after** the
retention window — never immediately.
6. Remove `deployments/<slug>/` and commit.
> Destroys are gated: the CLI refuses to delete data younger than the retention
> window without an explicit `--force`, and always snapshots before destroying.
## Backup / restore
Routine backups run on a schedule (not per-command); restore is on demand. Both
are specified in the [Backup & DR runbook](06-backup-and-dr.md). CLI surface:
`backup <slug>` (ad-hoc), `restore <slug> --snapshot <name> --db <dump>`.
## CLI command summary
| Command | Action |
|---------|--------|
| `provision` | Create a new site end-to-end (steps 18). |
| `reconfigure` | Apply changes from an edited `site.yaml`. |
| `deprovision` | Tear down a site with gated, backed-up deletion. |
| `list` | Show all sites, profiles, status. |
| `backup` | Ad-hoc snapshot + DB dump for a site. |
| `restore` | Two-step restore (files + DB) for a site. |
| `rotate-secret` | Regenerate DB/SFTP credentials for a site. |
Every command is idempotent and logs to the platform log stream (Loki).