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>
77 lines
3.4 KiB
Markdown
77 lines
3.4 KiB
Markdown
# 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 0–7; 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 1–8). |
|
||
| `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).
|