Inbetriebnahme
Die Anwendung wird entweder als veröffentlichte .NET-9-Anwendung (Windows oder Linux) oder als Docker-Image ausgeliefert. Wählen Sie einen der beiden Wege.
Voraussetzungen
- Eine SQL-Server-Instanz für die Überwachungsdatenbank (der eigene Metadatenspeicher
der Anwendung). Version 2017 oder neuer. SQL Express genügt. Empfohlen: eine eigene
Datenbank namens
SqlServerHealthMonitor. - Ein Dienstkonto, das
CREATE DATABASEausführen darf (nur beim ersten Start), oder eine leere, bereits angelegte Datenbank mit vollen Lese- und Schreibrechten. - Für jeden überwachten SQL Server: ein Konto mit geringen Rechten, das
VIEW SERVER STATE,VIEW DATABASE STATEsowieSELECTaufmsdb.dbo.sysjobs*besitzt, falls Sie die SQL-Agent-Aufträge sehen möchten.- SQL Server 2022 und neuer hat diese Berechtigungen aufgeteilt. Bei Instanzen ab 2022
vergeben Sie stattdessen
VIEW SERVER PERFORMANCE STATEundVIEW DATABASE PERFORMANCE STATE— mitVIEW SERVER STATEallein scheitern die Index-Scans mit „The VIEW SERVER PERFORMANCE STATE permission was denied“ (Fehler 300). - Das Konto braucht außerdem einen Benutzer in jeder Datenbank, die durchsucht werden
soll. Fehlt er, schlägt
USE [db]sofort fehl (Fehler 916) und die Datenbank wird auf/performance/index-healthals übersprungen ausgewiesen. - Das Fehlerprotokoll zu lesen (
/error-log) erfordert zwei Berechtigungen, dieVIEW SERVER STATEnicht einschließt, sowie einen Benutzer inmaster— dort liegen die Prozeduren. Siehe den zweiten Block unten. Ohne sie meldet genau diese eine Seite, was zu vergeben ist; alles andere bleibt unberührt. - Betriebssystem-Metriken (CPU, Arbeitsspeicher und Datenträger des Hosts, angezeigt
unter
/storage) werden per WMI vom Windows-Host gelesen, nicht über die SQL-Verbindung. Sie benötigen daher eine Windows-Berechtigung statt einer SQL-Berechtigung — siehe „Betriebssystem-Metriken über WMI“ weiter unten. Ohne sie bleibt nur diese eine Kachel leer.
- SQL Server 2022 und neuer hat diese Berechtigungen aufgeteilt. Bei Instanzen ab 2022
vergeben Sie stattdessen
-- Auf einer überwachten Instanz ab SQL Server 2022
GRANT VIEW SERVER PERFORMANCE STATE TO [monitoring_login];
GRANT VIEW ANY DEFINITION TO [monitoring_login];
-- Je Datenbank, die durchsucht werden soll
USE [YourDatabase];
CREATE USER [monitoring_login] FOR LOGIN [monitoring_login];
GRANT VIEW DATABASE PERFORMANCE STATE TO [monitoring_login]; -- ab 2022
-- GRANT VIEW DATABASE STATE TO [monitoring_login]; -- 2019 und älter
Der Zugriff auf das Fehlerprotokoll (/error-log) ist davon getrennt, denn
sys.xp_readerrorlog und sys.xp_enumerrorlogs liegen in master und werden von keiner
VIEW ... STATE-Berechtigung abgedeckt. Die Anmeldung braucht einen Benutzer in master,
damit die Berechtigungen überhaupt irgendwo landen können — dieser Schritt wird am häufigsten
übersehen:
USE master;
CREATE USER [monitoring_login] FOR LOGIN [monitoring_login];
GRANT EXECUTE ON sys.xp_readerrorlog TO [monitoring_login]; -- Protokoll lesen
GRANT EXECUTE ON sys.xp_enumerrorlogs TO [monitoring_login]; -- Archive auflisten
Eine Mitgliedschaft in securityadmin funktioniert ebenfalls und wird in den meisten
Anleitungen empfohlen, doch damit lassen sich Anmeldungen anlegen und Kennwörter
zurücksetzen — erheblich mehr, als ein Überwachungskonto besitzen sollte. Der Grund für
diesen Ratschlag sind die Hüllen sp_readerrorlog und sp_enumerrorlogs: Sie enthalten eine
interne securityadmin-Prüfung, die keine Berechtigung erfüllt. Der Monitor ruft genau
deshalb die darunterliegenden erweiterten Prozeduren direkt auf und kommt ohne die Rolle aus.
Betriebssystem-Metriken über WMI
Die Host-Kachel auf /storage beantwortet die Frage, die die DMVs nicht beantworten können:
Was läuft sonst noch auf diesem Rechner? SQL Server meldet die eigene CPU-Last und den eigenen
Speicher — ein Sicherungsagent, ein Virenscan oder eine zweite Instanz taucht dort nur als
Warten auf, nie als Ursache.
Agentenlos bleibt es trotzdem: Auf dem überwachten Rechner wird nichts installiert, der Monitor fragt WMI so ab, wie es der Systemmonitor tut. Die Abfrage läuft unter dem Dienstkonto des Monitors, es müssen also nirgends Zugangsdaten hinterlegt werden. Der Preis dafür: Das Konto muss auf dem überwachten Host bekannt sein — ein Host in einer anderen Domäne oder in einer Arbeitsgruppe antwortet mit „Zugriff verweigert“, und das Protokoll nennt genau diesen Grund.
Auf jedem überwachten Windows-Host, für das Dienstkonto des Monitors:
- Mitgliedschaft in Leistungsüberwachungsbenutzer (und, für entferntes DCOM, in Distributed COM-Benutzer).
- Remoteaktivierung für den WMI-Namensraum
root\cimv2(wmimgmt.msc → WMI-Steuerung → Eigenschaften → Sicherheit). - Die eingehende Firewallregel Windows-Verwaltungsinstrumentation (WMI eingehend) aktiviert.
In zwei Fällen ist das bewusst nicht verfügbar: Azure SQL Database und Managed Instance
haben keinen Host, den wir auslesen könnten (der Monitor weiß das und überspringt sie), und
ein Monitor, der im Linux-Container läuft, kann WMI überhaupt nicht nutzen — die Kachel
sagt das dann, statt Nullen anzuzeigen. Die Erfassung lässt sich mit
OsMetrics:Enabled = false ganz abschalten; Aufbewahrungsdauer und Zeitlimit je Host liegen
im selben Abschnitt (Standardwerte: 30 Tage, 10 Sekunden).
Windows — physisch oder virtuell
# Als Dienstkonto
dotnet publish -c Release -r win-x64 --self-contained false -o C:\Apps\SqlServerHealthMonitor
# Konfiguration für den ersten Start
cd C:\Apps\SqlServerHealthMonitor
notepad appsettings.json
# ConnectionStrings:DefaultConnection auf Ihre Überwachungsdatenbank setzen
# SecuritySettings:RequireHttps und SecuritySettings:HttpsPort prüfen
# Interaktiv starten und prüfen
.\SqlServerHealthMonitor.exe
Wenn die Anwendung startet und Now listening on: https://[::]:8443 protokolliert, ist alles
in Ordnung. Rufen Sie https://localhost:8443 auf (die Warnung wegen des selbstsignierten
Zertifikats beim ersten Mal bestätigen).
Als Windows-Dienst
Der MSI-Installer (
docs/installer.md) erledigt alle folgenden Schritte für Sie und ist der empfohlene Weg. Nutzen Sie die manuellen Befehle hier nur, wenn Sie die Installation lieber selbst skripten.
# Den interaktiven Lauf beenden, dann:
sc.exe create "SqlServerHealthMonitor" `
binPath= "C:\Apps\SqlServerHealthMonitor\SqlServerHealthMonitor.exe" `
start= auto `
DisplayName= "SQL Server Health Monitor"
sc.exe description "SqlServerHealthMonitor" "Monitors SQL Server fleet health and alerts on degradations."
sc.exe start "SqlServerHealthMonitor"
Der Dienst läuft standardmäßig als LocalSystem. Für den Betrieb unter einem Domänenkonto
(empfohlen, wenn die Überwachungsdatenbank über integrierte Sicherheit erreicht wird):
sc.exe config "SqlServerHealthMonitor" obj= "DOMAIN\monitor-svc" password= "..."
sc.exe stop "SqlServerHealthMonitor"
sc.exe start "SqlServerHealthMonitor"
Linux — systemd
sudo dotnet publish -c Release -r linux-x64 --self-contained false -o /opt/sshm
sudo useradd --system --no-create-home sshm
sudo chown -R sshm:sshm /opt/sshm
sudo tee /etc/systemd/system/sshm.service <<'EOF'
[Unit]
Description=SQL Server Health Monitor
After=network.target
[Service]
WorkingDirectory=/opt/sshm
ExecStart=/usr/bin/dotnet /opt/sshm/SqlServerHealthMonitor.dll
User=sshm
Restart=on-failure
RestartSec=10
Environment=ASPNETCORE_ENVIRONMENT=Production
SyslogIdentifier=sshm
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now sshm
sudo journalctl -u sshm -f
Docker
docker run -d --name sshm \
-p 8443:8443 \
-v sshm-keys:/root/.local/share/SqlServerHealthMonitor \
-e ASPNETCORE_ENVIRONMENT=Production \
-e ConnectionStrings__DefaultConnection="Server=db;Database=SqlServerHealthMonitor;User Id=sshm;Password=...;TrustServerCertificate=true" \
sqlserverhealthmonitor:latest
Empfohlen: Behalten Sie die Volume-Einbindung
-v sshm-keys:/root/.local/share/SqlServerHealthMonitor bei. Ohne sie werden die
DataProtection-Schlüssel bei jedem Containerneustart neu erzeugt, was alle Benutzer abmeldet
und das selbstsignierte Zertifikat neu ausstellt. Ihre verschlüsselten Spalten sind davon
nicht betroffen — die schützt der feste Encryption:Key, nicht der Schlüsselbund. Siehe
Sicherung & Wiederherstellung.
Hinter einem Reverse Proxy (Traefik / nginx)
Wenn TLS am Proxy terminiert wird, schalten Sie die HTTPS-Bindung der Anwendung ab:
// appsettings.Production.json
{
"SecuritySettings": {
"RequireHttps": false,
"BindHttps": false
}
}
… und lassen den Proxy per einfachem HTTP auf Port 8080 mit dem Container sprechen.
HTTPS und Zertifikate
Standardverhalten: Beim ersten Start wird ein selbstsigniertes RSA-2048-Zertifikat erzeugt und
unter %LOCALAPPDATA%\SqlServerHealthMonitor\Certs\sshm-server.pfx (Windows) bzw.
~/.local/share/SqlServerHealthMonitor/Certs/sshm-server.pfx (Linux) abgelegt. Das
Startprotokoll nennt den genauen Pfad samt einer Warnung „REPLACE FOR PRODUCTION“.
Um ein eigenes Zertifikat zu verwenden (von einer öffentlichen oder internen CA):
{
"SecuritySettings": {
"BindHttps": true,
"HttpsPort": 8443,
"CertificatePath": "C:\\certs\\sshm.pfx",
"CertificatePassword": "..."
}
}
Um das selbstsignierte Zertifikat neu erzeugen zu lassen (etwa nach einer Namensänderung des
Hosts): die .pfx löschen und neu starten. Es wird automatisch ein neues mit den aktuellen
alternativen Antragstellernamen erstellt.
Erstes Administratorkonto
Beim ersten Start erkennt die Anmeldeseite, dass noch kein Administrator existiert, und
leitet auf /Account/Setup weiter. Wählen Sie einen Benutzernamen und ein starkes Kennwort —
daraus wird der erste Administrator, der anschließend unter /Settings/Users weitere Benutzer
anlegen kann.
Ist appsettings.json:InitialAdmin:Password gesetzt, wird dieses Kennwort statt des
Einrichtungsablaufs verwendet (eine Warnung wird protokolliert, wenn es schwach oder ein
bekannter Platzhalter ist). Existiert InitialAdmin ohne Kennwort, wird ein starkes Kennwort
erzeugt und in INITIAL_ADMIN_PASSWORD.txt im Inhaltsverzeichnis der Anwendung abgelegt —
bewusst nicht im Anwendungsprotokoll. Lesen Sie diese Datei, melden Sie sich an, ändern Sie
das Kennwort und löschen Sie die Datei. (Lässt sich die Datei nicht schreiben, wird das
Kennwort ersatzweise protokolliert.)
Nach der Anmeldung: Zwei-Faktor-Anmeldung unter /Account/Security aktivieren. Für jeden
Administrator empfohlen.
Geheimnisse und sichere Konfiguration
Halten Sie Geheimnisse aus appsettings.json heraus (die Datei liegt in der Versionsverwaltung).
Jeder Konfigurationswert lässt sich über eine Umgebungsvariable setzen, mit __ (doppelter
Unterstrich) für die Verschachtelung — diese überschreiben die JSON-Dateien automatisch:
| Geheimnis | Umgebungsvariable |
|---|---|
| Datenbankverbindung | ConnectionStrings__DefaultConnection |
| Überwachungsdatenbank | ConnectionStrings__MonitoringDatabase |
| Kennwort des ersten Administrators | InitialAdmin__Password |
| OIDC-Clientgeheimnis | OidcSettings__ClientSecret |
| Öffentlicher Lizenzschlüssel | Licensing__PublicKeyBase64 |
# Docker
docker run -e ConnectionStrings__DefaultConnection="Server=db;Database=SQLSpa;User Id=svc;Password=…;TrustServerCertificate=true" …
# systemd-Unit
Environment=ConnectionStrings__DefaultConnection=Server=db;Database=SQLSpa;…
Hinweise:
- Produktivschutz: Die Anwendung verweigert den Start, wenn
ConnectionStrings:DefaultConnectionin der UmgebungProductionleer ist — setzen Sie den Wert vor dem ersten Start. - Lokale Entwicklung:
dotnet user-secretsverwenden (das Projekt hat bereits eine UserSecretsId), stattappsettings.Development.jsonzu bearbeiten. - Geheimnisse der Benachrichtigungskanäle (E-Mail/Teams/PagerDuty) liegen verschlüsselt in der Datenbank, nicht in der Konfiguration. Sie werden unter Einstellungen → Benachrichtigungen gepflegt. Werte in appsettings dienen nur dazu, die Datenbank beim ersten Start einmalig vorzubelegen.
Encryption:Keyist es, was die gespeicherten Verbindungszeichenfolgen und Benachrichtigungsgeheimnisse verschlüsselt (AES-256-GCM). Lassen Sie ihn ungesetzt, um den eingebauten Standard zu nutzen, oder setzen Sie einen eigenen 32-Byte-Base64-Schlüssel — und sichern Sie diesen dann gemeinsam mit der Datenbank, denn ohne ihn lassen sich diese Spalten von nichts mehr entschlüsseln (siehebackup-and-restore.md).- DataProtection-Schlüssel decken allein den Schlüsselbund des Frameworks ab: Anmelde-Cookies, Antiforgery-Token, das selbstsignierte Zertifikat. Geht dieser Ordner verloren, kostet das eine erneute Anmeldung, keine Daten.