Uptime Kuma weckt dich um drei Uhr nachts, weil der Server ausgefallen ist. Dass die Platte seit Wochen jede Woche ein bisschen schneller vollläuft, sagt es dir nicht. Ein Diagramm schon, und zwar an einem Dienstagnachmittag statt um drei Uhr nachts.
Kurz gesagt
Wie funktioniert Homelab-Monitoring mit Prometheus und Grafana? Du startest vier Container mit Docker Compose. Prometheus holt in festen Abständen Zahlen von deinen Rechnern und speichert sie. node_exporter macht CPU, Arbeitsspeicher, Platten und Netzwerk eines Linux-Hosts für Prometheus lesbar. Grafana zeichnet den Verlauf, und Alertmanager schickt eine Nachricht, wenn eine Regel auslöst [1][4][11][12][16]. Prometheus zieht die Daten selbst: Es fragt jedes Ziel nach den aktuellen Werten, standardmäßig einmal pro Minute [4]. Dieser Guide legt Image-Tags fest, die es nachweislich gibt (geprüft am 25. Okt. 2026), hält jeden Dienst auf der Loopback-Adresse, begrenzt den Plattenplatz für den Verlauf und liefert zwei Alarmregeln: Ein Dienst antwortet nicht mehr, und eine Platte ist in 24 Stunden voll. Unsere Einschätzung: Prometheus beantwortet „Wie entwickelt sich das?“, Uptime Kuma beantwortet „Ist es erreichbar?“. Nimm beides, denn beides fällt auf andere Weise aus.
So funktioniert’s
Vier Rollen. Ein Exporter ist ein kleines Programm, das die Messwerte eines Systems unter einer Webadresse zeigt, meist /metrics. node_exporter macht das für Linux-Hosts und lauscht standardmäßig auf Port 9100 [12]. Prometheus „scrapt“ (holt) alle eingetragenen Ziele, legt die Messwerte in einer Zeitreihen-Datenbank auf der lokalen Platte ab und speichert für jeden Abruf eine Reihe up mit 1 oder 0 [4][9]. Grafana speichert selbst keine Messwerte. Es fragt Prometheus über eine Datenquelle ab und zeichnet das Ergebnis [28][29]. Alertmanager verschickt die Benachrichtigungen. Laut Prometheus-Doku stellen Alarmregeln nur fest, was gerade kaputt ist, und für Zusammenfassen, Begrenzen und Stummschalten braucht es eine weitere Schicht. Im Prometheus-Umfeld ist das der Alertmanager [6].
Festgelegte Versionen. Prometheus 3.15.1 (veröffentlicht am 21. Okt. 2026) [18], node_exporter 1.12.1 (14. Juli 2026) [19], Alertmanager 0.34.1 (17. Sept. 2026) [20] und Grafana 13.2.4 (13. Okt. 2026) [21]. Jeder Tag existiert laut Docker Hub am 25. Okt. 2026 [22][23][24][25]. Wir nehmen nicht latest, damit ein Update eine Entscheidung von dir ist und nicht beim nächsten pull passiert.
Wo der Stack läuft. Die Docker-Images sind außer für x86-64 auch für 64-Bit-ARM und 32-Bit-ARM (v7) gelistet [22][23][24][25]. Darüber hinaus hängt die Wahl von deiner Lage ab:
| Option | Passt, wenn | Darauf achten |
|---|---|---|
| Mini-PC oder alter PC mit Linux | Er läuft ohnehin rund um die Uhr | Miss zuerst seinen Stromverbrauch; siehe die Stromguides unten |
| Raspberry Pi | Du willst die kleinste, leiseste Kiste | Prometheus schreibt dauernd auf die Platte: ein Write-ahead-Log und alle zwei Stunden einen neuen Block [1]. Unsere Einschätzung: nimm eine SSD statt einer SD-Karte. Verschleißzahlen haben wir nicht, dieser Teil ist unbelegt |
| Auf dem überwachten Host selbst | Du willst am schnellsten starten | Fällt der Host aus, fällt das Monitoring mit aus und schweigt |
| VPS | Du willst einen Blick von außen | Prometheus zieht die Daten, deine Exporter zu Hause müssten also aus dem Internet erreichbar sein. Das Projekt sagt, seine Endpunkte sollen nicht in öffentlichen Netzen stehen [10] |
Unsere Einschätzung: Setz den Stack auf einen kleinen Dauerläufer zu Hause und die Sicht von außen (Uptime Kuma) auf ein anderes Gerät oder einen VPS. Willst du Prometheus doch auf einem VPS, verbinde ihn per VPN mit deinem Heimnetz, statt Exporter-Ports zu öffnen; siehe den Guide zu WireGuard und Tailscale unten.
Warum das Uptime Kuma nicht wiederholt. Uptime Kuma fragt von außen, ob etwas antwortet. Prometheus liest Zahlen von innen und behält sie:
| Uptime Kuma | Prometheus mit node_exporter | |
|---|---|---|
| Typische Frage | Ist Seite, Port oder Host erreichbar? | Wie voll ist die Platte, und wie schnell füllt sie sich? |
| Datenquelle | Prüfungen, die es selbst ausführt | Exporter auf den Systemen |
| Was bleibt | Verlauf von Up und Down, Antwortzeiten | Jede Zahl, die die Exporter liefern, so lange du es erlaubst |
| Typischer Alarm | „Seit 2 Minuten nicht erreichbar“ | „In 24 Stunden voll“ |
Beide lassen sich verbinden: Uptime Kuma gibt seine Monitore unter /metrics als Prometheus-Metriken aus, standardmäßig mit Basic Authentication. Prometheus kann sie abholen, und Grafana zeigt die Verfügbarkeit neben der Last [36].
Den Verlauf begrenzen. Ohne Vorgabe gilt eine Aufbewahrung von 15 Tagen [1][3]. Setze Zeit und Größe. Beide gelten, und die Grenze, die zuerst greift, gewinnt [1]. Seit der Änderung in Prometheus von 2025 sind die beiden Kommandozeilen-Flags als veraltet markiert, und dieselben Einstellungen stehen in prometheus.yml unter storage.tsdb.retention; sie haben Vorrang vor den Flags [3][5]. Viele Anleitungen nutzen noch die Flags [37]. Die Größengrenze sollte höchstens 80 bis 85 Prozent des zugewiesenen Plattenplatzes betragen, weil die Verdichtung alte und neue Blöcke gleichzeitig ablegen muss [1].
Türen schließen. Prometheus lauscht standardmäßig auf 0.0.0.0:9090 [3]. Sein Sicherheitsmodell geht davon aus, dass nicht vertrauenswürdige Nutzer alles lesen können, was es ausliefert, und sagt, die Endpunkte gehören nicht in öffentliche Netze [10]. Docker legt eine Falle dazu: Ports, die du mit -p veröffentlichst, werden umgeleitet, bevor ufw sie sieht [34], und ein schlichtes -p 9090:9090 ist für alles offen, was den Host erreicht [33]. Wir umgehen beides, indem die Container im Host-Netzwerk laufen und jeder Dienst an 127.0.0.1 gebunden ist (nur Linux; Docker Desktop haben wir nicht getestet). Das README von node_exporter verlangt für die Host-Überwachung selbst Host-Netzwerk und Host-PID [12], und Docker legt für das Host-Netzwerk keine Firewall-Regeln an, sodass deine eigene Firewall weiter gilt [34].
Einrichten
Alles liegt in einem Ordner. Lege ihn und die folgenden Dateien an:
monitoring/
├── compose.yaml
├── .env # GRAFANA_ADMIN_PASSWORD=ein-langes-passwort (nie einchecken)
├── prometheus/
│ ├── prometheus.yml
│ └── rules.yml
├── alertmanager/
│ ├── alertmanager.yml
│ └── smtp_password # dein Mail-Passwort, sonst nichts in der Datei
└── grafana/provisioning/datasources/prometheus.ymlcompose.yaml. Gibst du dem Prometheus- oder Alertmanager-Image ein command:, ersetzt du die Voreinstellungen des Images, deshalb stehen Konfigurations- und Speicher-Flag noch einmal drin [2][17]:
name: monitoring
services:
prometheus:
image: prom/prometheus:v3.15.1
restart: unless-stopped
network_mode: host
command:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.path=/prometheus
- --web.listen-address=127.0.0.1:9090
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./prometheus/rules.yml:/etc/prometheus/rules.yml:ro
- prometheus-data:/prometheus
node-exporter:
image: prom/node-exporter:v1.12.1
restart: unless-stopped
network_mode: host
pid: host
command:
- --path.rootfs=/host
- --web.listen-address=127.0.0.1:9100
volumes:
- /:/host:ro,rslave
alertmanager:
image: prom/alertmanager:v0.34.1
restart: unless-stopped
network_mode: host
command:
- --config.file=/etc/alertmanager/alertmanager.yml
- --storage.path=/alertmanager
- --web.listen-address=127.0.0.1:9093
- --cluster.listen-address=
volumes:
- ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
- ./alertmanager/smtp_password:/etc/alertmanager/smtp_password:ro
- alertmanager-data:/alertmanager
grafana:
image: grafana/grafana:13.2.4
restart: unless-stopped
network_mode: host
environment:
GF_SERVER_HTTP_ADDR: 127.0.0.1
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD:?set GRAFANA_ADMIN_PASSWORD in .env}
volumes:
- ./grafana/provisioning/datasources:/etc/grafana/provisioning/datasources:ro
- grafana-data:/var/lib/grafana
volumes:
prometheus-data:
alertmanager-data:
grafana-data:Warum diese Zeilen zählen:
--path.rootfs=/hostzusammen mit dem Bind-Mount/:/host:ro,rslaveist das Rezept aus dem node_exporter-README. Ohne beides misst der Exporter nur seinen eigenen Container [12]. Das Präfix wird aus dem Labelmountpointentfernt, deine Systemplatte erscheint also als/[13].--cluster.listen-address=(leer) schaltet das Clustering des Alertmanagers ab. Es ist standardmäßig an und lauscht auf0.0.0.0:9094[16]. Im Host-Netzwerk würde das einen Port für dein ganzes LAN öffnen.--web.listen-addressist das Flag für die Bind-Adresse bei Prometheus und Alertmanager [3][38]. node_exporter teilt es über das Exporter-Toolkit von Prometheus, das auch--web.config.filefür TLS und Passwörter bietet, falls du später über das LAN scrapen musst [14]. Prüfe es bei dir mitdocker run --rm prom/node-exporter:v1.12.1 --help.GF_SERVER_HTTP_ADDRist die Umgebungsvariablen-Form vonhttp_addrim Abschnitt[server][27]. Das Admin-Passwort wird nur beim ersten Start gelesen [27], und:?lässt Compose abbrechen, wenn.enves nicht enthält [35]. Docker Secrets überGF_SECURITY_ADMIN_PASSWORD__FILEsind die Alternative [26].- Die Datei
smtp_passwordund die Konfigurationen liest der Container-Nutzernobody[17], sie müssen für ihn lesbar sein.
prometheus.yml. Der Standard-Abstand beim Scrapen ist eine Minute [4]. Wir nehmen 15 Sekunden, das passt für eine Handvoll Hosts:
global:
scrape_interval: 15s
evaluation_interval: 1m
storage:
tsdb:
retention:
time: 30d
size: 4GB
rule_files:
- /etc/prometheus/rules.yml
alerting:
alertmanagers:
- static_configs:
- targets: ["127.0.0.1:9093"]
scrape_configs:
- job_name: prometheus
static_configs:
- targets: ["127.0.0.1:9090"]
- job_name: node
static_configs:
- targets: ["127.0.0.1:9100"]Lass den Job node so heißen: Das Dashboard „Node Exporter Full“ erwartet genau diesen Namen [32]. Für weitere Rechner installierst du node_exporter dort und trägst deren adresse:9100 bei den node-Zielen ein. Binde den Exporter dann an die LAN-Adresse dieses Rechners und lass nur den Monitoring-Host heran. Mach ihn nicht breiter zugänglich [10].
rules.yml. Zwei Alarme reichen für den Anfang. Der erste stammt direkt aus der Prometheus-Dokumentation, der zweite schaut nach vorn [6][8]:
groups:
- name: homelab
rules:
- alert: InstanceDown
expr: up == 0
for: 5m
labels:
severity: critical
annotations:
summary: "{{ $labels.job }} on {{ $labels.instance }} has not answered for 5 minutes"
- alert: DiskFullWithin24h
expr: predict_linear(node_filesystem_avail_bytes{job="node", fstype!~"tmpfs|overlay|squashfs"}[6h], 24 * 3600) < 0
for: 30m
labels:
severity: warning
annotations:
summary: "{{ $labels.mountpoint }} on {{ $labels.instance }} will be full within 24 hours at the current rate"for lässt Prometheus warten, bevor ein Alarm als ausgelöst gilt, damit ein einzelner verpasster Abruf dich nicht weckt [6]. predict_linear legt eine Gerade durch die letzten sechs Stunden und liest sie 24 Stunden später ab. Es funktioniert nur bei Gauges und braucht mindestens zwei Messwerte [8]. Unsere Einschätzung: Ein großer einmaliger Schreibvorgang, etwa ein Backup, das auf der Platte landet, kann die Gerade verbiegen. Die 30 Minuten bei for sind ein Kompromiss, den du anpassen darfst.
alertmanager.yml. Die Werte unten sind Platzhalter. Ersetze Host, Adressen und Benutzer durch die deines Mail-Anbieters. Alertmanager kann das SMTP-Passwort aus einer Datei lesen und verlangt TLS zum Server, solange du das nicht änderst [15]:
global:
smtp_smarthost: "smtp.example.org:587"
smtp_from: "alerts@example.org"
smtp_auth_username: "alerts@example.org"
smtp_auth_password_file: /etc/alertmanager/smtp_password
route:
receiver: mail
group_by: ["alertname", "instance"]
receivers:
- name: mail
email_configs:
- to: "you@example.org"
send_resolved: trueWähle einen Kanal, der nicht vom Homelab selbst abhängt. Ein Postfach bei einem externen Anbieter erfüllt das. Ein Mailserver auf der Maschine, die gerade abgestürzt ist, nicht.
Grafana-Datenquelle. Grafana liest Provisioning-Dateien beim Start [28]. Lege Folgendes in grafana/provisioning/datasources/prometheus.yml. Eine so angelegte Datenquelle lässt sich danach nicht mehr in der Weboberfläche bearbeiten [29]:
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://127.0.0.1:9090
isDefault: true
editable: falseStarten und prüfen. Führe im Ordner docker compose up -d aus. Danach:
ss -tlnpsollte die Ports 9090, 9100, 9093 und 3000 nur auf127.0.0.1zeigen.curl -s http://127.0.0.1:9090/-/healthyliefert den Health-Check von Prometheus [39]. Der von Grafana istGET /api/health[30].- Öffne Prometheus unter
http://127.0.0.1:9090, führeupaus und erwarte zwei Reihen mit dem Wert 1. - Prüfe eine geänderte Regel oder Konfiguration mit
docker compose exec prometheus promtool check rules /etc/prometheus/rules.ymlundpromtool check config /etc/prometheus/prometheus.yml[7]. Lade sie dann mitdocker compose kill -s SIGHUP prometheusneu. Ein Neuladen per HTTP geht auch, aber nur mit--web.enable-lifecycle; das ist standardmäßig aus, und wir lassen es aus [3][10].
Von einem anderen Rechner kommst du per SSH-Tunnel heran: ssh -L 3000:127.0.0.1:3000 benutzer@monitoring-host, dann öffnest du http://127.0.0.1:3000. Willst du Grafana direkt im LAN erreichen, setze GF_SERVER_HTTP_ADDR auf die LAN-Adresse des Hosts statt auf 0.0.0.0 und leite keinen Port am Router weiter. Für eine ordentliche Adresse mit HTTPS stell einen Reverse Proxy davor; siehe den Guide unten.
Grafana-Dashboard. Melde dich als admin mit dem Passwort aus .env an. Ohne diesen Schritt gilt admin/admin [27], überspring ihn also nicht. Das schnellste Dashboard ist das der Community: Dashboards, New, Import, ID 1860 („Node Exporter Full“), Datenquelle wählen [31][32]. Die Seite empfiehlt für einige Panels die zusätzlichen Optionen --collector.systemd und --collector.processes bei node_exporter [32]. Wir haben sie nicht eingeschaltet, deshalb können einzelne Panels leer bleiben. Für dein eigenes erstes Dashboard genügen diese Abfragen:
| Panel | Abfrage | Quelle |
|---|---|---|
| CPU im System-Modus | rate(node_cpu_seconds_total{mode="system"}[1m]) | Prometheus-Guide zu node_exporter [11] |
| Freier Plattenplatz | node_filesystem_avail_bytes | [11] |
| Netzwerk empfangen | rate(node_network_receive_bytes_total[1m]) | [11] |
| Arbeitsspeicher verfügbar | node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes | Metrikname aus einer Anleitung [37], prüfe ihn in deinem eigenen Prometheus |
Praxisbeispiel
Wie groß wird der Verlauf? Die Prometheus-Doku nennt eine grobe Formel: Plattenbedarf = Aufbewahrung in Sekunden × Messwerte pro Sekunde × Bytes pro Messwert, im Schnitt 1 bis 2 Bytes pro Messwert [1]. Deine eigene Zahl liefert scrape_samples_scraped{job="node"}; sie zeigt, wie viele Messwerte ein Abruf zurückgab [9]. Hier ein Rechenbeispiel mit einem erfundenen Wert von 1.500 Messwerten pro Abruf:
15 s Abstand → 1.500 / 15 = 100 Messwerte pro Sekunde
30 Tage → 30 × 86.400 s = 2.592.000 s
Messwerte in 30 Tagen → 100 × 2.592.000 = 259.200.000
bei 1 Byte pro Wert → etwa 0,26 GB
bei 2 Bytes pro Wert → etwa 0,52 GBDie 1.500 sind für die Methode ausgedacht; miss deine eigene Zahl. Wir weisen dem Prometheus-Volume 5 GB zu und setzen size: 4GB. Das sind 80 Prozent und folgt dem Rat von 80 bis 85 Prozent [1]. Die Größengrenze zählt das Write-ahead-Log mit, gelöscht werden zu ihrer Einhaltung aber nur gespeicherte Blöcke [1]. Zum Testen des Alarms stoppst du den Exporter mit docker compose stop node-exporter. Nach fünf Minuten plus einem Auswertungsintervall sollte InstanceDown auslösen, und eine Mail sollte ankommen. Starte ihn danach wieder und warte auf die „resolved“-Mail.
Prüfliste
- Prüfe vor dem Kopieren, ob jeder Image-Tag auf Docker Hub existiert, und notiere das Datum.
- Setze
GRAFANA_ADMIN_PASSWORDin.envvor dem ersten Start, und halte.envaus git heraus. - Binde jeden Dienst an
127.0.0.1, und bestätige es mitss -tlnp. - Schalte das Alertmanager-Clustering ab, wenn du ihn im Host-Netzwerk betreibst.
- Setze Aufbewahrungszeit und -größe in
prometheus.yml, und halte die Größe unter 85 Prozent des zugewiesenen Platzes. - Miss
scrape_samples_scraped, bevor du einer Größenschätzung traust. - Führe vor jedem Neuladen
promtool check configundpromtool check rulesaus. - Löse einen Alarm absichtlich aus, und bestätige, dass die Mail außerhalb deines Homelabs ankommt.
- Überwache Grafana und den Host mit Uptime Kuma von einem zweiten Gerät aus, damit der Wächter selbst bewacht wird.
- Entscheide, ob der Messwert-Verlauf ein Backup verdient. Die Prometheus-Doku empfiehlt Snapshots, und die brauchen die Admin-API [1][10]. Wir lassen sie aus und sichern stattdessen den Compose-Ordner und das Grafana-Volume.
Passt dazu: Uptime Kuma: merken, wenn das Homelab ausfällt; Prometheus-Exporter; Container und OCI; Homelab-Stromverbrauch richtig messen; Homeserver oder VPS: die Stromrechnung; Reverse Proxy im Homelab; WireGuard oder Tailscale fürs Homelab; Raspberry Pi 5: SD, USB-SSD oder NVMe?; Homelab-Backup mit restic oder Borg.