DEV Community

Arnav Bansal
Arnav Bansal

Posted on

How I Built a Live Server Monitoring Dashboard From Scratch in One Night

It was 9 PM. The competition had just gone live.

The challenge: "Prometheus + Grafana + alerts. Make the server visible. Discord/Telegram bot bonus points."

I had a container on a 125GB RAM, 24-core, 7.5TB beast of a server. No Docker. Node v12. One port exposed.

This is the story of how I built CRISPR Monitor — a full live infrastructure dashboard — in one night, entirely from scratch.


The Problem

The organizers gave every team an isolated Ubuntu container on their server. The task was simple in theory: make the server visible. Show what's happening under the hood. Alert when things go wrong.

The classic answer? Prometheus + Grafana + Alertmanager. Spin it up with docker-compose, done.

Except.

There was no Docker. And Grafana runs on port 3000. Prometheus on port 9090. We only had one port exposed — port 8000.

So docker-compose was dead on arrival. Running Grafana natively on a minimized Ubuntu without apt access? That's an hour of dependency hell with no guarantee it works.

I had a choice: spend 2 hours fighting Grafana, or build something better.

I built something better.


The Stack

The entire thing runs as a single Node.js process on port 8000:

systeminformation
      ↓
  Node.js (Express + WebSocket)
      ↓
  ┌───────────────────────────┐
  │  Live Dashboard (Chart.js) │
  │  /metrics (Prometheus fmt) │
  │  Discord + Telegram alerts │
  └───────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

No external dependencies beyond npm packages. No Docker. No reverse proxy. Just one file.


What It Does

Live WebSocket Metrics

Every 3 seconds, the server pushes fresh data to every connected browser via WebSocket. No polling. No page refresh. The dashboard updates in real time — CPU, Memory, Disk, Network, CPU Temperature, Uptime.

Chart.js History Graphs

CPU and Memory history plots show the last 20 data points. You can watch the server breathe.

Top 5 Processes by CPU

Using systeminformation, the dashboard shows which processes are eating the most CPU right now — name, CPU%, memory%, and PID.

Prometheus-Compatible /metrics Endpoint

# HELP cpu_usage_percent Current CPU usage
# TYPE cpu_usage_percent gauge
cpu_usage_percent 15.66
# HELP memory_usage_percent Current memory usage
# TYPE memory_usage_percent gauge
memory_usage_percent 98.0
Enter fullscreen mode Exit fullscreen mode

Any real Prometheus instance could scrape this endpoint directly. The judges loved this detail.

Spike Detection Alerts

This is the part I'm most proud of. Instead of alerting every time a value is above a threshold (which causes spam when memory is sitting at 98%), the system only fires when a value jumps by 10% or more suddenly.

function checkSpike(key, current) {
  const prev = prevValues[key];
  prevValues[key] = current;
  if (prev === null) return false;
  return (current - prev) >= 10;
}
Enter fullscreen mode Exit fullscreen mode

One spike = one alert. Clean. No spam.

Discord + Telegram Alerts

When a spike is detected, a formatted alert fires to both Discord (as a rich embed) and Telegram (as a Markdown message). Both bots, simultaneously, in under a second.


What Broke First

1. Optional Chaining on Node v12

The server was running Node v12.22.9. My development machine had Node v18. I used ?. (optional chaining) everywhere:

const diskPct = parseFloat((disk[0]?.use || 0).toFixed(2));
Enter fullscreen mode Exit fullscreen mode

Node v12 doesn't support optional chaining. The server threw a SyntaxError immediately on startup.

Fix — replace every ?. with old-school AND checks:

const diskPct = parseFloat(((disk[0] && disk[0].use) || 0).toFixed(2));
Enter fullscreen mode Exit fullscreen mode

2. Express Version Too New

I had installed the latest Express on my PC. It uses node:events — a Node 14+ feature. Node v12 crashed with:

Error: Cannot find module 'node:events'
Enter fullscreen mode Exit fullscreen mode

Fix — install older compatible versions:

npm install express@4.18.2 systeminformation@5.18.0 ws@7.5.9 axios@0.27.2
Enter fullscreen mode Exit fullscreen mode

3. cpuLoad.currentLoad Undefined

On the server, si.currentLoad() occasionally returned an object where currentLoad was undefined. Adding a fallback fixed it:

const cpu = parseFloat((cpuLoad.currentLoad || 0).toFixed(2));
Enter fullscreen mode Exit fullscreen mode

The Result

A fully live dashboard running on the competition server, accessible at the judge's URL, showing real metrics from a real 24-core machine with 125GB of RAM.

Memory was sitting at 98% the whole competition — the bar glowed red, which honestly looked incredible on the demo.

The Prometheus /metrics endpoint was the detail that got the most reaction from judges. It showed we understood the ecosystem, not just the UI.


What I Would Add Next

  • Ping/uptime checker — monitor URLs and alert when they go down
  • Log viewer — tail /var/log/syslog live in the browser
  • Auto-restart — detect dead processes and restart them
  • Multi-server support — one dashboard for multiple containers

Key Takeaway

The best solution isn't always the most popular tool. Sometimes the constraint is the challenge. When Docker wasn't available and only one port was exposed, building from scratch wasn't a workaround — it was the answer.

And it was more impressive for it.


Built at CRISPR Hackathon, IIIT Nagpur. Stack: Node.js, Express, WebSocket, Chart.js, systeminformation, axios. Alerts via Discord + Telegram.

Top comments (0)