Import und Export in Uptime Kuma

Ich benötigte für ein Projekt ein kleines Monitoring Tool, welches eine Vielzahl an PCs überwacht und mir anzeigt, wann welcher PC eingeschaltet war.
Für die Umsetzung habe ich Uptime Kuma genutzt. Da es sich um meherere hundert PCs handelt, wollte ich diese gerne per CSV importieren, da das manuelle anlegen zu aufwendig gewesen wäre.
Danach wollte ich bei Bedarf einen Export machen können, der mir den Online-Status der PCs anzeigt.

Schritt 1: Uptime Kuma installieren

Die Installation erfolgte mit Docker Compose.

mkdir -p /opt/uptime-kuma
cd /opt/uptime-kuma
nano compose.yaml

Nun folgendes Docker Compose Script erstellen und die MariaDB-Passwörter ändern.

services:
  mariadb:
    image: mariadb:11
    container_name: uptime-kuma-db
    restart: unless-stopped
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: <SICHERES_PASSWORT>
      MYSQL_DATABASE: uptime_kuma
      MYSQL_USER: kuma
      MYSQL_PASSWORD: <SICHERES_PASSWORT>
    volumes:
      - ./mariadb_data:/var/lib/mysql

  uptime-kuma:
    image: louislam/uptime-kuma:2
    container_name: uptime-kuma
    restart: always
    ports:
      - "30001:3001"
    volumes:
      - ./data:/app/data
    environment:
      - TZ=Europe/Berlin
      - UMASK=0022
    depends_on:
      - mariadb
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3001"]
      interval: 30s
      retries: 3
      start_period: 10s
      timeout: 5s
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

Nun muss der Compose-Stack noch gestartet werden.

docker compose up -d

Schritt 2: Reverse Proxy und SSL-Zertifikat

Da der Server in einem Netzwerk mit sehr vielen PCs hängt, sollte das Webinterface nur per https aufrufbar sein. Dafür habe ich einen Nginx Reverse Proxy genutzt.

apt update && sudo apt install nginx -y

Danach ein selbstsigniertes SSL-Zertifikat generieren. Die IP-Adressen müssen noch angepasst werden.

sudo mkdir -p /etc/nginx/ssl

sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
  -keyout /etc/nginx/ssl/selfsigned.key \
  -out /etc/nginx/ssl/selfsigned.crt \
  -subj "/CN=192.168.x.x" \
  -addext "subjectAltName=IP:192.168.x.x"

Nun die Konfigurationsdatei erstellen:

sudo nano /etc/nginx/sites-available/uptime-kuma

# HTTP → HTTPS Weiterleitung (optional, aber empfohlen)
server {
    listen 80;
    server_name _;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name _;  # "_" akzeptiert Anfragen auf jede IP/Domain

    ssl_certificate     /etc/nginx/ssl/selfsigned.crt;
    ssl_certificate_key /etc/nginx/ssl/selfsigned.key;

    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;

    location / {
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   Host $host;
        proxy_pass         http://localhost:30001/;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection "upgrade";
    }
}

Nun noch die Konfiguration aktivueren und Nginx starten.

# Symlink erstellen
sudo ln -s /etc/nginx/sites-available/uptime-kuma /etc/nginx/sites-enabled/

# Syntax prüfen
sudo nginx -t

# nginx neu laden
sudo systemctl reload nginx

Es bietet sich ausserdem an die UFW Firewall zu aktivieren und Port 80/tcp und 443/tcp freizugeben.
Dafür gibt es bereits folgende Anleitung:
https://checkpoint-it.net/firewall-mit-ufw-konfigurieren/

Schritt 3: Uptime Kuma einrichten

Wenn alles geklappt hat sollte Uptime Kuma nun über die IP im Brwoser aufrufbar sein.
Als Datenbankverbindung muss „MariaDB/MySQL“ ausgewählt werden und mit den Zugangsdaten aus der Compose-Datei gefüllt werden.
Als Host „mariadb“ eintragen

Schritt 4: Importscript erstellen

Um nun den Import der Geräte vorzunehmen wird als erstes eine CSV-Datei namen Geraete.csv benötigt, welche nach folgenden Schema erstellt werden muss:

nano /opt/uptime-kuma/Geraete.csv

#Name;Typ;IPv4
raum1-pc00;COMPUTER;192.168.1.100
raum2-pc01;COMPUTER;192.168.1.101
raum3-pc02;COMPUTER;192.168.1.102

Jetzt muss Python und die benötigte Python Bibliothek installiert werden:

sudo apt install python3-pip -y
pip3 install uptime-kuma-api --break-system-packages
pip3 install mysql-connector-python --break-system-packages

Jetzt das Script erstellen und die folgenden 3 Zeilen anpassen:

UPTIME_KUMA_URL = "http://localhost:30001"
USERNAME        = "UPTIME-KUMA-BENUTZER"
PASSWORD        = "UPTIME-KUMA-PASSWORT"

Hier das Script:

nano import_uptime_kuma.py
#!/usr/bin/env python3
"""
Uptime Kuma Monitor Import
Liest eine CSV-Datei und legt alle Geräte als Ping-Monitor an.

Verwendung:
    python3 import_uptime_kuma.py
"""

from uptime_kuma_api import UptimeKumaApi, MonitorType
import csv
import sys

# -------------------------------------------------------
# KONFIGURATION – hier anpassen
# -------------------------------------------------------
UPTIME_KUMA_URL = "http://localhost:30001"
USERNAME        = "UPTIME-KUMA-BENUTZER"
PASSWORD        = "UPTIME-KUMA-PASSWORT"
CSV_DATEI       = "Geraete.csv"             # Pfad zur CSV-Datei
PING_INTERVALL  = 300                       # Sekunden (300 = 5 Minuten)
# -------------------------------------------------------

def main():
    print(f"Verbinde mit Uptime Kuma unter {UPTIME_KUMA_URL} ...")
    try:
        api = UptimeKumaApi(UPTIME_KUMA_URL)
        api.login(USERNAME, PASSWORD)
        print("Login erfolgreich.\n")
    except Exception as e:
        import traceback
        traceback.print_exc()
        sys.exit(1)

    # Vorhandene Monitore laden, um Duplikate zu vermeiden
    vorhandene = api.get_monitors()
    vorhandene_namen = {m["name"] for m in vorhandene}
    print(f"{len(vorhandene_namen)} Monitore bereits vorhanden.\n")

    hinzugefuegt = 0
    uebersprungen = 0
    fehler = 0

    with open(CSV_DATEI, encoding="utf-8-sig") as f:
        reader = csv.DictReader(f, delimiter=";")
        for zeile in reader:
            name = zeile["#Name"].strip()
            ip   = zeile["IPv4"].strip()

            if not name or not ip:
                continue

            if name in vorhandene_namen:
                print(f"  [SKIP]  {name} ({ip}) – bereits vorhanden")
                uebersprungen += 1
                continue

            try:
                api.add_monitor(
                    type=MonitorType.PING,
                    name=name,
                    hostname=ip,
                    interval=PING_INTERVALL,
                )
                print(f"  [OK]    {name} ({ip})")
                hinzugefuegt += 1
            except Exception as e:
                print(f"  [FEHLER] {name} ({ip}): {e}")
                fehler += 1

    api.disconnect()

    print(f"\n--- Fertig ---")
    print(f"Hinzugefügt:   {hinzugefuegt}")
    print(f"Übersprungen:  {uebersprungen}")
    print(f"Fehler:        {fehler}")

if __name__ == "__main__":
    main()

Nun das Script ausführen:

python3 import_uptime_kuma.py

Das Ergebnis sollte in etwa so aussehen:

[OK]    raum1-pc00 (192.168.1.100
...
--- Fertig ---
Hinzugefügt:   150
Übersprungen:  0
Fehler:        0

Wichtig: Das Skript prüft automatisch ob ein Monitor mit dem gleichen Namen schon existiert und überspringt ihn dann – du kannst es also problemlos mehrfach ausführen ohne Duplikate zu erzeugen.

Schritt 5: Export der Daten

Nun müssen die Daten noch exportiert werden. Dazu folgendes Export.Script erstellen und das „DB_PASSWORD“ anpassen:

nano /opt/uptime-kuma/export_uptime_kuma.py
#!/usr/bin/env python3
"""
Uptime Kuma - Online-Zeiten Export
Exportiert pro Gerät und Tag die Online-Zeiten aus der MariaDB in eine CSV-Datei.

Verwendung:
    python3 export_uptime_kuma.py

Voraussetzungen:
    pip3 install mysql-connector-python --break-system-packages
"""

import mysql.connector
import csv
from datetime import datetime, date

# -------------------------------------------------------
# KONFIGURATION – hier anpassen
# -------------------------------------------------------
DB_HOST     = "127.0.0.1"
DB_PORT     = 3306          # Standard MariaDB Port (nicht der Docker-Port!)
DB_NAME     = "uptime_kuma"
DB_USER     = "kuma"
DB_PASSWORD = "DATENBANK-PASSWORT"

# Zeitraum filtern (None = alles exportieren)
DATUM_VON   = None          # z.B. "2025-01-01"
DATUM_BIS   = None          # z.B. "2025-12-31"

# Ausgabedatei
AUSGABE_CSV = f"uptime_export_{date.today().strftime('%Y-%m-%d')}.csv"
# -------------------------------------------------------


def verbinden():
    return mysql.connector.connect(
        host=DB_HOST,
        port=DB_PORT,
        database=DB_NAME,
        user=DB_USER,
        password=DB_PASSWORD,
    )


def daten_abfragen(cursor):
    bedingungen = ["h.status = 1"]
    parameter = []

    if DATUM_VON:
        bedingungen.append("DATE(h.time) >= %s")
        parameter.append(DATUM_VON)
    if DATUM_BIS:
        bedingungen.append("DATE(h.time) <= %s")
        parameter.append(DATUM_BIS)

    where = " AND ".join(bedingungen)

    query = f"""
        SELECT
            m.name                          AS geraet,
            DATE(h.time)                    AS datum,
            MIN(h.time)                     AS erstes_online,
            MAX(h.time)                     AS letztes_online,
            COUNT(*)                        AS ping_anzahl,
            ROUND(COUNT(*) * 5 / 60.0, 1)  AS online_stunden
        FROM heartbeat h
        JOIN monitor m ON h.monitor_id = m.id
        WHERE {where}
        GROUP BY m.name, DATE(h.time)
        ORDER BY m.name, datum;
    """

    cursor.execute(query, parameter)
    return cursor.fetchall(), [d[0] for d in cursor.description]


def exportieren(zeilen, spalten):
    with open(AUSGABE_CSV, "w", newline="", encoding="utf-8") as f:
        writer = csv.writer(f, delimiter=";")
        writer.writerow(spalten)
        writer.writerows(zeilen)


def zusammenfassung(zeilen):
    geraete = set(z[0] for z in zeilen)
    tage    = set(z[1] for z in zeilen)
    print(f"  Geräte:        {len(geraete)}")
    print(f"  Tage im Export: {len(tage)}")
    print(f"  Datensätze:    {len(zeilen)}")

    if zeilen:
        print(f"\n  Beispiel (erste 5 Einträge):")
        print(f"  {'Gerät':<20} {'Datum':<12} {'Erstes Online':<22} {'Letztes Online':<22} {'Pings':<8} {'Stunden'}")
        print(f"  {'-'*95}")
        for z in zeilen[:5]:
            print(f"  {str(z[0]):<20} {str(z[1]):<12} {str(z[2]):<22} {str(z[3]):<22} {str(z[4]):<8} {z[5]}")


def main():
    print("Uptime Kuma Export\n")

    if DATUM_VON or DATUM_BIS:
        print(f"  Zeitraum: {DATUM_VON or 'Anfang'} bis {DATUM_BIS or 'heute'}")
    else:
        print("  Zeitraum: gesamter Verlauf")

    print(f"  Ausgabedatei: {AUSGABE_CSV}\n")

    print("Verbinde mit MariaDB ...")
    try:
        conn   = verbinden()
        cursor = conn.cursor()
        print("Verbindung erfolgreich.\n")
    except Exception as e:
        print(f"FEHLER bei der Verbindung: {e}")
        return

    print("Frage Daten ab ...")
    try:
        zeilen, spalten = daten_abfragen(cursor)
    except Exception as e:
        print(f"FEHLER bei der Abfrage: {e}")
        cursor.close()
        conn.close()
        return

    if not zeilen:
        print("Keine Daten gefunden. Sind schon Monitore aktiv und Daten gesammelt worden?")
        cursor.close()
        conn.close()
        return

    print(f"{len(zeilen)} Datensätze gefunden.\n")
    zusammenfassung(zeilen)

    print(f"\nSchreibe CSV ...")
    exportieren(zeilen, spalten)
    print(f"Fertig! Datei gespeichert: {AUSGABE_CSV}")

    cursor.close()
    conn.close()


if __name__ == "__main__":
    main()

Je nach Bedarf können auch noch die Zeiten angepasst werden, welche exportiert werden sollen:

# Nur einen bestimmten Zeitraum exportieren:
DATUM_VON   = "2026-01-01"
DATUM_BIS   = "2026-03-31"

# Oder alles:
DATUM_VON   = None
DATUM_BIS   = None

Danach liegt eine neue CSV-Datei unter /opt/uptime-kuma/