Build a Real-Time Server Dashboard with Python & WebSockets
DEV Community

Build a Real-Time Server Dashboard with Python & WebSockets

What We're Building

A dark-themed dashboard that shows:

  • CPU usage with real-time sparkline charts
  • RAM consumption with percentage and absolute values
  • Network throughput (upload/download in KB/s)
  • Disk usage across all mounted partitions
  • Top processes by CPU usage
  • System info (OS, hostname, uptime, cores)

All data is pushed via WebSocket - so the browser updates automatically, no polling needed.

The Architecture

[psutil] β†’ [Python aiohttp server] ←WebSocketβ†’ [Browser Dashboard]
                                              ↕
                                    [Static HTML/CSS/JS]

The Python backend:

  • Collects system metrics using psutil
  • Serves the static dashboard files
  • Pushes metric snapshots to all connected browsers via WebSocket every 2 seconds

Step 1: The Backend

First, install the dependencies:

pip install psutil aiohttp

Here's the core metric collection function:

import psutil
import time

_prev_net = psutil.net_io_counters()
_prev_time = time.monotonic()

def collect_metrics():
    global _prev_net, _prev_time

    now = time.monotonic()
    dt = now - _prev_time
    _prev_time = now

    # CPU
    cpu_percent = psutil.cpu_percent(interval=None)

    # Memory
    mem = psutil.virtual_memory()

    # Network (calculate rate)
    net = psutil.net_io_counters()
    sent_rate = (net.bytes_sent - _prev_net.bytes_sent) / dt
    recv_rate = (net.bytes_recv - _prev_net.bytes_recv) / dt
    _prev_net = net

    # Disk
    disks = []
    for part in psutil.disk_partitions(all=False):
        try:
            usage = psutil.disk_usage(part.mountpoint)
            disks.append({
                "mountpoint": part.mountpoint,
                "percent": usage.percent,
                "total": usage.total,
                "used": usage.used,
            })
        except PermissionError:
            continue

    return {
        "cpu": {"percent": cpu_percent},
        "memory": {"percent": mem.percent, "total": mem.total, "used": mem.used},
        "network": {"sent_rate_kbs": sent_rate / 1024, "recv_rate_kbs": recv_rate / 1024},
        "disks": disks,
    }

The key insight: we track the previous network counter and timestamp to calculate the transfer rate in KB/s.

Step 2: WebSocket Server

Using aiohttp, we serve both the static files and the WebSocket endpoint:

import asyncio
import json
from aiohttp import web

clients = set()

async def ws_handler(request):
    ws = web.WebSocketResponse()
    await ws.prepare(request)
    clients.add(ws)
    try:
        data = collect_metrics()
        await ws.send_json(data)
        async for msg in ws:
            pass  # We only push, never receive
    finally:
        clients.discard(ws)
    return ws

async def broadcast(app):
    while True:
        await asyncio.sleep(2)
        if not clients:
            continue
        data = collect_metrics()
        payload = json.dumps(data)
        for ws in set(clients):
            try:
                await ws.send_str(payload)
            except:
                clients.discard(ws)

Step 3: The Dashboard UI

For the frontend, I used a single HTML file with inline CSS and JavaScript. The dark theme uses carefully chosen colors:

:root {
    --bg-primary: #0a0e17;
    --bg-card: #111827;
    --accent-blue: #3b82f6;
    --accent-cyan: #06b6d4;
    --accent-green: #10b981;
}

Each metric gets its own card with an animated progress bar and a dedicated color scheme. Chart.js handles the sparkline charts with smooth BΓ©zier interpolation.

The WebSocket client auto-reconnects if the server goes down:

function connect() {
    const ws = new WebSocket(`ws://${location.host}/ws`);
    ws.onmessage = (event) => {
        const data = JSON.parse(event.data);
        updateDashboard(data);
    };
    ws.onclose = () => {
        setTimeout(connect, 3000); // Auto-reconnect
    };
}

Step 4: Run It

python server.py

Open http://localhost:8765 and watch your server metrics update in real-time!

Going Further

Some ideas to extend this:

  • Add alerts: Email or Discord webhook when CPU > 90%
  • Authentication: Add basic auth or API key for public-facing deployments
  • History storage: Log metrics to SQLite for historical analysis
  • Docker: Add a Dockerfile for one-command deployment

Grab the Full Source

If you want the complete, production-ready source code with the full premium dashboard UI, Docker support, and all features - you can grab it on my Gumroad. I'm a 16-year-old developer from Lithuania building tools for sysadmins and server owners. Follow me for more tutorials on Linux, Docker, and Python!

Tags: python #webdev #tutorial #monitoring #devops #websocket #dashboard

Comments

No comments yet. Start the discussion.