Skip to content
All projects
Open source Python Flask Three.js WebGL Proxmox Zabbix

Homelab Galaxy Dashboard

The whole estate as a star system, on a wall display.

A 3D monitoring console for Proxmox estates. Each node renders as a spiral galaxy and each guest as a planet, coloured by role and sized by memory, flaring when Zabbix raises a problem against it. Built for a wall display read from across a room.

9

data sources

1

screen, not five tabs

0

runtime CDN dependencies

Why not just use Grafana

Grafana is excellent at here is a time series. It is much weaker at the question a homelab operator actually asks first: what is my estate, and what in it is unhappy right now?

Answering that normally means five tabs — Proxmox for guests, Zabbix for problems, UniFi for clients, the NVR for cameras, nvidia-smi for the GPUs. This puts all of it into one spatial view legible from across a room.

Nothing in the scene is decorative. Planet colour is the guest's role, size is its RAM allocation, dimming means stopped, and a red flare means Zabbix has an active problem against that specific guest. If something looks wrong, something is wrong.

Architecture

Backends are polled by background threads into a single in-memory cache; the HTTP layer only ever reads that cache. Three properties fall out of that shape, and all three matter more than they sound.

  • Requests never block on a backend. A Zabbix server that has gone away makes its poller log and retry. It does not make the dashboard slow.
  • Failures are isolated. Each poller writes only its own key of the cache, wrapped end to end in try/except. One dead backend removes one layer from the scene rather than the scene.
  • Last-good data survives. Pollers overwrite their key only on success, so a transient failure leaves the previous reading on screen instead of blanking the panel.

The UniFi session that lies

A UDM returns an empty client list rather than an error when its session expires. Handled naively, the client count silently drops to zero and every graph shows a cliff that never happened.

The poller treats an empty list as session expiry: keep the last-good reading, re-authenticate on the next cycle. It is two lines of code and the difference between a dashboard you trust and one you learn to second-guess.

Degrading gracefully

A wall display that shows an error page is worse than no wall display, because nobody notices it has stopped being true.

Three render paths exist. The full WebGL scene when the browser supports it; a plain HUD rendering the same data as panels when a script fails or the scene has not reported ready within 4.5 seconds; and optionally a server-side offscreen render on the host GPU via EGL, for clients that cannot run WebGL at all.

The same principle governs configuration. Every backend except Proxmox is optional — leave its URL unset and that layer is simply absent. You can run the whole thing against nothing but Proxmox and still get a galaxy.

Preparing it for release

The internal version had grown the way internal tools do: addresses and credentials inline, panels wired to services only this lab has, a utility carrying a live API token.

Opening it meant moving every setting into an environment-driven config module, replacing site-specific panels with generic equivalents, making NVML and the GPU renderer optional imports so it runs on hosts without an NVIDIA card, and adding a startup preflight that reports exactly what configuration is missing instead of failing deep inside a poller.

There are now no credentials and no private addresses anywhere in the application code.