22 KiB
Monitoring — Rebuild-Runbook
Neue LXC CT104 monitoring (<LAN_IP_MONITORING>, Tailscale-Mitglied monitoring.<TAILNET>) 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
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=<LAN_IP_MONITORING>/24,gw=<LAN_IP_ROUTER> \
--nameserver <LAN_IP_ADGUARD> --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").
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
docker exec influxdb influx setup --username admin --password '<PW>' \
--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):
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
pvesh create /cluster/metrics/server/monitoring \
--type influxdb --server <LAN_IP_MONITORING> --port 8086 \
--influxdbproto http --organization homelab --bucket raw --token '<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:
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://<CT104-Tailscale-IP>: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).
# /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 '<PW>' (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):
python3 -m venv /opt/monitoring/kuma-venv
/opt/monitoring/kuma-venv/bin/pip install uptime-kuma-api
from uptime_kuma_api import UptimeKumaApi, MonitorType, NotificationType
api = UptimeKumaApi('http://localhost:3001')
api.setup('admin', '<PW>') # nur beim allerersten Mal
api.login('admin', '<PW>')
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={'<notif_id>': 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
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.<TAILNET> 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 ! <command>; 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 => <Status> |
| 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@ippersed -nEausAccepted/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 denNOTICE [sshd] Ban <ip>-Zeilen statt nur "eine neue IP" - Vaultwarden: brauchte
IP_HEADER: "X-Forwarded-For"in der Compose-Datei (Vaultwarden loggt IPs sonst gar nicht) —tailscale servesetzt den Header bereits automatisch, nur Vaultwarden vertraute ihm nicht. Danach erscheint bei FehlschlägenUsername 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, liestX-Forwarded-Forvon 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 bleibtguacamole_user_history.remote_hosttrotzdem 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 <dev> — ü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:
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 <chip> 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":
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 guacds 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://<LAN_IP_MONITORING>:3000 |
Admin-Passwort in Vaultwarden |
| Uptime Kuma | http://<LAN_IP_MONITORING>:3001 |
Admin-Passwort in Vaultwarden |
| InfluxDB | http://<LAN_IP_MONITORING>:8086 |
Admin-Passwort + Token in Vaultwarden |
| ntfy (Push) | https://monitoring.<TAILNET>, Topic homelab-alerts |
Android/iOS-App auf den self-hosted Server zeigen lassen |
| NAS-Backups (SMB) | \\nas.pve\backups |
Read-only, gleicher Nutzer <PRIMARY_USER> wie freigabe |