3.7 KiB
3.7 KiB
CLAUDE.md — heleosv2 platform
Multi-tenant web hosting platform: container-per-site + ZFS-dataset-per-site, CLI-driven provisioning, decoupled per-site backup/restore. Single bare-metal host, Docker Compose per site, no orchestrator.
Read
docs/first — it is the source of truth. Start with docs/00-roadmap.md. This file is just the orientation map so a fresh session gets up to speed cheaply.
Core philosophy
- The customer is the boundary — isolation, backup, restore align on it.
- Two levels: a
customerowns manysites. Isolation/containers/DB/network are per site; grouping (one SFTP login, recursive backup, billing) is per customer. See docs/03-naming-conventions.md. - Containers isolate, they don't secure by themselves — non-root FPM, read-only rootfs, per-site networks, egress filtering, least-priv DB users.
- Each backup stream matches its change pattern — web files via ZFS
snapshot/
send; DB via automysqlbackup + rsync; logs via Loki. Never fold the DB dump into the web dataset (it bloats every incremental). - CLI/templates before UI. Prove the platform, then wrap it in a panel.
Status
- ✅ Phase 0 — design docs, ADRs, scaffold (docs/)
- ✅ Phase 1 — host baseline Ansible (platform-infra/ansible/)
- ✅ Phase 2 — platform services (Traefik, MariaDB, Forgejo) in platform-infra/stacks/
- ✅ Phase 3 — site templates & base images in site-templates/
- 🚧 Phase 4 — provisioning CLI in
control-panel/(renders templates → deployments/, creates ZFS+DB+SFTP,compose up) - ⬜ Phases 5–8 — backup/DR, observability, migration, panel
Repo map
| Path | Purpose |
|---|---|
docs/ |
Architecture, ADRs, runbooks, conventions (authoritative). |
platform-infra/ansible/ |
Phase 1 host baseline (ZFS, Docker, firewall, SSH). |
platform-infra/stacks/ |
Phase 2 base compose projects (Traefik/MariaDB/Forgejo). |
site-templates/ |
Dockerfiles + per-profile compose templates (Phase 3). |
deployments/ |
Rendered per-site configs <customer>/<site>/ (GitOps state). |
control-panel/ |
Provisioning CLI (Phase 4), panel later. |
Naming quick-ref (see docs/03)
customer+siteids;slug = <customer>-<site>(Docker/DB key).- ZFS:
tank/customers/<customer>/<site>/web; platform ontank/platform/*. - DB:
db_<customer>_<site>+ useru_<customer>_<site>on shared MariaDB. - Networks: shared
proxy(edge) +platform(DB); per-site<slug>_net.
Common commands
# Phase 1 — host baseline (from platform-infra/ansible, against the VM)
ansible-galaxy collection install -r requirements.yml
ansible-playbook site.yml # tags: base|zfs|docker|firewall|ssh
# Phase 2 — platform services (on the host, once Phase 1 is applied)
platform-infra/stacks/bootstrap-networks.sh
cd platform-infra/stacks/<svc> && cp .env.example .env && docker compose up -d
Working agreements
- Docs are source of truth. When a design decision changes, update the
relevant
docs/file and add/adjust an ADR indocs/adr/. - Never commit plaintext secrets. Only
*.enc.*(SOPS/age) are allowed;.envis git-ignored (.env.exampleis committed). See.gitignore. - Line endings: LF for scripts/Dockerfiles/YAML (enforced by
.gitattributes) — these run on Linux. - Commit per phase/step with a descriptive message; the repo is the memory.
- Environment is Windows (authoring) → Linux host (runtime). Prefer the Bash tool for POSIX one-offs.