# Monitoring — Rebuild-Runbook Neue LXC `CT104 monitoring` (``, Tailscale-Mitglied `monitoring.`) hostet als Docker-Compose-Stack: InfluxDB (Metrik-Datenbank), Grafana (Dashboards), Uptime Kuma (Erreichbarkeit + Alert-Routing), ntfy (Push-Benachrichtigungen). Ergänzt um PVE-Metric-Server-Export, Telegraf auf dem VPS, ein HDD-SMART-Tracking-Script und Login-/Zugriffs-Tracking je Dienst. ## 1. CT104 anlegen ```bash pct create 104 local:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst \ --hostname monitoring --memory 1536 --swap 512 --cores 2 \ --rootfs local-lvm:12 \ --net0 name=eth0,bridge=vmbr0,ip=/24,gw= \ --nameserver --unprivileged 1 --features nesting=1 \ --onboot 1 --timezone Europe/Berlin --ostype debian pct start 104 pct stop 104 cat >> /etc/pve/lxc/104.conf <<'EOF' lxc.cgroup2.devices.allow: c 10:200 rwm lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file 0 0 EOF pct start 104 ``` Danach Docker (`curl -fsSL https://get.docker.com | sh`) und Tailscale (`curl -fsSL https://tailscale.com/install.sh | sh && tailscale up --hostname=monitoring --accept-routes=false`) installieren. ⚠️ **NICHT vergessen:** CT104 ins nächtliche `vzdump`-Backup aufnehmen (`crontab -e` auf dem PVE-Host, `104` zur ID-Liste ergänzen) — sonst ist der Monitoring-Stack selbst nicht gesichert. ## 2. Docker-Compose-Stack `/opt/monitoring/docker-compose.yml` (Auszug, vollständige Datei im laufenden System): vier Services `influxdb`, `grafana`, `uptime-kuma`, `ntfy`, gemeinsamer `x-logging`-Anchor (10m×3 Dateien, bestehende Konvention). Ports: InfluxDB 8086, Grafana 3000, Uptime Kuma 3001, ntfy 8090→80. ⚠️ **NICHT TUN:** Grafana-Datenverzeichnis (`./grafana`) beim ersten Start nicht vor-chownen — der Container läuft als UID 472, ein per `pct exec`/root angelegtes Bind-Mount-Verzeichnis gehört aber root:root. Fix: `chown -R 472:472 /opt/monitoring/grafana` **vor** dem ersten Start von Grafana, sonst Crash-Loop ("not writable"). ```bash mkdir -p /opt/monitoring/{influxdb,grafana,uptime-kuma,ntfy} chown -R 472:472 /opt/monitoring/grafana cd /opt/monitoring && docker compose up -d ``` ## 3. InfluxDB: Setup, Buckets, Retention, Downsampling ```bash docker exec influxdb influx setup --username admin --password '' \ --org homelab --bucket raw --retention 14d --force docker exec influxdb influx bucket create --name aggregated --org homelab --retention 730d ``` Zwei Buckets statt vieler kleiner: `raw` (14 Tage, volle Auflösung — deckt die längste Rohdaten-Anforderung aller Datentypen ab) und `aggregated` (2 Jahre, stündliche Mittelwerte). Downsampling-Task (`influx task create -f downsample.flux`): ```flux option task = {name: "downsample-hourly", every: 1h} from(bucket: "raw") |> range(start: -task.every) |> filter(fn: (r) => r._field != "name" and r._field != "status" and r._field != "type" and r._field != "tags" and r._field != "uptime_format" and r._field != "content") |> aggregateWindow(every: 1h, fn: mean, createEmpty: false) |> to(bucket: "aggregated", org: "homelab") ``` ⚠️ **NICHT TUN:** Den `raw`-Bucket ohne Feld-Filter blind mit `aggregateWindow(fn: mean)` downsamplen. Proxmox' `system`-Measurement (LXC- und Storage-Objekte) enthält Text-Felder (`name`, `status`, `type`, `tags`, `uptime_format`, `content`) — `mean` auf einer String-Spalte lässt den Task mit `unsupported input type for mean aggregate: string` fehlschlagen. Vor dem Anlegen des Tasks die tatsächlichen Feldnamen je Measurement prüfen (`schema.fieldKeys`), nicht raten. Retention-Prinzip (Details/Begründung siehe Plan-Historie): Rohdaten kurz (Tage), Aggregate lang (Jahre) — hält die Gesamtgröße über Jahre konstant klein statt linear mit der Laufzeit zu wachsen. ## 4. PVE Metric Server → InfluxDB ```bash pvesh create /cluster/metrics/server/monitoring \ --type influxdb --server --port 8086 \ --influxdbproto http --organization homelab --bucket raw --token '' ``` Pusht Host- und LXC-Metriken automatisch alle ~10s, kein Agent in den LXCs nötig. Guest-Metriken landen unter Measurement `system` (Felder `cpu`, `mem`, `maxmem`, …, Tag `object=lxc`), Host-Metriken unter `cpustat`/`memory`/`blockstat`/`nics` (Tag `object=nodes`) — **unterschiedliches Schema**, beim Dashboard-Bau beide Fälle abdecken. ## 5. Telegraf auf dem VPS VPS ist kein PVE-Cluster-Mitglied, braucht eigenen Agent: ```bash apt install -y gnupg curl -sL -o /tmp/telegraf.deb https://dl.influxdata.com/telegraf/releases/telegraf_1.39.1-1_amd64.deb dpkg -i /tmp/telegraf.deb ``` ⚠️ **NICHT TUN:** Das offizielle InfluxData-apt-Repo (`repos.influxdata.com/debian`) auf Debian 13 (trixie) einbinden — die GPG-Signatur wird von `apt`/`sqv` mit "Missing key" abgelehnt (Schlüssel-Rotation nicht mit dem dokumentierten `_compat.key` synchron). Stattdessen das `.deb` direkt von `dl.influxdata.com/telegraf/releases/` laden und mit `dpkg -i` installieren. ⚠️ **NICHT vergessen:** Minimale Debian-13-Installationen haben oft kein `cron`-Paket (`crontab: command not found`) — `apt install -y cron && systemctl enable --now cron` vor dem ersten `crontab -e`. `/etc/telegraf/telegraf.conf`: `outputs.influxdb_v2` auf `http://:8086`, Bucket `raw`, Org `homelab`; Inputs `cpu`, `mem`, `disk`, `net`, `system`. ## 6. HDD-SMART-Tracking (PVE-Host) `/usr/local/bin/hdd-smart-to-influx.sh` liest `smartctl -A` für beide Platten (Attribute `Load_Cycle_Count`, `Start_Stop_Count`, `Temperature_Celsius` — Raw-Wert ist das erste Feld vor evtl. Klammertext), `zfs list -H -o name,used,avail,refer -p` für `nas`/`nas/freigabe`/`nas/backups` (Measurement `zfs_usage`, `/` im Dataset-Namen zu `_` normalisiert für den Tag-Wert) **und** NVMe-Belegung (Measurement `nvme_usage`) — die VG `pve` deckt praktisch die gesamte Intenso-NVMe ab (nur EFI-/Boot-Partitionen liegen außerhalb, vernachlässigbar). Schreibt alles per InfluxDB-Line-Protocol via `curl` in den `raw`-Bucket. systemd-Timer `hdd-smart-to-influx.timer`, alle 5 Minuten: ⚠️ **NICHT TUN:** Bei LVM-Thin-Provisioning (hier: LV `pve/data`, 137GB Pool für alle LXC-Disks) `vgs -o vg_size,vg_free` als "wie voll ist die Platte" interpretieren. Das misst nur, wie viel VG-Fläche noch **unallokiert** ist (also Platz für neue LVs) — nicht, wie viel der bereits allokierten LVs tatsächlich mit Daten beschrieben ist. Bei diesem Setup zeigte `vgs` 93% "belegt", obwohl real nur ~8% Daten auf der Platte lagen (root-LV zu 68GB allokiert, aber nur 6GB genutzt; Thin-Pool zu 137GB allokiert, aber nur 8,88% beschrieben). Für eine ehrliche Nutzungsanzeige: `df --output=used -B1 /` (root-FS) + `lvs -o lv_size,data_percent pve/data` (Thin-Pool-Ist-Nutzung) addieren → Feld `actual_used_gb`, getrennt von `total_gb`/`free_gb` (VG-Allokation, weiterhin nützlich um zu wissen, wie viel Raum für neue LVs übrig ist). ```ini # /etc/systemd/system/hdd-smart-to-influx.timer [Timer] OnBootSec=2min OnUnitActiveSec=5min ``` Grafana-Panel "HDD Load-Cycle-Rate" (`derivative(unit: 1h, nonNegative: true)` auf `load_cycle_count`) ist die eigentliche Verifikation, ob ein Spindown-Timeout in der Praxis zu häufiges Spin-up/down verursacht. ⚠️ **NICHT TUN:** Bei Prozent-Berechnungen aus zwei InfluxDB-Feldern (z.B. `used_bytes / (used_bytes + avail_bytes)`) auf automatische Int→Float-Konvertierung verlassen. Line-Protocol-Felder mit `i`-Suffix sind in Flux `int`, eine Division mit einem Float-Literal (`* 100.0`) scheitert dann mit `type conflict: float != int`. Fix: `float(v: r.used_bytes) / float(v: r.used_bytes + r.avail_bytes) * 100.0`. ## 7. Grafana: Datasource + Dashboard per Provisioning `/opt/monitoring/grafana-provisioning/datasources/influxdb.yaml` (InfluxDB2/Flux, fester `uid: influxdb-homelab`) und `/opt/monitoring/grafana-provisioning/dashboards/{provider.yaml,homelab.json}`, gemountet nach `/etc/grafana/provisioning`. Dashboard-JSON referenziert die Datasource über die feste `uid`, nicht per Name. Dashboard-Struktur (per `"type": "row"`-Panels gruppiert, jede Zeile bewusst `"collapsed": false`): **Übersicht** (Esprimo/PVE-Host CPU+RAM als Graph + Intenso-NVMe frei/gesamt/Belegung-%, direkt darunter dasselbe Muster für den VPS: CPU+RAM als Graph + Root-Filesystem frei/gesamt/Belegung-%), **Ressourcen** (CPU/RAM/Speicherbelegung nur LXCs — PVE-Host und VPS bewusst nicht doppelt, stehen schon in der Übersicht), **Festplatten** (ZFS-Belegung in Bytes, HDD-Load-Cycle-Count/-Rate, Temperatur), **Logins & Zugriffe** (erfolgreiche/fehlgeschlagene Logins je Dienst, gestapelte Balken). `refresh: "1m"` auf Dashboard-Ebene gesetzt. VPS-Speicherbelegung braucht kein neues Tracking — Telegrafs `disk`-Input-Plugin (bereits für die Ressourcen-Metriken konfiguriert, siehe Abschnitt 5) liefert `free`/`total`/`used_percent` für `/` schon fertig aufbereitet, kein manueller Prozent-Umweg wie bei NVMe/ZFS nötig. **LXC-Speicherbelegung** (Panel "Speicherbelegung: LXCs", Ressourcen-Abschnitt): braucht kein neues Tracking-Script — Felder `disk`/`maxdisk` kommen schon über den PVE-Metric-Export im `system`-Measurement mit (Rootfs-Füllstand je Container, nicht zu verwechseln mit der NVMe- oder ZFS-Belegung). ⚠️ **NICHT TUN:** Bei Stat-Panels mit `pivot()`+`map()`-Berechnung (z.B. Prozent aus zwei Feldern) das Ergebnis ohne abschließendes `|> keep(columns: ["_time", "_value"])` zurückgeben. Grafana zeigt bei `reduceOptions.fields: ""` (Auto-Erkennung) sonst **jedes** numerische Feld der Tabelle als eigene Kachel-Zahl an — inklusive der Zwischenwerte (`used_bytes`, `avail_bytes`) neben dem eigentlichen `_value`. Gleiches Prinzip für Legenden bei Mehrserien-Timeseries-Panels: ohne `keep(columns: ["_time", "host", "_value"])` zeigt die Legende alle Tags (`nodename`, `object`, `vmid`, …) statt nur des relevanten (`host`). ⚠️ **NICHT TUN:** Bei Stat-Panels mit reinen Referenzzahlen (z.B. "frei (GB)", "gesamt (GB)") `colorMode: "value"` ohne explizite Thresholds stehen lassen. Grafanas Default-Threshold färbt ab Wert 80 automatisch rot — bei einer GB-Zahl wie 213,9 (viel freier Platz, eigentlich gut) sieht das wie ein Alarm aus, obwohl "hoch" hier positiv ist. Für reine Referenzzahlen `colorMode: "none"` setzen; Ampelfarben nur bei tatsächlich alarmwürdigen Metriken (z.B. Belegungs-Prozent, wo hoch = schlecht stimmt) verwenden. ⚠️ **NICHT vergessen:** `GF_SECURITY_ADMIN_PASSWORD` wirkt nur bei der **ersten** DB-Initialisierung. Ist Grafana schon einmal mit Default-Credentials (`admin`/`admin`) gestartet, hilft nur `docker exec grafana grafana cli admin reset-admin-password ''` (neuere Grafana-Versionen: `grafana cli`, nicht mehr das alte `grafana-cli`-Binary). ## 8. Uptime Kuma: Monitore + ntfy-Notification Kein offizielles REST-API für Monitor-Verwaltung — Setup über die Python-Bibliothek `uptime-kuma-api` (nutzt das interne Socket.IO-Protokoll): ```bash python3 -m venv /opt/monitoring/kuma-venv /opt/monitoring/kuma-venv/bin/pip install uptime-kuma-api ``` ```python from uptime_kuma_api import UptimeKumaApi, MonitorType, NotificationType api = UptimeKumaApi('http://localhost:3001') api.setup('admin', '') # nur beim allerersten Mal api.login('admin', '') api.add_notification(name='ntfy-homelab', type=NotificationType.NTFY, isDefault=True, ntfyserverurl='http://ntfy:80', ntfytopic='homelab-alerts', ntfyPriority=4, ntfyAuthenticationMethod='none') api.add_monitor(type=MonitorType.HTTP, name='...', url='...', interval=60, maxretries=2) api.add_monitor(type=MonitorType.PING, name='...', hostname='...', interval=60, maxretries=2) ``` ⚠️ **NICHT TUN:** Sich auf `isDefault=True` bei `add_notification` verlassen, um die Notification automatisch an alle (auch später erstellte) Monitore zu hängen — greift über die API nicht zuverlässig. Stattdessen nach dem Anlegen explizit für jeden Monitor `api.edit_monitor(id, notificationIDList={'': True})` setzen. ⚠️ **NICHT TUN:** `retries=` als Kwarg für `add_monitor` verwenden — die Bibliothek erwartet `maxretries`, sonst `TypeError`. Angelegte Monitore: 5× HTTP (Guacamole öffentlich, Vaultwarden/PVE-Web über Tailnet-Namen, AdGuard/Filebrowser über LAN-IP — bewusst IP statt `*.pve`-Name bei AdGuard, um keine Zirkularität zu erzeugen, falls AdGuard selbst der Ausfall ist), 6× Ping (VPS über Tailscale-IP, PVE-Host + 4 LXCs über LAN-IP). ## 9. ntfy: Erreichbarkeit + tailscale serve ```bash tailscale serve --bg http://localhost:8090 ``` ⚠️ **NICHT TUN:** `https+insecure://localhost:8090` verwenden (das Muster aus `01-pve-host.md`/PVE-Webinterface) — dort war es richtig, weil das Backend (`pveproxy`) selbst HTTPS mit selbstsigniertem Zertifikat spricht. ntfy spricht intern nur **plain HTTP**; `https+insecure://` gegen einen HTTP-Backend führt zu `502 Bad Gateway`. Korrekt: `http://localhost:8090`. Nach Einrichtung `NTFY_BASE_URL` in der Compose-Datei auf `https://monitoring.` setzen und `docker compose up -d ntfy` (Recreate). ## 10. Backup-Cronjobs: Fehlschlag-Alerts Bestehende Cronjobs (`vzdump`, `backup-guacamole.sh`, rsync-Pull) auf Wrapper-Skripte umgestellt, die bei Fehlschlag (`if ! ; then curl ntfy; fi` bzw. `trap ... ERR`) eine Push-Nachricht senden. Bewusst nur bei Fehlschlag, kein täglicher Erfolgs-Spam. Ersetzt die bis dahin wirkungslose `vzdump`-Mail-Benachrichtigung (Postfix auf dem PVE-Host ist `inet_interfaces = loopback-only`, kein Relay, kein root-Postfach — die Mail ging faktisch ins Leere). ## 11. Login-/Zugriffs-Tracking Kleine Skripte (alle 5 Min. per Cron) statt eines Loki/Promtail-Log-Stacks — schreiben Erfolgs-/Fehlschlag-Zähler nach InfluxDB, pushen bei Schwellenwert (>3 Fehlschläge/5 Min.) einen ntfy-Alert. Zusätzlich pusht jedes Skript bei `SUCCESS -gt 0` eine niedrigprioritäre ntfy-Meldung für erfolgreiche Logins (eigener Block je Skript, `Priority: default` statt `high`, Tag `white_check_mark` statt `warning`). ⚠️ **Bekannte Rauschquelle:** Vaultwardens Clients nutzen denselben `/identity/connect/token`-Endpunkt auch für OAuth-Token-Refreshes, nicht nur für echte Logins — der Erfolgs-Alert kann dadurch öfter feuern als ein tatsächlicher neuer Login stattfindet. Bewusst so belassen (Nutzeranforderung), aber beim nächsten Mal ggf. auf `grant_type=password` in den Logs filtern, um echte Logins von Refreshes zu trennen. | Dienst | Quelle | |---|---| | Guacamole (VPS) | Docker-Logs (`InMemoryAuthenticationFailureTracker`) + `guacamole_user_history`-Tabelle für Erfolge | | Vaultwarden (CT103) | Docker-Logs, `(login) POST /identity/connect/token => ` | | PVE-Weboberfläche (Host) | `/var/log/pveproxy/access.log`, byte-offset-basiertes Tailing (kein natives `--since`) | | SSH (PVE-Host) | `journalctl -u ssh --since "5 min ago"` | | SSH/fail2ban (VPS) | `fail2ban-client status sshd` (Currently/Total failed/banned) — kein Log-Parsing nötig, fail2ban liefert die Zahlen direkt; Alert nur wenn „Currently banned" gegenüber letzter Messung steigt | | AdGuard-Web-UI (CT100) | **nicht umgesetzt** — AdGuard loggt fehlgeschlagene Web-UI-Logins nachweislich nicht (getestet: weder Journal noch mit `verbose`-Flag), trotz eingebautem Lockout (`auth_attempts: 5`, `block_auth_min: 15`). Bewusste, dokumentierte Lücke statt einer fragilen Behelfslösung | **Update 2026-07-19 — Wer/IP statt nur Zahlen:** Alle fünf Skripte (außer fail2ban, das schon Zahlen liefert) hängen den echten Login-Kontext an den ntfy-Text an: - **SSH (Host):** `user@ip` per `sed -nE` aus `Accepted`/`Failed password`/`Invalid user`-Zeilen extrahiert - **PVE-Web:** Quell-IP (erstes Feld in `access.log`, `::ffff:`-Präfix entfernt) - **fail2ban:** von reinem Status-Polling auf `fail2ban.log`-Tailing (byte-offset) umgestellt — liefert die tatsächlich gesperrte(n) IP(s) aus den `NOTICE [sshd] Ban `-Zeilen statt nur "eine neue IP" - **Vaultwarden:** brauchte `IP_HEADER: "X-Forwarded-For"` in der Compose-Datei (Vaultwarden loggt IPs sonst gar nicht) — `tailscale serve` setzt den Header bereits automatisch, nur Vaultwarden vertraute ihm nicht. Danach erscheint bei Fehlschlägen `Username or password is incorrect... IP: X. Username: Y.` im Log, extrahierbar. Bei **Erfolg** bleibt die IP unverfügbar (dieser Log-Pfad existiert nur im Fehlerfall) - **Guacamole:** brauchte `REMOTE_IP_VALVE_ENABLED: "true"` in der Compose-Datei (Tomcats RemoteIpValve, liest `X-Forwarded-For` von Caddy). Vorher zeigte der Fehlschlag-Tracker nur die interne Docker-Gateway-IP (`172.18.0.1`), nach dem Fix die echte Client-IP. Bei **Erfolg** bleibt `guacamole_user_history.remote_host` trotzdem auf der internen Adresse — der DB-Verlauf nutzt offenbar einen anderen internen Pfad als der Live-Fehlschlag-Tracker, der die Valve-korrigierte Adresse honoriert. Nicht weiter debuggt (Aufwand/Nutzen), Username bei Erfolg ist trotzdem neu und nützlich ⚠️ **NICHT TUN:** `paste -sd', ' -` verwenden, um mehrere Werte mit `, ` zu verbinden. `paste -s -d LISTE` zykelt durch die **einzelnen Zeichen** der Delimiter-Liste statt sie als einen mehrzeichigen Trenner zu nutzen — bei 3+ Werten entsteht `a,b c,d e,f` (abwechselnd Komma und Leerzeichen) statt `a, b, c, d, e, f`. Fällt bei nur 1-2 Werten nicht auf (Zufallstreffer), erst bei mehreren wird der Bug sichtbar. Fix: `paste -sd',' - | sed 's/,/, /g'`. ## 12. HDD-Tracking hat sich selbst sabotiert (kritischer Fund) Das 5-Minuten-Tracking-Script (`hdd-smart-to-influx.sh`) weckte mit jedem Lauf die schlafenden Platten — `smartctl -A` liest per Default auch bei einer Platte im Standby, was sie aufweckt. Da Check-Takt (5 Min.) und Spindown-Timeout (5 Min., siehe `01-pve-host.md`) identisch sind, hat das Monitoring den gerade erst eingerichteten Spindown fast vollständig ausgehebelt — bewiesen durch manuellen Test (Platte per `hdparm -y` schlafen gelegt, `smartctl -A` drüber, Status sofort wieder `active/idle`). **Fix:** `smartctl -n standby -A ` — überspringt (ohne Weckvorgang) die Abfrage, wenn die Platte schon schläft; Skript erkennt das am Exit-Code/der Meldung `Device is in STANDBY mode` und schreibt für diesen Durchlauf einfach keinen Datenpunkt für die schlafende Platte (InfluxDB/Grafana kommen mit Lücken problemlos klar). ⚠️ **NICHT TUN:** `smartctl -A` (ohne `-n standby`) in einem Monitoring-Script verwenden, das eine Platte im Standby beobachten soll — das ist ein Widerspruch in sich, das Skript verhindert genau das, was es messen will. ## 13. Esprimo-Hardware-Sensoren (CPU-Temp + Lüfter) Fujitsu-eigener Sensorchip, nicht automatisch aktiv: ```bash apt install -y lm-sensors yes | sensors-detect --auto echo -e "ftsteutates\ncoretemp" > /etc/modules-load.d/ftsteutates.conf modprobe ftsteutates coretemp ``` Liefert `coretemp-isa-0000` (`Package id 0` = CPU-Temperatur) und `ftsteutates-i2c-0-73` (`fan2` = einziger belegter Lüfterkanal von 8, Rest `FAULT`/nicht verbaut). Werte per `sensors ` parsen, ins `hdd-smart-to-influx.sh`-Script integriert (Measurement `esprimo_hw`, Felder `cpu_temp_c`/`fan_rpm`) — läuft im selben 5-Min-Timer mit statt einen eigenen zu brauchen. Grafana-Panel kombiniert beide Metriken in einer Kachel mit zwei Y-Achsen (Temperatur links, RPM rechts, per `byFrameRefID`-Field-Override) — zeigt auf einen Blick, ob und wann der Lüfter bei steigender Last einsetzt (Ziel: möglichst viel passive Kühlung). ## 14. Load-Cycle-Verifikation: tägliche Momentaufnahme statt Dauerkurve Zusätzlich zur laufenden 5-Min-Erfassung (jetzt korrekt, siehe Punkt 12) schreibt `vzdump-backup.sh` einmal täglich (03:00, während die Platten wegen des Snapshots ohnehin wach sind — kein zusätzlicher Weckvorgang) den rohen `Load_Cycle_Count` nach InfluxDB. Grafana-Panel "Differenz zum Vortag": ```flux from(bucket: "aggregated") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn: (r) => r._measurement == "smart" and r._field == "load_cycle_count") |> aggregateWindow(every: 1d, fn: last, createEmpty: false) |> difference(nonNegative: true) ``` Beantwortet direkt "wie viele Spin-ups gab es seit gestern" — eindeutiger als die stündliche Rate-Kurve, die bei Datenlücken (Platte war lange am Stück wach oder lange am Stück im Standby) leicht misszuinterpretieren ist. ## Guacamole-SFTP: bekanntes, ungelöstes Problem Die SFTP-Begleitverbindung (Datei-Transfer-Feature, `enable-sftp`) der VNC-Verbindung "Management-Desktop (Browser)" ist aktuell **deaktiviert** (`enable-sftp: false` in der DB). Ursache war zunächst ein reines Passwort-Drift zwischen dem in Guacamole hinterlegten Passwort und dem tatsächlichen System-Passwort des `transfer`-Users auf CT102 (behoben, `chpasswd`) — aber selbst mit korrektem Passwort scheiterte `guacd`s eingebauter SSH-Client (`libssh2`) weiterhin an der Authentifizierung, während derselbe Login mit dem normalen OpenSSH-Client (von PVE-Host **und** vom VPS aus, exakt derselbe Netzwerkpfad wie `guacd`) anstandslos funktionierte. Deutet auf eine Algorithmus-/Protokoll-Inkompatibilität zwischen `libssh2` und CT102s OpenSSH-Server hin (z.B. moderne KEX-Defaults, die `libssh2` nicht unterstützt), nicht auf ein Credential-Problem. VNC selbst funktioniert einwandfrei (davon unabhängig). Für eine vollständige Lösung: `sshd_config` auf CT102 um ältere, `libssh2`-kompatible `KexAlgorithms`/`HostKeyAlgorithms` erweitern (Kompatibilitäts-Fallback, nicht global schwächen) und erneut mit aktiviertem `enable-sftp` testen — noch nicht gemacht (Priorität war, den Nutzer schnell wieder reinzulassen). ## Referenz: Zugänge | Dienst | URL | Hinweis | |---|---|---| | Grafana | `http://:3000` | Admin-Passwort in Vaultwarden | | Uptime Kuma | `http://:3001` | Admin-Passwort in Vaultwarden | | InfluxDB | `http://:8086` | Admin-Passwort + Token in Vaultwarden | | ntfy (Push) | `https://monitoring.`, Topic `homelab-alerts` | Android/iOS-App auf den self-hosted Server zeigen lassen | | NAS-Backups (SMB) | `\\nas.pve\backups` | Read-only, gleicher Nutzer `` wie `freigabe` |