Commit graph

7 commits

Author SHA1 Message Date
Bart Van Geyt
fe4cbbe36a Phase 4: provisioning CLI (heleosctl)
Python control-panel package driving the full provisioning flow from a
site's site.yaml (docs/05):

- provision: ZFS web dataset + ownership, per-site DB + least-priv user,
  generated .env encrypted to secrets.enc.yaml (SOPS/age), render the
  profile templates + persist site.yaml, per-customer chrooted SFTP
  account, docker compose up.
- deprovision (gated: data destroyed only with --purge, after a final
  backup), backup (ZFS snapshot + mariadb-dump), restore (rollback +
  import), render (preview), list.

Design: one command/file runner with a real --dry-run (prints every
action, redacts secrets); idempotent steps; Config + Site validation
mirroring docs/03; passwords never logged.

Modules: cli, config, naming, context, render, runner, zfs, database,
secrets, sftp, compose, provision, backup. Plus pyproject (heleosctl
entry point), config.example.yaml, an example site, and a README.

Tests: 22 pure-logic unit tests (naming, config validation, template
render across all profiles + db on/off) — all passing. Full provision and
deprovision verified end-to-end in --dry-run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 17:18:36 +02:00
Bart Van Geyt
f2ab25c99f Update CLAUDE.md status: Phases 1-3 complete, Phase 4 next
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 17:06:42 +02:00
Bart Van Geyt
edfb4c44b8 Phase 3: site templates & base images
Add the building blocks the provisioning CLI renders per site.

Base images (site-templates/images):
- php-fpm: non-root (www-data) php:<ver>-fpm-alpine with pdo_mysql, mysqli,
  gd, intl, zip, opcache, exif; tuned php.ini + pool; built per PHP version.
- nginx: hardened nginx:1.27-alpine with shared security + fastcgi snippets;
  per-site server block mounted at runtime.
- build.sh: build + Trivy-scan (+ optional push) for both images.

Profile templates (site-templates/profiles), Jinja2 rendered:
- static, redirect (tiny nginx 301/302), custom-php (nginx + our php-fpm,
  optional DB), wordpress (nginx + official wordpress-fpm, DB required,
  upload-exec denied). Only nginx carries Traefik labels and joins proxy;
  php-fpm uses the private <slug>_net and joins platform only when a DB is
  needed. Secrets stay in a git-ignored .env, not the compose.

CI: .forgejo/workflows/images.yml builds/scans images (gitleaks + Trivy).
README documents the render context and the Phase 4 web-root ownership item.

Templates validated: all profiles render to valid compose YAML across the
database on/off branches and single/multi-domain host rules.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 17:06:25 +02:00
Bart Van Geyt
41a01c60ef Phase 2: platform service stacks + CLAUDE.md
Add base Docker Compose projects under platform-infra/stacks, using the
Phase 1 ZFS platform datasets and shared networks:

- bootstrap-networks.sh: idempotent creation of shared `proxy` (edge) and
  `platform` (internal) Docker networks.
- traefik: edge router with TLS/ACME (HTTP-01), global HTTP->HTTPS redirect,
  file-based security-headers/TLS middlewares, and a basic-auth dashboard.
  Docker access via a least-privilege tecnativa/docker-socket-proxy instead
  of mounting docker.sock directly.
- mariadb: shared instance on tank/platform/mariadb, utf8mb4, tuned; not
  published to the host (internal `platform` network only).
- forgejo: Git + container registry over HTTPS (SSH disabled to avoid extra
  inbound ports), SQLite backend, data on tank/platform/forgejo.

Each stack ships a committed .env.example (real .env is git-ignored) and the
stacks README documents bring-up order, secrets, and verification.

Also add root CLAUDE.md so fresh sessions orient from files cheaply:
philosophy, doc pointers, naming quick-ref, repo map, commands, agreements.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 16:58:18 +02:00
Bart Van Geyt
d715244b76 Phase 1: Ansible host baseline for Ubuntu VM
Idempotent host configuration targeting Ubuntu 24.04 with ZFS on a
dedicated second disk. Role-based platform-infra/ansible:

- base: apt packages, timezone, unattended security upgrades.
- zfs: install ZFS, create pool on a dedicated disk (guarded against
  wiping a non-empty disk), create platform datasets + customers parent
  per docs/03; docker dataset mounted at /var/lib/docker.
- docker: Docker Engine + Compose plugin, daemon.json written before first
  start so the native zfs storage driver initializes on the ZFS data-root;
  per-site network address pool preconfigured.
- firewall: nftables inbound default-deny in a dedicated table that never
  flushes Docker's rules; container outbound SMTP blocked via a DOCKER-USER
  jump applied by a systemd oneshot.
- ssh_hardening: key-first SSH with an anti-lockout assertion, config
  validation gate, and the sftponly group for Phase 4 SFTP accounts.

Includes ansible.cfg, requirements.yml, inventory example, group_vars with
safety notes, and a run guide. Real inventory (hosts.yml) is git-ignored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 12:45:42 +02:00
Bart Van Geyt
e5ff798dd4 Refine to nested customer -> site model
Adopt a two-level ownership model: a customer owns many sites, with
isolation/containers/DB/backup at the site level and grouping (one SFTP
login, recursive backup, billing, bulk delete) at the customer level.

- 03-naming-conventions: rewritten for customer/site ids and slug =
  <customer>-<site>; nested ZFS, per-customer SFTP chroot, deployments
  mirror the nesting.
- Propagated paths through docs 01, 04, 05, 06, 07 and deployments/README.
- ADR 0005 retitled/updated to per-site datasets nested under customer.
- architecture-plan.md: note pointing to doc 03 as authoritative on naming.

Clarifies subdomains: same-app subdomains are aliases on one site; a
separate-app subdomain is its own isolated site under the same customer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 12:37:39 +02:00
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