# Plan: nixos-config in drei eigenständige Repositories aufteilen Stand: 17.09.2026 — Entscheidungen aus der Plan-Review eingearbeitet. ## Ausgangslage Alle drei Maschinen (`tnix`, `pinix`, `blunix`) werden aktuell über ein gemeinsames Repository `nixos-config` verwaltet (1750 Commits, ein Flake, gemeinsame `globalServices/`, eine `secrets/secrets.nix` für alle Hosts). Ziel sind drei eigenständige Repositories, deren Grenzen der Rolle der jeweiligen Maschine folgen. Hostnamen bleiben unverändert. | Repo | Host | Rolle | | -------- | -------- | -------------------------------------------- | | `tnix` | `tnix` | persönliche Maschine (Laptop) | | `pinix` | `pinix` | persönliche, autonome Server-Infrastruktur | | `blunix` | `blunix` | gemeinsam nutzbare Plattform (`0ff.space`) | ## Rollen ### tnix - persönlich, lokal, die eigentliche Arbeitsmaschine - Konfiguration betrifft primär die eigene Arbeitsumgebung (inkl. home-manager) ### pinix - Raspberry Pi 4 (aarch64), persönlicher autonomer Server - IPv6, soll möglichst unabhängig funktionieren - hostet persönliche Dienste und Tools - **cgit** als persönlicher Git-Server (nur im pinix-Tailnet) - **eigener Identity-Stack** (Dex + LLDAP + Headscale unter `domain2`) - **Headscale ist das Admin-Tailnet**: alle drei Hosts sind Mitglied (Stand seit 14.09.2026, bleibt so) - Uplink: pinix hat die Funktionen des (offline genommenen) Mango-Routers übernommen - **`lukasrosier.com`** gehört hierher und läuft auf pinix, **IPv6-only** (bisher bewusst auf blunix — Umzug ist Teil der Aufteilung; kein IPv4-Proxy über blunix) ### blunix - VPS, **bleibt dauerhaft** als gemeinsame Plattform (Roadmap-Punkt „VPS durch IPv6 ersetzen" damit erledigt/umformulieren) - Dienste, die mit anderen Menschen geteilt werden, über `0ff.space`: Launcher/Startseite, Prosody/XMPP, xmpp-web, Forgejo, künftige Kommunikationsdienste - **eigener Identity-Stack** (Dex + LLDAP + Headscale für `0ff.space`); der blunix-Headscale ist nur für geteilte Nutzer, nicht für die Admin- Verbindung zwischen den eigenen Hosts - **Forgejo** als Git-Server ## Git: Source of Truth und Clones Jedes Repo hat sein Origin auf „seinem" System; auf den anderen Systemen liegen Clones. Bearbeitung ist überall möglich: direkt auf dem Host, oder auf `tnix` lokal bzw. agentisch per SSH, mit Remote-Build auf dem Zielhost. Maßgeblich ist immer das versionierte Origin. | Repo | Origin (Source of Truth) | Clones / Mirror | | --------------- | ------------------------------ | -------------------------------- | | `tnix` | `~/tnix` auf `tnix` | Mirror auf pinix/cgit | | `pinix` | pinix/cgit | Clone auf tnix | | `blunix` | blunix/Forgejo | Clone auf tnix | | `ereader-viewer`| pinix/cgit | Flake-Input des `pinix`-Repos | | `website` | pinix/cgit (bisher Forgejo) | Auto-Pull auf pinix | | `memory` | pinix/cgit (aus `memory/`) | Clone auf tnix | | `nixos-config` | Archiv, read-only | im Backup | ## Entscheidungen 1. **Gemeinsame Module werden kopiert**, kein viertes common-Repo. `globalServices/` (sshd, security, zsh, journald, packages, …) landet als Kopie in jedem Repo und darf pro Rolle auseinanderlaufen. Ebenso bekommt jedes Repo sein eigenes `variables.nix`/`variables-local.nix` mit nur den dort gebrauchten Optionen. 2. **Git-Historie: frischer Start.** Die neuen Repos beginnen mit einem Initial-Commit. `nixos-config` wird vorher mit dem vollständigen aktuellen Stand committet und danach read-only archiviert. 3. **Secrets pro Repo.** Jedes Repo bekommt eine eigene `secrets/secrets.nix` mit nur den eigenen Host-Keys als Empfänger; betroffene `.age`-Dateien werden kopiert und per `agenix -r` neu verschlüsselt. Geteilte Secrets (z. B. `dns-challenge`, `domain`, `mailPW`) werden pro Repo dupliziert — wo sinnvoll, später getrennt rotiert. 4. **Build-unabhängig, nicht laufzeit-unabhängig.** Jedes Repo baut ohne die anderen. Zur Laufzeit bleiben bewusste Kopplungen (siehe unten), die als Werte in `variables.nix` statt als Cross-Repo-Importe abgebildet werden. 5. **Agents (agent-codex, board-agent, orga-agent, `agents/`)** werden ins `blunix`-Repo übernommen, aber **nicht importiert** (deaktiviert). Über Reaktivierung und Repo-Zugriff wird später entschieden. 6. **GoToSocial** läuft aktuell nirgends und ist **nicht** Teil der Aufteilung — kommt danach als eigener Schritt ins `blunix`-Repo. 7. **ereaderViewer** (`path:/home/builder/ereader/viewer`) wird ein eigenes Repo auf pinix/cgit und per Git-URL als Flake-Input eingebunden. ## Bekannte Laufzeit-Kopplungen - **Admin-Tailnet:** blunix und tnix hängen am pinix-Headscale. Fällt pinix aus, ist blunix nur noch öffentlich per SSH erreichbar. - **Traefik auf blunix → pinix-Backends:** keine mehr aktiv — alle Routen dorthin sind tot und werden auskommentiert übernommen ([Inventar](docs/repo-split-inventar.md)). - **Forgejo-Hostkey** auf allen Hosts; pinix kann das blunix-Repo im Notfall klonen. SSH blunix → pinix (`nixbuild.nix`) entfällt. - **tnix-Backup-Skripte** ziehen per rsync von pinix und blunix. - **`lukasrosier.com` auf pinix:** bewusst IPv6-only, keine Kopplung an blunix. ## Backup Zentraler Ordner, als Ganzes auf einen USB-Stick kopierbar, unabhängig von der Erreichbarkeit von pinix oder blunix: ```text nixos-backup/ ├── tnix.bundle ├── pinix.bundle ├── blunix.bundle ├── ereader-viewer.bundle ├── website.bundle ├── memory.bundle └── nixos-config.bundle # Archiv ``` Umfang: **nur die Git-Repos**, vollständig mit allen Branches (`git bundle create … --all` oder `git clone --mirror`). Nicht enthalten: Flake-Inputs für Offline-Rebuilds, private Keys zum Entschlüsseln der Secrets, Dienst-Daten (die sichert weiterhin restic). ## Vorgehensweise 1. **Laufenden Stand sichern:** uncommittete Änderungen (live-intent, ereader-viewer, tailnet-dns, tnix-Configs, docs, …) in `nixos-config` committen und pushen. 2. **Inventar erstellen** ([`docs/repo-split-inventar.md`](docs/repo-split-inventar.md)): jedes Modul, jeder Service, jedes Secret, jedes Skript, jede Datei unter `docs/`, `services/`, `scripts/`, `home/`, `agents/` → Zuordnung `tnix` / `pinix` / `blunix` / kopieren / Archiv; dazu alle Cross-Host-Referenzen (`tailnetIPs.*`, Traefik-Routen, Webhooks, known_hosts, nixbuild). 3. **Neue Repos auf cgit:** `ereader-viewer` (Flake-Input umstellen), `website` (von Forgejo umziehen, inkl. `scripts/resize-image.sh`), `memory` (aus `memory/`). — *Erledigt 17.09.2026:* alle drei unter `/var/lib/git` angelegt; `ereader-viewer` frisch importiert und als `git+file`-Input eingebunden (pinix-Switch ergab dasselbe System); `website` als Mirror aller Branches, Forgejo-Kopie bleibt bis Schritt 5 parallel und synchron (Auto-Pull auf blunix); `memory` per `git subtree split`. 4. **tnix als Pilot:** Repo aufbauen, Muster für kopierte globalServices, `variables.nix` und `secrets.nix` festlegen. Rebuild auf tnix, Origin unter `~/tnix`, Mirror auf cgit. — *Erledigt 17.09.2026* (`~/tnix` @ `0d77a25`). Festgelegtes Muster für pinix/blunix: - flaches Layout ohne `hosts//`: `configuration.nix`, `globalServices/` (nur tatsächlich importierte Kopien, ohne `secretFiles.nix`), `localServices/`, `user/`, `secrets/`, `tests/` - `variables.nix` nur mit den Optionen, die das Repo liest - `secrets/secrets.nix` nur mit eigenen Keys, `.age`-Dateien per `agenix -r` neu verschlüsselt, Inhalte per `agenix -d` gegengeprüft - `flake.lock` aus `nixos-config` übernehmen, damit nixpkgs-Revisionen gleich bleiben; vor dem Switch `diff-closures` gegen das laufende System (Pilot-Check) - Mirror: Bare-Repo auf cgit + `post-commit`-Hook (`git push --mirror`) Ergebnis-Diff tnix: nur 15 ungenutzte Secrets weg, `fastpi` aus `/etc/hosts`, wpa-Units mit neuen Restart-Triggern. `switch` sauber, WLAN/Tailnet/SSH/cgit danach geprüft. tnix wird ab jetzt nur noch aus `~/tnix` deployt; `hosts/tnix` hier ist eingefroren. 5. **pinix:** Repo aufbauen, `lukasrosier.com` von blunix übernehmen (Auto-Pull-Hook für das `website`-Repo). Website-Bilder aus `/var/www/website-data` (von blunix kopiert am 17.09.) mit Verzeichnis-Listing ausliefern, `data.0ff.space`-URLs im `website`-Repo umstellen, Default-Ziel von `scripts/resize-image.sh` anpassen; danach Nachzügler von blunix per rsync abgleichen. — *Erledigt 17.09.2026 bis auf den letzten DNS-Schritt* (Repo `pinix` @ `e9cf08b` auf cgit, Arbeitskopie `~/pinix` auf tnix, Build-Verzeichnis `pinix:/home/drone/pinix-build`): - pinix läuft aus dem neuen Repo; `diff-closures` vorher zeigte nur erwartete Änderungen. Headscale scheiterte beim Switch einmal am gleichzeitigen Traefik-Neustart (OIDC-Discovery EOF) und lief beim automatischen Restart; danach `running`, keine failed Units. - Dex/Headscale-Client-Secret neu generiert (nicht mehr mit blunix geteilt), gegen Dex' Token-Endpunkt geprüft (richtig 400, falsch 401). - Website: `website.nix` mit `post-receive`-Hook in `website.git` (Branch `dev`, der auch auf blunix live war); Bilder unter `/pictures/` und `/booklet.pdf` aus `/var/www/website-data`. Im `website`-Repo URLs relativ gemacht (`df5f230`); alle 26 verlinkten Dateien 200, von blunix aus über pinix' öffentliches IPv6 mit gültigem Zertifikat getestet. Forgejo-Kopie von `website` ist ab hier veraltet (Archiv in Schritt 7). - DNS: Cloudflare-Proxy bleibt (Entscheidung 17.09.). Apex hat MX/NS/TXT, daher proxied AAAA statt CNAME für `lukasrosier.com` und `www`, gepflegt von `wan-dns-update` (folgt der NAT66-Adresse). - **Offen:** die alten A-Einträge (`23.88.33.137`, blunix) für `lukasrosier.com` und `www` löschen. Solange sie existieren, bevorzugt Cloudflare blunix als Ursprung — Besucher sehen noch die alte Kopie mit `data.0ff.space`-Bildern (funktioniert). Nach dem Löschen `data.`-Kopie der Bilder erst in Schritt 6 entfernen. - Altes `.git` der Website-Checkout auf pinix liegt unter `/home/drone/website-checkout-git.bak-20260917`. - *Nachtrag 17.09.2026:* A-Einträge gelöscht (auf ausdrückliche Anweisung). Über IPv4 (Cloudflare) und IPv6 liefert jetzt pinix aus (`version.json` = `df5f230`, Bilder 200). Rebuild lokal auf pinix (rsync-Zyklus). Origin auf cgit, Clone auf tnix. 6. **blunix** (zuletzt, vorsichtig — Aussperr-Risiko): Repo aufbauen, Website und Agents entfernen bzw. deaktivieren, Traefik-Routen auf pinix-Backends bereinigen. Rebuild auf blunix. Origin auf Forgejo, Clone auf tnix. — *Erledigt 17.09.2026* (`lukas/blunix` auf Forgejo, privat per Push-to-Create, @ `fd4c876`; Checkout `/home/drone/blunix`, Clone `~/blunix` auf tnix): - Agents, orga-Dienste, tasks, graphify-refresh, oauth2-proxy, `website-production` und `nixbuild.nix` sind aus; tote Routen, Dex-Clients, AdGuard-Rewrites und die pinix-IP in Forgejos Webhook-Allowlist auskommentiert. Closure ~1 GB kleiner (Chromium, numpy & Co. hingen an den Agents). - Aussperr-Check vor dem Switch: sshd, Firewall, Netz, tailscaled unverändert (nur SSH-*Client*-Config/known_hosts durch `nixbuild.nix`). `hosts/blunix/localServices/sshd.nix` war nie importiert (lauscht auf alten 100.64-Adressen) — Archiv. - Korrektur zum Inventar: `bindPW.age` wird auf blunix gelesen (Prosody-Include `/run/agenix/0ff.space.cfg.lua`), ist mitgenommen. - Headscale scheiterte beim Switch wie auf pinix einmal an der gleichzeitig neu startenden Dex/Traefik-Kette und lief beim Restart. Danach `running`, keine failed Units; öffentlich geprüft: `0ff.space`, `git.`, `dex.`, `lldap.`, `head.`, `data.`, `hdm.`, `upload.`, XMPP 5222/5269, intern `schema.`. - **Befund pinix (offen):** Seit dem pinix-Switch um 13:08 hatte der technische Node `pinix-dns` (`tailscaled-pinix`) keine Control-Verbindung mehr (`PollNetMap` gegen `127.0.0.1:443`), der Datenpfad zu cgit lief weiter. `systemctl restart tailscaled-pinix` hat es behoben. Der Prozess sieht trotz `BindReadOnlyPaths` die Host-`/etc/hosts` (dex./head. → 127.0.0.1); Mechanismus nicht geklärt. Nach pinix-Switches, die `/etc/hosts` ändern, prüfen. - Die Admin-Sitzung unter `/home/drone/nixos-config` auf blunix ist unverändert; blunix wird ab jetzt nur noch aus `/home/drone/blunix` deployt. - Die Bilder-Kopie unter `blunix:/var/www/data/external/pictures` bleibt (Entscheidung 17.09.2026). 7. **nixos-config archivieren** (Forgejo: read-only/archiviert), Checkouts unter `/home/drone/nixos-config` durch die neuen Repos ersetzen. — *Erledigt 17.09.2026* (dieser Commit ist der letzte): - Alle `nixos-config*`-Verzeichnisse auf blunix (6, inkl. Wiki-Checkout) und pinix (10) nach `/home/drone/archiv-nixos-config-20260917/` verschoben, nicht gelöscht. Uncommittete Stände darin waren alte Zwischenstände (letzter Commit 12.09.), inhaltlich längst in der Historie. Ersetzt durch `/home/drone/blunix` (Clone) bzw. `/home/drone/pinix-build` (rsync-Ziel). - Archiv-Hinweis oben in README.md, AGENTS.md, CLAUDE.md. - Danach: `git push --mirror` auf pinix-cgit (`nixos-config.git`), dann `nixos-config` und `website` auf Forgejo archiviert. - Die Plan-Fortschreibung für Schritt 8 und 9 liegt ab hier in `~/tnix/docs/repo-split/` (tnix ist die Admin-Arbeitsmaschine). 8. **Backup-Skript** für `nixos-backup/` schreiben und testen: Ordner auf USB kopieren, auf einer anderen Maschine aus den Bundles klonen. 9. **Doku nachziehen:** README/CLAUDE.md/AGENTS.md pro Repo, `docs/roadmap.md` (VPS-Punkt), `docs/repos.md`. ## Weitere Festlegungen - **LLDAP:** Nutzer und Gruppen bleiben so, wie sie aktuell auf den Systemen aktiv sind (blunix-LLDAP für `0ff.space`, pinix-LLDAP für `domain2`) — keine Migration im Zuge der Aufteilung. - **Doku zu Mango** (CLAUDE.md, `docs/networking.md` u. a.) ist veraltet und wird in Schritt 9 nachgezogen. ## Designziel ```text tnix = meine persönliche Maschine pinix = meine persönliche/private Server-Infrastruktur blunix = gemeinsam nutzbare Plattform-Infrastruktur ``` Die technische Struktur — Repo-Grenzen, Git-Hosting, Identität, Secrets — folgt dieser Trennung.