Files
0012/MONITORING.md
Frank Schwenk 85ab829805 feat: add monitoring dashboard under /monitor/
Status page and JSON API read from private/data; root index.php stays a placeholder. Mark todo 06 done.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-12 15:22:00 +02:00

167 lines
7.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Monitoring — externer PHP-Webspace (0012.de)
Der vServer **`boka`** (`89.163.231.180`) wird von **`0012.de`** (wint.global Classic 1.0, Plesk-Cron) aus überwacht. Der Webspace sieht den Server von außen — interne Metriken (Disk, Docker) brauchen ein Push-Skript auf boka oder eine Status-API.
**Webspace:** unabhängig von boka gehostet — fällt der VPS aus, kann 0012.de noch alarmieren.
Siehe auch: [`todo/03-monitoring-pull-phase1.md`](todo/03-monitoring-pull-phase1.md), [`todo/04-monitoring-push-boka.md`](todo/04-monitoring-push-boka.md), [`HOSTING.md`](HOSTING.md)
---
## Architektur (empfohlen)
### Ebene 1 — Pull (PHP-Cron auf Webspace, alle 5–15 Min)
- HTTPS-Checks auf öffentliche URLs
- SSL-Zertifikat-Ablauf
- Optional: TCP-Checks (Gitea SSH, RustDesk)
- Bei Fehler: E-Mail / Telegram (nach 2. Versuch, 2 Min Abstand → weniger Fehlalarme)
### Ebene 2 — Push (Cron auf boka, alle 5 Min) — **implementiert** (2026-06-12)
- Skript `~/server/scripts/push-status.sh` postet JSON an `ingest.php` (Token + IP-Whitelist)
- Payload: `load`, `disk_percent`, `mem_available_mb`, `containers_running`, `containers_unhealthy`
- `ingest.php` speichert nach `private/data/boka-status.json`
- `monitor.php` prüft: kein Push seit 15 Min → „boka silent“; optional Disk &gt; 85 %, unhealthy &gt; 0, Backup &gt; 25h
- Sicherheit: `BOKA_IP=89.163.231.180` — nur Requests von dieser IP werden akzeptiert (zusätzlich zum Token)
**Zwei Repos:** PHP in diesem Repo (Pull + Ingest); Push-Skript + Cron im boka-Repo (`~/server`). Deploy-Ablauf: [`todo/04-monitoring-push-boka.md`](todo/04-monitoring-push-boka.md); boka-seitig `docs/MONITORING-WORKFLOW.md`.
---
## Prio **high** — zuerst umsetzen
| Was | Wie (extern) | Warum |
|-----|----------------|-------|
| HTTPS-Erreichbarkeit kritischer Domains | `curl` / `file_get_contents`, Timeout ~10s, Status 200/301 | Einzelne Apps können down sein, ohne dass es auffällt (z. B. bringtake) |
| Traefik / Edge | `https://schwenk.online` + eine App-Domain + `https://gitea.schwenk.online` | Fällt Traefik oder Let's Encrypt aus, sind viele Sites betroffen |
| Gitea | HTTPS, optional Login-Seite erreichbar | Zentrale Git-/CI-Basis |
| Immich | `https://pics.schwenk.online` | Fotos, großer Datenbestand |
| SSL-Zertifikat-Ablauf | TLS-Handshake prüfen, Warnung bei &lt; 14 Tagen | Ablauf oder verlorenes `acme.json` = Ausfall vieler Dienste |
| Backup-Heartbeat | Server pingt nach erfolgreichem Backup den Webspace; Cron alarmiert bei **keinem Ping seit 25h** | Sobald Backups existieren: kritisch |
| Alarm bei Ausfall | E-Mail oder Telegram vom PHP-Cron | Externer Beobachter ohne Zugang zu boka |
### Mindest-URL-Liste (Start)
- `https://schwenk.online`
- `https://gitea.schwenk.online`
- `https://pics.schwenk.online`
- `https://medis.schwenk.online`
- `https://portainer.schwenk.online`
- Eine `bsc-gp.de`-Subdomain (z. B. `https://score.bsc-gp.de`)
- `https://vfb.red`
---
## Prio **medium** — bald sinnvoll
| Was | Wie (extern) | Warum |
|-----|----------------|-------|
| Weitere App-Domains | HTTP-Check pro Stack | Viele kleine Sites; einzelne Container können sterben |
| API-Health | z. B. `https://api.bringtake.schwenk.online/health` | Frontend kann 200 liefern, Backend tot |
| Antwortzeit | Dauer messen, Warnung bei &gt; 5s | Frühwarnung bei Last (Immich ML, viele Container) |
| Inhalt prüfen | Marker-String im HTML (`<title>`, fester Text) | Erkennt „200 aber leere/falsche Seite“ |
| HTTP→HTTPS-Redirect | `http://domain` → 301/308 | Kaputter Redirect = Browser-Warnungen |
| DNS-Auflösung | `gethostbyname` / DNS-API | Domain zeigt plötzlich woanders hin |
| Gitea SSH | TCP-Check Port **2222** (`fsockopen`) | Git per SSH unabhängig von der Web-UI |
| RustDesk | TCP **21115–21117** (falls genutzt) | Kein HTTP möglich |
| SSL pro Subdomain | Einzelcheck je Host | Nicht jeder Host nutzt dasselbe Zertifikat |
| Push-Status vom Server | `POST` an Webspace mit Token + JSON | Disk/RAM/Container sonst von außen unsichtbar |
### Weitere URLs (medium, nach und nach)
- `https://affen.schwenk.online`
- `https://bringtake.schwenk.online`
- `https://api.bringtake.schwenk.online`
- `https://link.schwenk.online`
- `https://traefik.schwenk.online` (nur wenn Dashboard öffentlich bleiben soll)
- Weitere `*.schwenk.online` und `*.bsc-gp.de` laut Inventory
---
## Prio **low** — nice to have
| Was | Wie (extern) | Warum |
|-----|----------------|-------|
| Alle ~25 Domains einzeln | Lange Checkliste | Hoher Pflegeaufwand; Stichproben reichen oft |
| Security Headers | HSTS, `X-Frame-Options` | Sicherheit, kein Verfügbarkeitsproblem |
| TLS-Version / Cipher | Nur TLS 1.2+ | Selten akut |
| Port-Scan light | 22, 80, 443, 2222 erwartet; **5432 nicht** offen | Postgres soll nicht öffentlich sein |
| Blacklist / Malware-Scan | Externe API | Für Homelab meist overkill |
| WHOIS / Domain-Ablauf | Registrar-API | Oft ohnehin Mail vom Registrar |
| Öffentliche Feeds | RSS/iCal-Outputs | Nur wenn businesskritisch |
| Synthetic Login | Formular-POST mit Test-User | Aufwendig, bricht bei UI-Änderungen |
| Response-Größe | Plötzlich sehr kleine Antwort | Selten nötig |
| Uptime-Dashboard / SLA | DB auf Webspace | Nach echten Checks |
---
## Von außen schlecht prüfbar (ohne Hilfsskript auf boka)
| Intern | Lösung |
|--------|--------|
| Disk voll, RAM, Load | Push-Endpoint (Ebene 2) |
| `docker ps`, exited containers | Status-JSON von boka pushen |
| Log-Fehler, OOM | Push oder zentraler Log-Dienst |
| Dangling volumes, Backup-Größe | Nur auf dem Host |
| fail2ban / SSH-Bruteforce | Auth-Log per Push oder separater Dienst |
**Pragmatisch:** `monitor-push.sh` auf boka (Cron alle 5 Min) → POST an Webspace:
```json
{
"token": "...",
"load": [1.2, 0.8, 0.5],
"disk_percent": 55,
"mem_available_mb": 4700,
"containers_running": 38,
"containers_unhealthy": 0,
"backup_last_success": "2026-06-10T03:00:00+02:00"
}
```
---
## Umsetzung in Phasen
### Phase 1 (high, ~1h)
- 8–12 HTTPS-URLs aus der Mindestliste
- SSL-Ablauf &lt; 14 Tage → Warnung
- E-Mail bei Fehler, Retry nach 2 Minuten
### Phase 2 (medium)
- API-Health für Stacks mit Backend (bringtake, medis, affen, …)
- Latenz-Schwelle
- Backup-Heartbeat (sobald Backups existieren) — Ingest-Feld `backup_last_success` vorbereitet
- ~~Push-Status von boka~~ → erledigt (Todo 04)
### Phase 3 (low)
- Restliche Domains, Header-Checks, Dashboard
---
## Dateien
| Ort | Datei | Zweck |
|-----|-------|--------|
| Webspace | `monitor.php` | Cron: Pull-Checks + boka-Stale/Schwellen |
| Webspace | `monitor/index.php` | Öffentliches Status-Dashboard (`/monitor/`, noindex) |
| Webspace | `monitor/status.php` | Read-only JSON-API (`/monitor/status.php`, Alias `status.json`) |
| Webspace | `ingest.php` | Empfang Push von boka (Token + IP) |
| Webspace | `private/data/last-checks.json` | Letzte Pull-Check-Ergebnisse |
| Webspace | `private/data/boka-status.json` | Letzter Push-Stand |
| boka | `~/server/scripts/push-status.sh` | Sammelt Metriken, POST an Webspace |
| boka | `~/server/config/push.env` | `INGEST_URL`, `PUSH_TOKEN` |
| boka | Crontab | `*/5 * * * *` push-status |
---
## Hinweise
- **Portainer** und **Traefik-Dashboard** öffentlich monitoren = öffentlich bestätigen, dass sie erreichbar sind. Basic Auth beibehalten; Monitoring prüft nur Erreichbarkeit (und ggf. 401 als „ok“).
- **Exit 401/403** kann bei geschützten Diensten **erwünscht** sein — Checks pro Host konfigurieren.
- Externer Monitor ersetzt kein **fail2ban** oder **UFW-Audit** auf boka (separates boka-Repo).