- Python 86%
- Jupyter Notebook 7.8%
- Shell 4%
- Dockerfile 2.2%
hermes/Dockerfile trug die Forgejo-Fork-URL (192.168.178.92:3000) als eigenen Literal, unabhängig von deployment/build-and-push.sh's REGISTRY_HOST/REGISTRY_ORG (docker:3000/iris) — beide meinen dieselbe Instanz, waren aber bereits auseinandergedriftet. Jetzt ein Build-ARG (HERMES_AGENT_REPO_URL), das build-and-push.sh explizit aus REGISTRY_HOST/REGISTRY_ORG ableitet — nur noch eine Stelle kennt die Registry-Adresse. Behebt nicht den in Testserver-2 sichtbaren "diverging branches"-Fehler selbst (git-Historie dieser einen Instanz vs. Fork-main) — das ist ein separates, instanzspezifisches Problem, kein Hardcoding-Bug. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RA7qAhGpR1Ct2sABqNNhNo |
||
|---|---|---|
| deployment | ||
| iris-server | ||
| scripts | ||
| .gitignore | ||
| CLAUDE.md | ||
| CLIENT-LOCAL-EXECUTION.md | ||
| PLAN.md | ||
| README.md | ||
| ROUTES.md | ||
| SERVER-ADMIN.md | ||
Iris Linux-Server — Installation
Dieses Dokument beschreibt, wie ein komplett neuer Iris-Linux-Server aus den Quellen in
diesem Verzeichnis aufgesetzt wird — z. B. auf einem zweiten Docker-Host oder als Ersatz für den
bestehenden. Für Hintergrund/Architektur siehe CLAUDE.md, für den
Rollout-/Feature-Stand PLAN.md, für die tägliche Redeploy-Routine gegen den
bereits laufenden Server den entsprechenden Abschnitt in CLAUDE.md.
1. Voraussetzungen auf dem Zielhost
- Docker + Docker-Compose-Plugin (
docker compose, nicht das altedocker-compose). - Optional
qrencode(apt-get install qrencode) — für den QR-Code beim iOS-Pairing (Schritt 6). Fehlt es, gibtpairing-info.shdas Pairing-JSON stattdessen als reinen Text aus, den man von Hand ins iOS-Pairing-Feld eintippt/kopiert. - Ein SSH-Zugang zum Host für die Einrichtung selbst — danach läuft die Administration über den
IrisClient, sieheSERVER-ADMIN.md.
2. Code auf den Host bringen
Entweder direkt klonen:
git clone http://<forgejo-host>:3000/iris/iris-linux-server.git /docker/iris-server
oder von einer lokalen Entwicklungskopie synchronisieren (identisch zum bestehenden
Redeploy-Workflow in CLAUDE.md) — --exclude='.env' ist Pflicht, sobald auf dem Zielhost schon
eine .env existiert (Schritt 3), sonst überschreibt ein späterer Redeploy die host-spezifischen
Werte:
rsync -av --exclude='.git' --exclude='.env' \
~/Documents/2ndbrain/linux-server/iris-server/ \
<user>@<neuer-host>:/docker/iris-server/
<user> ist ein gewöhnlicher, per usermod -aG docker in die Docker-Gruppe aufgenommener
Nutzer, kein root — siehe SERVER-ADMIN.md Punkt 4. docker-compose.ymls Bind-Mount-Quellen
sind seit dem .env-Umbau (siehe Schritt 3) nicht mehr auf /docker/iris-server/ fest verdrahtet
— nur pairing-info.sh leitet seinen Datenpfad weiterhin relativ zur eigenen Skript-Position ab,
funktioniert also unabhängig vom gewählten Basisverzeichnis.
3. Host-spezifische Werte in .env setzen
Host-spezifische Werte liegen NICHT mehr direkt in docker-compose.yml (Stand vor 2026-08-31),
sondern in einer pro Host individuellen .env (Docker Compose liest sie automatisch aus
demselben Verzeichnis). Einmalig aus der committeten Vorlage anlegen:
cd /docker/iris-server
cp .env.example .env
Dann die Werte für diesen Host setzen (siehe .env.example's Kopfkommentar für Details):
| Variable | Bedeutung |
|---|---|
IRIS_SERVER_HOST |
Echte LAN-IP des neuen Hosts — geht als SubjectAlternativeName ins selbstsignierte TLS-Leaf-Zertifikat (app/certs.py). Muss die Adresse sein, unter der Clients den Server tatsächlich erreichen. |
IRIS_DOCKER_DIR |
Basisverzeichnis für Container-Daten auf diesem Host (Standard: /docker/iris-server — muss zu Schritt 2 passen). |
IRIS_VAULT_DIR |
Obsidian-Vault-Wurzel — bewusst UNABHÄNGIG von IRIS_DOCKER_DIR, kann z. B. auf einem separaten NAS-Mount liegen. |
APP_UID/APP_GID/DOCKER_GID |
Nicht von Hand setzen — siehe Schritt 3a. |
LLM_BASE_URL/LLM_MODEL (Backend für vault-admin enrich, LLM-gestützte Kurzbeschreibungen —
unabhängig vom eigentlichen Agent-Backend, das später per POST /config gesetzt wird) stehen
weiterhin direkt in docker-compose.yml (Services hermes/hermes-scheduled), zeigen aktuell
auf ein bestimmtes Ollama im LAN — ggf. auf ein für den neuen Host erreichbares Backend ändern.
3a. Host-User/Docker-GID ermitteln
Der server-Container läuft als non-root (iris, UID/GID passend zum echten Host-Login) und
braucht dafür zusätzlich APP_UID/APP_GID/DOCKER_GID in .env — niemals von Hand auf
einen festen Wert wie 1000 setzen, das bricht auf jedem Host mit einem anderen Admin-Login.
Stattdessen live ermitteln (läuft idempotent, auch bei jedem späteren Redeploy erneut
ausführbar):
./scripts/detect-host-env.sh
Siehe CLAUDE.md, Abschnitt "server läuft als non-root", für die volle Begründung — u. a.
warum hermes/hermes-scheduled/tunnel bewusst weiterhin als root laufen.
4. Erststart
cd /docker/iris-server
docker compose up -d --build
Auf einem leeren /data-Volume greift entrypoint.sh/entrypoint.pys "erster Start"-Zweig:
docker-entrypoint.shbringt/datain einen für den non-rootiris-Prozess beschreibbaren Zustand (Root→gosu-Privilegien-Drop, siehe Schritt 3a) — läuft bei jedem Start, kein Sonderfall fürs erste Mal,- eigene CA + Leaf-Zertifikat werden erzeugt (
app/certs.py), - ein Bearer-Token wird generiert und persistiert (
app/secrets_store.py), - Hermes' Basis-Config/Skills sowie
SOUL.mdwerden aus dem Image-Seed kopiert (in BEIDE Hermes-Container,iris-hermesundiris-hermes-scheduled), - die idempotenten Hermes-Quellcode-Patches laufen (
hermes/patch_hermes.py).
Alle fünf Container sollten danach laufen (iris-server, iris-hermes,
iris-hermes-scheduled, iris-tunnel, iris-bgutil-provider):
docker compose ps
5. Verifizieren
curl -sk https://<neuer-host>:8765/health
Erwartete Antwort (Shape muss zu RemoteServerClient.swifts Erwartung passen):
{"status":"ok","version":"0.1.0","job_count":0,"jobs_version":0,"notifications_version":0,
"vault_root":"","available_agents":{"hermes":false,"claudeCode":false,"opencode":false},
"companion_chat_version":0,"qwen_voice_version":0,"platform":"linux"}
https, nicht http — der Server terminiert TLS selbst über uvicorn (-k unterdrückt die
Zertifikatsprüfung für den selbstsignierten Leaf beim reinen Health-Check).
6. Clients pairen
Auf dem Host selbst (nicht im Container):
./scripts/pairing-info.sh
Erzeugt beim ersten Aufruf ein dediziertes SSH-Schlüsselpaar für die spätere
Admin-Shell/Toolcall-Proxy-Nutzung, zeigt den QR-Code fürs iOS-Pairing an und schreibt
/docker/iris-server/data/pairing-macos.json für den macOS-IrisClient
(Zahnrad → „+" → Datei-Drop, siehe AddConnectionSheetView).
7. Vault befüllen
/docker/iris-server/vault/ startet leer. Der Nutzer befüllt ihn selbst — per rsync, git clone, Syncthing o. Ä. — das ist bewusst außerhalb der Verantwortung der App (siehe
SERVER-ADMIN.md Punkt 3). Ohne Inhalt verhalten sich alle /vault/*-Routen korrekt wie bei
einem leeren Vault (leere Listen, kein Fehler).
Alternative: Bestehendes Backup restaurieren statt neu einrichten
Wer keinen komplett leeren Server will, sondern eine Kopie eines bereits laufenden Servers (Vault + Hermes-Daten + Chat-/Job-Historie in einem Schritt statt Schritt 6+7 von Hand), kann nach Schritt 5 stattdessen ein vorhandenes Backup restaurieren:
curl -sk -X POST https://<neuer-host>:8765/backup/restore \
-H "Authorization: Bearer <bearer-token-des-NEUEN-servers>" \
-H "Content-Type: application/json" \
-d '{"path": "<pfad-zur-hochgeladenen-zip>", "scope": "everything"}'
In der Praxis läuft das über den IrisClient (Einstellungen → Backup & Restore → „Von lokaler
Datei wiederherstellen"), der das Hochladen selbst übernimmt. Das Backup-Manifest-Format ist
cross-plattform-kompatibel (Mac ↔ Linux, siehe BackupUnit-Dokumentation in
BackupRestoreManager.swift bzw. app/backup_manager.pys UNIT_MAPPING) — ein auf dem
bestehenden Server erstelltes Backup lässt sich so direkt auf dem neuen wiederherstellen.
scope: "everything" übernimmt auch die Backend-Konfiguration des Ursprungsservers;
"dataOnly" lässt sie unangetastet, falls der neue Host ein anderes LLM-Backend nutzen soll.
Danach: Administration ohne SSH
Ab hier läuft alles über den IrisClient (Agent-Backend wählen, API-Keys hinterlegen,
Systemprompts, Job-Hooks, Hintergrund-Jobs, Vault-Wartung) — kein weiterer SSH-Zugriff nötig.
Details: SERVER-ADMIN.md.