← Zurück zur Übersicht Wieviel RAM frisst dein Server wirklich? Baue dein eigenes Monitoring-Dashboard

Wieviel RAM frisst dein Server wirklich? Baue dein eigenes Monitoring-Dashboard

[WERBUNG: CONTENT OBEN]

Wieviel RAM frisst dein Server? Baue dein eigenes Monitoring-Dashboard

Du hast einen VPS, einen Homeserver oder einen Raspberry Pi – aber wie viel Arbeitsspeicher ist gerade frei? Wie hoch ist die CPU-Last? Klar, du könntest htop in der Konsole nutzen, aber wäre ein schickes Web-Dashboard nicht viel besser?

In diesem Tutorial bauen wir ein Echtzeit-Monitoring-Dashboard, das dir CPU, RAM und Disk-Auslastung live im Browser anzeigt – mit automatischen Updates via WebSockets.


🛠️ Projekt aufsetzen

mkdir my-server-monitor && cd my-server-monitor
npm init -y

Damit der Docker-Container später weiß, wie er die App starten soll (und welche Pakete benötigt werden), legen wir die package.json im Projektordner an:

my-server-monitor/package.json:

{
  "name": "my-server-monitor",
  "version": "1.0.0",
  "scripts": { "start": "node server.js" },
  "dependencies": {
    "express": "^4.18.2",
    "socket.io": "^4.7.2",
    "os-utils": "^0.0.14"
  }
}

Was macht os-utils? Es ist eine winzige Library, die den Zugriff auf Systemdaten (CPU, RAM) vereinfacht, ohne dass wir /proc/meminfo selbst parsen müssen.


1. Der Server: Systemdaten sammeln & senden

my-server-monitor/server.js:

const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const os = require('os');
const osUtils = require('os-utils');
const path = require('path');

const app = express();
const server = http.createServer(app);
const io = new Server(server);

app.use(express.static(
    path.join(__dirname, 'public')
));

// Systemdaten sammeln
function getSystemData() {
    const totalMem = os.totalmem();
    const freeMem = os.freemem();
    const usedMem = totalMem - freeMem;

    return {
        hostname: os.hostname(),
        platform: os.platform(),
        uptime: os.uptime(),
        memory: {
            total: totalMem,
            used: usedMem,
            free: freeMem,
            percent: Math.round(
                (usedMem / totalMem) * 100
            )
        },
        cpus: os.cpus().length
    };
}

io.on('connection', (socket) => {
    console.log('Dashboard verbunden');

    // Sofort Daten senden
    const send = () => {
        osUtils.cpuUsage((cpuPercent) => {
            const data = getSystemData();
            data.cpu = Math.round(cpuPercent * 100);
            socket.emit('stats', data);
        });
    };

    send();
    const interval = setInterval(send, 2000);

    socket.on('disconnect', () => {
        clearInterval(interval);
    });
});

const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
    console.log(
        `Monitor läuft auf http://localhost:${PORT}`
    );
});

2. Das Dashboard-Frontend

my-server-monitor/public/index.html:

<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <title>Server Monitor</title>
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        body {
            font-family: 'Courier New', monospace;
            background: #0a0e17;
            color: #c8d6e5;
            min-height: 100vh;
            display: flex;
            justify-content: center;
            padding: 2rem 1rem;
        }
        #dashboard {
            width: 100%;
            max-width: 600px;
        }
        h1 {
            text-align: center;
            color: #10b981;
            margin-bottom: 0.5rem;
        }
        .subtitle {
            text-align: center;
            color: #576574;
            font-size: 0.8rem;
            margin-bottom: 2rem;
        }
        .card {
            background: #141a2a;
            border: 1px solid #1e293b;
            border-radius: 10px;
            padding: 1.25rem;
            margin-bottom: 1rem;
        }
        .card-title {
            font-size: 0.8rem;
            color: #576574;
            margin-bottom: 0.75rem;
            text-transform: uppercase;
            letter-spacing: 1px;
        }
        .metric {
            font-size: 2rem;
            font-weight: bold;
        }
        .cpu { color: #38bdf8; }
        .ram { color: #f59e0b; }
        .uptime-val { color: #10b981; }
        .bar-bg {
            width: 100%;
            height: 12px;
            background: #1e293b;
            border-radius: 6px;
            margin-top: 0.75rem;
            overflow: hidden;
        }
        .bar-fill {
            height: 100%;
            border-radius: 6px;
            transition: width 0.5s ease;
        }
        .bar-fill.cpu-bar { background: #38bdf8; }
        .bar-fill.ram-bar { background: #f59e0b; }
        .info-row {
            display: flex;
            justify-content: space-between;
            font-size: 0.85rem;
            color: #576574;
            margin-top: 0.5rem;
        }
        .grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 1rem;
        }
        .status-dot {
            display: inline-block;
            width: 8px;
            height: 8px;
            background: #10b981;
            border-radius: 50%;
            margin-right: 6px;
            animation: pulse 2s infinite;
        }
        @keyframes pulse {
            0%, 100% { opacity: 1; }
            50% { opacity: 0.3; }
        }
    </style>
</head>
<body>
    <div id="dashboard">
        <h1>📡 Server Monitor</h1>
        <p class="subtitle">
            <span class="status-dot"></span>
            Live-Daten alle 2 Sekunden
        </p>

        <div class="card">
            <div class="card-title">CPU Auslastung</div>
            <div class="metric cpu" id="cpu">0%</div>
            <div class="bar-bg">
                <div class="bar-fill cpu-bar"
                     id="cpuBar"
                     style="width: 0%"></div>
            </div>
            <div class="info-row">
                <span id="cpuCores">– Kerne</span>
                <span id="platform">–</span>
            </div>
        </div>

        <div class="card">
            <div class="card-title">
                Arbeitsspeicher (RAM)
            </div>
            <div class="metric ram" id="ram">0%</div>
            <div class="bar-bg">
                <div class="bar-fill ram-bar"
                     id="ramBar"
                     style="width: 0%"></div>
            </div>
            <div class="info-row">
                <span id="ramUsed">– / – GB</span>
                <span id="ramFree">– GB frei</span>
            </div>
        </div>

        <div class="grid">
            <div class="card">
                <div class="card-title">Uptime</div>
                <div class="metric uptime-val"
                     id="uptime">–</div>
            </div>
            <div class="card">
                <div class="card-title">Hostname</div>
                <div class="metric"
                     style="font-size:1rem;color:#e2e8f0"
                     id="hostname">–</div>
            </div>
        </div>
    </div>

    <script src="/socket.io/socket.io.js"></script>
    <script>
    const socket = io();

    function formatBytes(bytes) {
        return (bytes / 1073741824).toFixed(1);
    }

    function formatUptime(seconds) {
        const d = Math.floor(seconds / 86400);
        const h = Math.floor((seconds % 86400) / 3600);
        const m = Math.floor((seconds % 3600) / 60);
        if (d > 0) return d + 'd ' + h + 'h';
        if (h > 0) return h + 'h ' + m + 'm';
        return m + 'm';
    }

    socket.on('stats', (data) => {
        // CPU
        document.getElementById('cpu')
            .textContent = data.cpu + '%';
        document.getElementById('cpuBar')
            .style.width = data.cpu + '%';
        document.getElementById('cpuCores')
            .textContent = data.cpus + ' Kerne';
        document.getElementById('platform')
            .textContent = data.platform;

        // RAM
        document.getElementById('ram')
            .textContent = data.memory.percent + '%';
        document.getElementById('ramBar')
            .style.width = data.memory.percent + '%';
        document.getElementById('ramUsed')
            .textContent =
                formatBytes(data.memory.used) + ' / ' +
                formatBytes(data.memory.total) + ' GB';
        document.getElementById('ramFree')
            .textContent =
                formatBytes(data.memory.free) + ' GB frei';

        // Info
        document.getElementById('uptime')
            .textContent = formatUptime(data.uptime);
        document.getElementById('hostname')
            .textContent = data.hostname;
    });
    </script>
</body>
</html>

3. Docker Deployment

my-server-monitor/docker-compose.yml:

version: '3.8'
services:
  app:
    image: node:18-alpine
    working_dir: /app
    volumes:
      - .:/app
    ports:
      - "3000:3000"
    command: sh -c "npm install && npm start"
docker compose up -d

Öffne http://localhost:3000 – dein Dashboard ist live!

⚠️ 📸 SCREENSHOT ANFRAGE: Hier einen Screenshot vom Dashboard mit aktiven CPU- und RAM-Balken einfügen.


🧠 Wie funktioniert es?

Schritt Was passiert
1. Verbindung Browser öffnet WebSocket via Socket.io
2. Intervall Server sammelt alle 2 Sekunden Systemdaten
3. Push Daten werden sofort an den Client gesendet
4. Rendering Frontend aktualisiert Balken und Zahlen

Der Clou: Kein Polling! Der Server pusht die Daten aktiv zum Client. Das ist effizienter und fühlt sich deutlich flüssiger an als ein setInterval mit fetch.


📈 Erweiterungs-Ideen

Feature Schwierigkeit Beschreibung
Disk-Auslastung ⭐⭐ df-Befehl auslesen und anzeigen
Netzwerk-Traffic ⭐⭐⭐ Eingehende/ausgehende Bytes tracken
Historische Daten ⭐⭐⭐ Messwerte in SQLite speichern und Graphen zeigen
Multi-Server ⭐⭐⭐⭐ Mehrere Server auf einem Dashboard
Alerts ⭐⭐ E-Mail-Warnung bei CPU > 90%

Fazit

In wenigen Minuten hast du ein eigenes Server-Monitoring-Dashboard gebaut, das dir in Echtzeit zeigt, was auf deiner Maschine passiert. Kein Grafana-Setup, kein Prometheus – nur Node.js und ein Browser.

Perfekt für Homeserver, Raspberry Pis oder als Basis für ein größeres Monitoring-System. Happy Monitoring! 📡

[WERBUNG: CONTENT UNTEN]