Zum Inhalt springen

Server-Monitoring mit Grafana und Prometheus: Metriken, Dashboards und Alerting

Veröffentlicht am 28. Nov. 2025 | ca. 5 Min. Lesezeit |

Ein Server ohne Monitoring ist ein blinder Fleck. Man erfährt von Problemen erst, wenn der Nutzer sich beschwert — oder wenn der Server bereits abgestürzt ist. Prometheus sammelt Metriken, Grafana visualisiert sie und sendet Alerts. Zusammen bilden sie das de-facto Standard-Monitoring-Stack für Server und Kubernetes.

Architektur des Stacks

Server              Prometheus          Grafana
[Node Exporter] ──→ [Scraping]  ──→  [Dashboards]
[nginx Exporter]    [Storage]         [Alerting]
[PHP-FPM Exporter]  [Query (PromQL)]  [Notifications]
[Blackbox Exporter]                   └── Email/Slack

Prometheus "scrapet" Metriken von Exportern in regelmäßigen Intervallen (Standard: 15 Sekunden). Die Metriken werden in einer Zeitreihendatenbank gespeichert. Grafana verbindet sich mit Prometheus als Datenquelle und rendert Dashboards.

Setup mit Docker Compose

# docker-compose.yml
version: '3.8'

services:
    prometheus:
        image: prom/prometheus:v2.50.0
        container_name: prometheus
        volumes:
            - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
            - prometheus_data:/prometheus
        command:
            - '--config.file=/etc/prometheus/prometheus.yml'
            - '--storage.tsdb.retention.time=30d'
        ports:
            - "9090:9090"
        restart: unless-stopped

    grafana:
        image: grafana/grafana-oss:10.3.0
        container_name: grafana
        environment:
            GF_SECURITY_ADMIN_USER: admin
            GF_SECURITY_ADMIN_PASSWORD: "${GRAFANA_PASSWORD}"
            GF_SERVER_ROOT_URL: https://monitoring.example.com
        volumes:
            - grafana_data:/var/lib/grafana
            - ./grafana/provisioning:/etc/grafana/provisioning
        ports:
            - "3000:3000"
        depends_on:
            - prometheus
        restart: unless-stopped

    node-exporter:
        image: prom/node-exporter:v1.7.0
        container_name: node-exporter
        pid: host
        volumes:
            - /proc:/host/proc:ro
            - /sys:/host/sys:ro
            - /:/rootfs:ro
        command:
            - '--path.procfs=/host/proc'
            - '--path.sysfs=/host/sys'
            - '--path.rootfs=/rootfs'
        ports:
            - "9100:9100"
        restart: unless-stopped

volumes:
    prometheus_data:
    grafana_data:

Prometheus Konfiguration

# prometheus/prometheus.yml
global:
    scrape_interval: 15s
    evaluation_interval: 15s

alerting:
    alertmanagers:
        - static_configs:
              - targets: ['alertmanager:9093']

rule_files:
    - /etc/prometheus/rules/*.yml

scrape_configs:
    - job_name: 'prometheus'
      static_configs:
          - targets: ['localhost:9090']

    - job_name: 'node'
      static_configs:
          - targets: ['node-exporter:9100']
      scrape_interval: 30s

    - job_name: 'nginx'
      static_configs:
          - targets: ['nginx-exporter:9113']

    - job_name: 'php-fpm'
      static_configs:
          - targets: ['php-fpm-exporter:9253']

    # Blackbox für HTTP-Monitoring
    - job_name: 'blackbox-http'
      metrics_path: /probe
      params:
          module: [http_2xx]
      static_configs:
          - targets:
                - https://www.wunner-software.de
                - https://firma-neu.ddev.site
      relabel_configs:
          - source_labels: [__address__]
            target_label: __param_target
          - source_labels: [__param_target]
            target_label: instance
          - target_label: __address__
            replacement: blackbox-exporter:9115

Wichtige Metriken und PromQL

PromQL (Prometheus Query Language) ist die Abfragesprache für Metriken.

CPU-Auslastung

# CPU-Nutzung in Prozent (ohne idle)
100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

# Load Average (1 Minute)
node_load1

Memory

# Verfügbarer Arbeitsspeicher in Prozent
(node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100

# Swapnutzung
(1 - (node_memory_SwapFree_bytes / node_memory_SwapTotal_bytes)) * 100

Festplattenplatz

# Freier Festplattenplatz in Prozent
(node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100

# Festplatten-IO
rate(node_disk_io_time_seconds_total[5m])

nginx Metriken

# Aktive Verbindungen
nginx_connections_active

# Requests pro Sekunde
rate(nginx_http_requests_total[5m])

# 4xx und 5xx Fehlerrate
rate(nginx_http_requests_total{status=~"[45].."}[5m])
    / rate(nginx_http_requests_total[5m]) * 100

HTTP-Verfügbarkeit (Blackbox Exporter)

# 1 = Up, 0 = Down
probe_success

# SSL-Zertifikat läuft ab in X Tagen
(probe_ssl_earliest_cert_expiry - time()) / 86400

Alerting-Regeln

# prometheus/rules/alerts.yml
groups:
    - name: server
      rules:
          - alert: HighCPUUsage
            expr: >
                100 - (avg by (instance)
                (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85
            for: 5m
            labels:
                severity: warning
            annotations:
                summary: "Hohe CPU-Auslastung auf {{ $labels.instance }}"
                description: "CPU-Auslastung {{ $value | printf \"%.1f\" }}% > 85% seit 5 Minuten"

          - alert: LowDiskSpace
            expr: >
                (node_filesystem_avail_bytes{mountpoint="/"}
                / node_filesystem_size_bytes{mountpoint="/"}) * 100 < 10
            for: 1m
            labels:
                severity: critical
            annotations:
                summary: "Wenig Festplattenplatz auf {{ $labels.instance }}"
                description: "Noch {{ $value | printf \"%.1f\" }}% freier Speicher auf /"

          - alert: HighMemoryUsage
            expr: >
                (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 90
            for: 5m
            labels:
                severity: critical
            annotations:
                summary: "Sehr hohe Speicherauslastung"

          - alert: SiteDown
            expr: probe_success == 0
            for: 1m
            labels:
                severity: critical
            annotations:
                summary: "Website nicht erreichbar: {{ $labels.instance }}"

          - alert: SSLCertificateExpiringSoon
            expr: (probe_ssl_earliest_cert_expiry - time()) / 86400 < 14
            for: 1h
            labels:
                severity: warning
            annotations:
                summary: "SSL-Zertifikat läuft bald ab: {{ $labels.instance }}"
                description: "Noch {{ $value | printf \"%.0f\" }} Tage bis zum Ablauf"

Grafana Dashboard provisioning

# grafana/provisioning/dashboards/dashboards.yml
apiVersion: 1

providers:
    - name: 'default'
      orgId: 1
      folder: ''
      type: file
      options:
          path: /etc/grafana/provisioning/dashboards

Für Server-Monitoring empfiehlt sich der fertige "Node Exporter Full" Dashboard (ID: 1860) von grafana.com — importieren über Dashboard → Import → ID 1860.

Benachrichtigungen: E-Mail und Slack

In Grafana unter Alerting → Contact Points:

{
    "name": "email-alert",
    "type": "email",
    "settings": {
        "addresses": "thomas@wunner-software.de",
        "subject": "[{{ .Status | toUpper }}] {{ .CommonAnnotations.summary }}"
    }
}

Für Slack:

{
    "name": "slack-alert",
    "type": "slack",
    "settings": {
        "url": "https://hooks.slack.com/services/xxx/yyy/zzz",
        "channel": "#monitoring",
        "title": "{{ .CommonAnnotations.summary }}",
        "text": "{{ .CommonAnnotations.description }}"
    }
}

Fazit

Prometheus und Grafana sind der Industriestandard für Open-Source-Monitoring aus gutem Grund: flexibel, skalierbar, mit riesigem Ökosystem an Exportern. Für einen typischen Web-Server (nginx, PHP-FPM, MariaDB) genügen Node Exporter, nginx Exporter und Blackbox Exporter, um vollständige Sichtbarkeit zu erhalten.

Die wichtigsten Metriken, die man im Blick haben sollte:

  1. CPU und Memory Auslastung
  2. Festplattenplatz (mit Trend)
  3. HTTP-Verfügbarkeit und Antwortzeiten
  4. SSL-Zertifikat-Ablaufdatum
  5. Error-Rate in nginx-Logs
Thomas Wunner

Thomas Wunner

Fachinformatiker für Anwendungsentwicklung mit Ausbildereignungsprüfung und über 14 Jahre Erfahrung im Aufbau skalierbarer Webanwendungen mit Symfony und Shopware. Abseits der Tastatur ist Thomas als Rettungsschwimmer in der Wasserwacht aktiv, legt als DJ auf und erkundet die Umgebung auf dem Motorrad.

Kommentare

Kommentare werden von Remark42 bereitgestellt. Beim Laden werden Daten an unseren Kommentar-Server übertragen.