A full-stack observability dashboard for exploring Amazon EC2 metrics from
CloudWatch — CPU, network, disk I/O, CPU credits and status checks. Enter an
instance's private IP, pick a time window, and the app resolves the EC2
InstanceId and charts its metrics over time.
Live demo: https://aws-cpu-utilization-metrics-six.vercel.app
API: https://aws-cpu-utilization-metrics.onrender.com
The public demo runs in demo mode — it serves realistic synthetic data so the app works for everyone without exposing AWS credentials. Run it locally with real AWS keys to query live CloudWatch metrics.
The API is on Render's free tier and sleeps after inactivity, so the first query may take ~50s to wake it; subsequent queries are fast.
- Resolve an EC2 instance by its private IP (EC2
DescribeInstances) - Multi-metric dashboard from CloudWatch (
GetMetricStatistics): CPU, Network In/Out, Disk I/O, and CPU credit balance — plus instance/system status checks - Sparkline row to switch the main chart between metrics; average / peak / minimum / sample-count stats per metric
- Interactive 3D exploded-view hero, light & dark theme, fully responsive
- Demo mode for zero-credential public deployment
| Layer | Tech |
|---|---|
| Backend | Node.js, Express, AWS SDK v3 (EC2 + CloudWatch) |
| Frontend | React, Vite, Chart.js (react-chartjs-2) |
| Deploy | Backend → Render · Frontend → Vercel |
Browser (React · three.js · Chart.js)
│ POST /api/metrics { ip, periodMinutes, intervalSeconds }
▼
Express API
├─ EC2 DescribeInstances → resolve InstanceId by private IP
└─ CloudWatch GetMetricStatistics (in parallel) →
│ CPU · NetworkIn/Out · DiskRead/WriteOps · CPUCreditBalance
│ + StatusCheckFailed (instance / system)
│ (demo mode → synthetic series, no AWS calls)
▼
JSON { instanceId, series {…}, status {…}, demo }
POST /api/cpu remains as a CPU-only convenience endpoint (see API).
cd backend
cp .env.example .env # demo mode is on by default
npm install
npm start # http://localhost:4000To query real AWS metrics, set DEMO_MODE=false in .env and fill in
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_REGION. The credentials
need ec2:DescribeInstances and cloudwatch:GetMetricStatistics permissions.
cd frontend
cp .env.example .env # VITE_API_URL=http://localhost:4000
npm install
npm run dev # http://localhost:5173POST /api/metrics — the primary endpoint; returns every metric at once.
{ "ip": "172.31.88.161", "periodMinutes": 60, "intervalSeconds": 300 }Response:
{
"instanceId": "i-0abc123",
"series": {
"cpu": [{ "time": "...", "value": 25.4 }],
"netIn": [], "netOut": [], "diskRead": [], "diskWrite": [], "credits": []
},
"status": { "instance": "ok", "system": "ok" },
"demo": true
}intervalSeconds must be one of 60, 300, 600; periodMinutes is 1–1440.
POST /api/cpu — CPU-only convenience endpoint (same body):
{
"instanceId": "i-0abc123",
"points": [{ "time": "2026-08-06T09:10:00Z", "cpu": 25.47 }],
"demo": true
}Also: GET /health → { "status": "ok", "demo": true }.
The hero renders an interactive 3D CPU chip with three.js — click to explode
the chip into its layers (core, top plate, base, and four pin rails) and click
again to reassemble; drag to orbit. It respects prefers-reduced-motion.
The model (frontend/public/models/cpu-chip.glb) was generated with
Meshy and processed for the web with gltf-transform:
the source was a single 58 MB merged mesh, so it was simplified, split by
geometry into named layers (each carrying an explode offset vector in glTF
extras), texture-downscaled, and meshopt-compressed down to ~6 MB.
three.js and the loaders are lazy-loaded as a separate chunk. Fallbacks degrade
gracefully: if WebGL or the model is unavailable, the hero shows an animated
raster render, then a built-in SVG chip. Set VITE_HERO_MODEL=off to disable 3D.
- Backend (Render): the repo includes
render.yaml. Create a Blueprint from the repo, or a Web Service with root dirbackend, buildnpm install, startnpm start, and envDEMO_MODE=true. - Frontend (Vercel): import the repo, set root directory to
frontend, and add envVITE_API_URLpointing at the deployed backend URL.