From 9cd471d66ec68b9a4c6356378860bcd571efec74 Mon Sep 17 00:00:00 2001 From: Herb Date: Mon, 13 Jul 2026 13:11:35 +0200 Subject: [PATCH] Konventions-Geruest anlegen (CLAUDE.md, docs, Obsidian-Vault) Projekt-CLAUDE.md mit Status, Entscheidungslog E-001..E-006, Architektur mit Mermaid-Diagrammen, COCKPIT/CHANGELOG als Vault-Start. Alt-Doku (CLAUDE_KONTEXT.md, ZUSAMMENFASSUNG_TODO.md) darin aufgegangen. Co-Authored-By: Claude Fable 5 --- .gitignore | 8 +++++ CHANGELOG.md | 22 +++++++++++++ CLAUDE.md | 50 +++++++++++++++++++++++++++++ COCKPIT.md | 31 ++++++++++++++++++ docs/architektur.md | 78 +++++++++++++++++++++++++++++++++++++++++++++ docs/decisions.md | 62 +++++++++++++++++++++++++++++++++++ 6 files changed, 251 insertions(+) create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 CLAUDE.md create mode 100644 COCKPIT.md create mode 100644 docs/architektur.md create mode 100644 docs/decisions.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a3da8b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# Obsidian-Vault-Metadaten (Konvention: Projektordner = Vault) +.obsidian/ + +# Lokale Claude-Code-Einstellungen +.claude/settings.local.json + +# Ansible +*.retry diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e7e0d8f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,22 @@ +# Changelog + +## 2026-07-13 — Projektgruendung & Kurswechsel auf Pull + +- Alter git-loser Ordner `~/ansible-schule` (Jan/Feb 2026) nach + `~/projekte/schul-laptops` verschoben, Konventions-Geruest angelegt + ([[CLAUDE]], [[docs/decisions]], [[docs/architektur]], [[COCKPIT]]). +- Kernentscheidungen E-001 bis E-006 dokumentiert: **ansible-pull statt Push** + (Schul-WLAN blockiert Push), Hetzner nur als Git-Host (kein Image, kein Mirror), + HTTPS-Pull + SSH-Fallback, Jahres-Reimage ohne Stick (Clonezilla Batch, + Hostname bleibt erhalten), Admin-Key nur auf laptop03. +- Gitea-Repo `admin/schul-laptops` angelegt, initialer Push. +- Alt-Doku (CLAUDE_KONTEXT.md, ZUSAMMENFASSUNG_TODO.md) in die neue Struktur + ueberfuehrt und entfernt. + +## Vorgeschichte (aus Alt-Doku uebernommen) + +- **2026-02-05:** update-ips.sh (mDNS) + inventory.yml fuer laptop01–16. +- **2026-02-01:** Master-Image von laptop03 erstellt; Test-Restore auf laptop10 + + Ansible-Verbindung erfolgreich; automatisierter Clonezilla-Stick gebaut. +- **2026-01-29:** Ansible-Grundgeruest (Playbooks ping/update/install-software/ + reboot/set-hostname), first-boot-setup.sh, Benutzer puettmann/schueler. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..aa2dfc2 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,50 @@ +# schul-laptops — Projektstatus + +Status: aktiv · Stand: 2026-07-13 + +## Worum es geht + +Zentrale Verwaltung von 12–16 Linux-Mint-Schullaptops. Zwei Standbeine: + +1. **Laufende Updates per `ansible-pull`** (Normalfall): Die Laptops ziehen sich + Konfiguration/Software selbst aus Gitea (`git.lehrstun.de`, HTTPS) — Push per + Ansible scheitert am Schul-WLAN (Client-Isolation). +2. **Komplett-Reimage ~1×/Jahr** von der externen Platte `DEZNTRSICHERUNG` + (Clonezilla, neuestes Image gewinnt, Hostname bleibt erhalten). + +Master-Laptop: **laptop03** (dieser Rechner). Details: `docs/architektur.md`. + +## Quickstart + +```bash +cd ~/projekte/schul-laptops + +# Aenderung an den Laptops ausrollen: Repo aendern + pushen — mehr nicht. +git add -A && git commit -m "..." && git push +# Die Laptops ziehen es beim naechsten Timer-Lauf (Boot bzw. <=30 min). + +# Pull-Lauf lokal testen (laptop03): +sudo systemctl start ansible-pull.service && journalctl -u ansible-pull -f +``` + +Benutzer auf den Laptops: `puettmann` (Admin, passwordless sudo), `schueler` (ohne Adminrechte). + +## Blocker + +- Keine. + +## Naechste Schritte + +- [ ] Teil A: Server — DNS `git.lehrstun.de`, Nginx-vHost, Deploy-Key +- [ ] Teil B: Pull-Mechanik (local.yml, schul-pull.sh, systemd-Units, first-boot) +- [ ] Teil C: Jahres-Reimage (Clonezilla lokal, Boot-Check, Mini-Menue) +- [ ] Teil D: Aktivierung auf laptop03 + Verifikation +- [ ] Master-Image erstellen, Rollout auf laptop01–16 (auch laptop10 neu) + +## Hinweise + +- Plan/Entscheidungen: `docs/decisions.md` · Historie: `CHANGELOG.md` · Vault-Start: `COCKPIT.md` +- Legacy-Push-Setup (inventory.yml, update-ips.sh, playbooks/) funktioniert nur im + Heimnetz — siehe README.md. +- Auf laptop03 liegt auch das RS41ng-Wettersondenprojekt (`~/RS41ng/`), Vorsicht + beim Image-Erstellen: laptop03 bespielt sich nie selbst (reimage-check deaktiviert). diff --git a/COCKPIT.md b/COCKPIT.md new file mode 100644 index 0000000..6796465 --- /dev/null +++ b/COCKPIT.md @@ -0,0 +1,31 @@ +--- +stand: 2026-07-13 +--- + +# 🛰️ Cockpit — schul-laptops + +## Status auf einen Blick + +| | | +|---|---| +| **Status** | aktiv — Umbau auf ansible-pull laeuft | +| **Master** | laptop03 (dieser Rechner) | +| **Geklont** | nur laptop10 (Test, Feb 2026) — Rollout steht aus | +| **Repo** | `ssh://git@46.225.114.15:2222/admin/schul-laptops.git` | +| **Pull-URL (Laptops)** | `https://git.lehrstun.de/admin/schul-laptops.git` | +| **Images** | externe Platte `DEZNTRSICHERUNG`, `schule-laptop-JJJJ-MM-TT` | + +## Einstiege + +- [[CLAUDE|Projektstatus (Quelle der Wahrheit)]] +- [[docs/architektur|Architektur + Diagramme]] +- [[docs/decisions|Entscheidungslog (E-001 …)]] +- [[CHANGELOG|Sitzungs-Historie]] +- [[README|Bedienung & Befehle]] +- [[ANLEITUNG_NACH_KLONEN|Anleitung nach dem Klonen]] +- [[CLONEZILLA_AUTOMATISCH|Clonezilla-Stick (Doku)]] + +## Merksatz + +> Aenderung an allen Laptops = Repo aendern + `git push`. Mehr nicht. +> Komplett-Image nur ~1×/Jahr: Platte anstecken, einschalten, warten. diff --git a/docs/architektur.md b/docs/architektur.md new file mode 100644 index 0000000..9e43c76 --- /dev/null +++ b/docs/architektur.md @@ -0,0 +1,78 @@ +# Architektur + +Stand: 2026-07-13 + +## Ueberblick + +Zwei getrennte Wege: **laufende Updates** (haeufig, automatisch, uebers Netz) und +**Komplett-Reimage** (~1×/Jahr, von der externen Platte, ohne Netz). + +```mermaid +flowchart LR + subgraph Herb["Herb (laptop03 = Master)"] + REPO["~/projekte/schul-laptops
(git)"] + end + + subgraph Hetzner["Hetzner 46.225.114.15 (nur Git!)"] + GITEA["Gitea
admin/schul-laptops (public)"] + NGINX["Nginx
git.lehrstun.de:443"] + NGINX --> GITEA + end + + subgraph Laptop["Schul-Laptop (laptop01–16)"] + TIMER["systemd-Timer
Boot + alle 30 min"] + PULL["schul-pull.sh →
ansible-pull local.yml"] + TIMER --> PULL + CHECK["reimage-check.service
(frueh im Boot)"] + GRUB["GRUB-Eintrag
Schul-Neuinstallation
(Clonezilla toram)"] + CHECK -- "Platte + neueres Image" --> GRUB + end + + REPO -- "git push (SSH :2222)" --> GITEA + PULL -- "HTTPS 443 (Standard)" --> NGINX + PULL -. "Fallback: SSH :2222
Deploy-Key (read-only)" .-> GITEA + + subgraph Platte["Externe Platte DEZNTRSICHERUNG"] + IMG["schule-laptop-JJJJ-MM-TT/
(mehrere, neuestes gewinnt)"] + end + + GRUB -- "Mini-Menue: AUFSPIELEN (auto) /
IMAGE ERSTELLEN / Abbrechen" --> IMG +``` + +## Ablauf Reimage (ohne Stick) + +```mermaid +sequenceDiagram + participant P as Platte (DEZNTRSICHERUNG) + participant L as Laptop (altes System) + participant C as Clonezilla (toram, aus /boot/clonezilla) + + Note over L: Platte anstecken, einschalten + L->>P: reimage-check: neuestes Image > /etc/schul-image-version? + L->>L: grub-reboot "Schul-Neuinstallation" + Reboot + C->>L: Hostname aus altem /etc/hostname lesen + Note over C: Mini-Menue, "AUFSPIELEN" startet nach ~20 s + C->>L: ocs-sr restoredisk (Batch, ohne Nachpruefung) + C->>L: Hostname, SSH-Host-Keys, Machine-ID,
Versionsdatei schreiben; Admin-Key loeschen (ausser laptop03) + Note over L: Poweroff → naechster Boot: fertig, Pull laeuft weiter +``` + +## Komponenten im Repo + +| Pfad | Zweck | +|---|---| +| `local.yml` | ansible-pull-Playbook (Updates, Pakete, Selbstverwaltung der Mechanik) | +| `group_vars/all.yml` | Paketliste u.a. Variablen | +| `files/schul-pull.sh` | Pull-Wrapper: HTTPS zuerst, SSH-Fallback, Journal-Log | +| `files/ansible-pull.service/.timer` | systemd-Units (Boot + 30 min, RandomizedDelay) | +| `files/first-boot-setup.sh` | Einmalig nach Erstinstallation: Hostname etc. | +| `files/reimage-check.*` | Boot-Check: Platte erkannt → Reboot in Clonezilla | +| `files/clonezilla/` | Mini-Menue + ocs-sr-Batch-Skripte (Restore/Save) | +| `playbooks/`, `inventory.yml`, `update-ips.sh` | Legacy-Push (nur Heimnetz) | + +## Sicherheit + +- Repo public (nur Lesen), enthaelt keine Secrets. +- Privater Gitea-Admin-Key existiert nur auf laptop03 (E-005). +- Deploy-Key (Fallback) ist read-only und liegt unter `/root/.ssh/` (600). +- laptop03: `reimage-check` deaktiviert — der Master ueberschreibt sich nie selbst. diff --git a/docs/decisions.md b/docs/decisions.md new file mode 100644 index 0000000..2f5365a --- /dev/null +++ b/docs/decisions.md @@ -0,0 +1,62 @@ +# Entscheidungslog + +Format: E-NNN · Datum · Entscheidung · Begruendung + +## E-001 · 2026-07-13 · Pull statt Push + +**Entscheidung:** Verwaltung der Laptops per `ansible-pull` (Laptops holen sich das +Repo selbst), nicht mehr per Ansible-Push vom Controller. + +**Begruendung:** Das Schul-WLAN (Client-Isolation) blockiert mDNS und SSH zwischen +den Geraeten — Push und `update-ips.sh` funktionieren dort prinzipbedingt nicht. +Pull braucht nur ausgehendes HTTPS. Das Push-Setup bleibt als Legacy fuers Heimnetz. + +## E-002 · 2026-07-13 · Kein Image und kein Paket-Mirror auf dem Hetzner + +**Entscheidung:** Der Hetzner-Server haelt nur das Git-Repo (Gitea) und den +HTTPS-Zugang (`git.lehrstun.de` via Nginx). Clonezilla-Images bleiben komplett auf +der externen Platte `DEZNTRSICHERUNG`; kein eigener APT-Mirror, keine eigene Distro. + +**Begruendung:** 75-GB-Server zu klein fuer Images/Mirror; Restore uebers Schul-WLAN +waere um ein Vielfaches langsamer als von der USB3-Platte (~5–10 min). Reimage ist +nur ~1×/Jahr noetig. Sicherheitsupdates kommen direkt von den offiziellen +Mint/Ubuntu-Servern. + +## E-003 · 2026-07-13 · Repo-Zugriff: HTTPS als Standard, SSH-Deploy-Key als Fallback + +**Entscheidung:** Laptops pullen per HTTPS von `git.lehrstun.de` (Port 443, Repo +oeffentlich lesbar); Fallback SSH Port 2222 mit dediziertem Read-only-Deploy-Key. + +**Begruendung:** Schulnetze blockieren oft alles ausser 80/443. Das Repo enthaelt +keine Secrets (geprueft). Kein Token in URLs (globale Regel). + +## E-004 · 2026-07-13 · Jahres-Reimage ohne Stick, Clonezilla im Batch-Modus + +**Entscheidung:** Master-Image enthaelt Clonezilla-Live unter `/boot/clonezilla/` +(GRUB-Eintrag, `toram`). Ein Boot-Check-Dienst erkennt die angesteckte Platte mit +neuerem Image und startet den Reimage-Vorgang. Eigenes Mini-Menue +(„AUFSPIELEN“ vorausgewaehlt mit ~20 s Countdown / „IMAGE ERSTELLEN“ / Abbrechen) +statt Clonezilla-TUI; `ocs-sr` direkt im Batch-Modus, alle Sicherheitsschranken und +die sektorweise Nachpruefung abgeschaltet. + +**Begruendung:** 12× identische Hardware — Pruefungen bringen wenig, kosten Zeit; +Fehlerfaelle behandelt Herb von Hand. Der Hostname bleibt erhalten, indem das +Restore-Skript ihn vor dem Ueberschreiben aus dem alten System liest. +Versionsvergleich (`/etc/schul-image-version` vs. Datumsname des Images) +verhindert Reimage-Schleifen. laptop03 (Master) bespielt sich nie selbst. + +## E-005 · 2026-07-13 · Privater Admin-Key nur auf laptop03 + +**Entscheidung:** `first-boot-setup.sh` und das Restore-Skript loeschen den privaten +SSH-Key von `puettmann` auf allen Laptops ausser laptop03. Fuer den Pull-Fallback +gibt es einen separaten Read-only-Deploy-Key unter `/root/.ssh/`. + +**Begruendung:** Der Key auf laptop03 ist der Gitea-Admin-Key („herb-local“) — er +wuerde sonst mit dem Image auf alle Schueler-Laptops geklont. + +## E-006 · 2026-07-13 · Projekt nach Konventionen unter ~/projekte/schul-laptops + +**Entscheidung:** Alter git-loser Ordner `~/ansible-schule` ist vollstaendig in +`~/projekte/schul-laptops` aufgegangen (verschoben); git + Gitea-Remote (SSH), +Projektordner ist zugleich Obsidian-Vault (COCKPIT.md, CHANGELOG.md, +`.obsidian/` gitignored).