Skip to content

brainchillz/virtualization-dashboard

Repository files navigation

VM Dashboard

A web-based infrastructure monitoring dashboard for VMware vCenter, standalone ESXi hosts, and Proxmox VE clusters. Displays VM count, CPU, memory, and storage utilization across all your hypervisors in one place.

Features

  • Multi-platform — monitors VMware vCenter, standalone ESXi, and Proxmox VE (including LXC containers)
  • Live overview — single dashboard with gauge charts for CPU, memory, and storage per device, plus a last-hour CPU sparkline on each card
  • Drill-down detail — per-device page with utilization history charts and a VM/container list with text search, power-state filter, and sortable columns
  • Configurable polling — per-device poll interval (default 5 minutes); first poll runs immediately on device add or edit
  • Per-device thresholds — set CPU/memory/storage alert percentages that drive the gauge colour bands
  • Users & roles — multiple accounts with admin (full control) or viewer (read-only) roles, managed from a Users page
  • Data export — download a device's metric history as CSV, or scrape latest metrics from a Prometheus-format endpoint
  • Automatic retention — a daily job prunes metric history older than a configurable window (default 90 days)
  • Security hardening — credentials encrypted at rest (Fernet); JWT signing key auto-generated and stored, not hardcoded; bcrypt password hashing; login rate limiting
  • System service — runs as a hardened systemd service, starts automatically on boot; schema upgrades apply automatically

Requirements

Component Version
Ubuntu 24.04 LTS or 26.04 LTS
Python 3.12 (installed automatically)
Node.js 18+ (installed automatically)
Disk space ~300 MB (app + venv + node_modules)

The installer handles all dependencies. No manual setup is needed before running it.


Quick Install

git clone https://github.com/your-org/vmdashboard.git
cd vmdashboard
sudo ./install.sh

This installs to /opt/vmdashboard, creates a vmdashboard system user, builds the frontend, and starts the service on port 8080.

To use a different port:

sudo ./install.sh --port 9090

Docker Deployment

The repository ships with a multi-stage Dockerfile and a docker-compose.yml. The image builds the frontend, installs the backend, and serves both from a single container on port 8080. The SQLite database and encryption keys live on a named volume (/data inside the container) so they survive restarts and image rebuilds.

With Docker Compose (recommended)

docker compose up -d --build

Then open http://<host>:8080 and complete first-time setup.

docker compose logs -f          # follow logs
docker compose down             # stop (data volume is kept)
docker compose up -d --build    # upgrade to new code (migrations run on startup)

Configuration is via environment variables (set them inline or in a .env file next to the compose file):

Variable Default Purpose
PORT 8080 Host port to publish
DASHBOARD_RETENTION_DAYS 90 Days of metric history to keep (0 = forever)
DASHBOARD_SECRET_KEY auto-generated Pin the JWT signing key (otherwise generated into the volume on first run)
PORT=9090 DASHBOARD_RETENTION_DAYS=30 docker compose up -d --build

With plain Docker

docker build -t virtualization-dashboard:latest .
docker volume create dashboard-data
docker run -d --name virtualization-dashboard \
  -p 8080:8080 \
  -v dashboard-data:/data \
  --restart unless-stopped \
  virtualization-dashboard:latest

Backing up a Docker install

All state is in the dashboard-data volume. Back it up with:

docker run --rm -v dashboard-data:/data -v "$PWD":/backup alpine \
  tar czf /backup/vmdashboard-backup.tar.gz -C /data .

The container runs as an unprivileged user and includes a /api/health healthcheck. The image does not bundle any database or keys — they are created in the volume on first run.


Manual / Step-by-Step Install

If you prefer to understand each step, here is what the installer does:

1. Install system packages

sudo apt-get update
sudo apt-get install -y curl software-properties-common rsync

# Python 3.12
sudo add-apt-repository -y ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get install -y python3.12 python3.12-venv python3.12-dev

# Node.js 20.x
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -
sudo apt-get install -y nodejs

2. Create system user

sudo useradd --system --no-create-home --shell /bin/false vmdashboard

3. Copy files

sudo mkdir -p /opt/vmdashboard
sudo rsync -a --exclude='backend/venv' --exclude='frontend/node_modules' \
    ./ /opt/vmdashboard/

4. Set up Python virtual environment

cd /opt/vmdashboard/backend
sudo python3.12 -m venv venv
sudo venv/bin/pip install -r requirements.txt

5. Build frontend

cd /opt/vmdashboard/frontend
sudo npm install
sudo npm run build
sudo cp -r dist /opt/vmdashboard/backend/dist

6. Set permissions

sudo chown -R vmdashboard:vmdashboard /opt/vmdashboard
sudo chmod 750 /opt/vmdashboard/backend

7. Create systemd service

Create /etc/systemd/system/vmdashboard.service:

[Unit]
Description=VM Dashboard
After=network.target

[Service]
Type=simple
User=vmdashboard
Group=vmdashboard
WorkingDirectory=/opt/vmdashboard/backend
ExecStart=/opt/vmdashboard/backend/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8080
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=vmdashboard
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/opt/vmdashboard/backend
ProtectHome=true

[Install]
WantedBy=multi-user.target

8. Enable and start

sudo systemctl daemon-reload
sudo systemctl enable vmdashboard
sudo systemctl start vmdashboard

First-Time Setup

  1. Open your browser and navigate to http://<server-ip>:8080
  2. You will be redirected to the login page
  3. Click the First Time Setup tab
  4. Enter a username and password for the first admin account and click Create Account & Sign In
  5. Public registration is permanently closed once the first account is created

Note: The first account is always an admin. Additional accounts (admin or read-only viewer) are created afterwards from the Users page in the sidebar — see Users & Roles below. If you ever lose all admin access, stop the service, delete /opt/vmdashboard/backend/dashboard.db, restart, and go through first-time setup again (this also erases devices and history).


Users & Roles

Once logged in as an admin, open the Users page from the sidebar to manage accounts:

Role Can do
admin Everything — add/edit/remove devices, manage users, change settings
viewer Read-only — view the dashboard, device details, and export data, but cannot modify devices or users
  • The first account created during first-time setup is always an admin.
  • Admins can add users, reset any user's password, and delete users.
  • You cannot delete your own account or remove the last remaining admin (this prevents lock-out).
  • Viewers see the dashboard and device pages but the add/edit/delete controls are hidden, and the API rejects write attempts with 403.

Adding Devices

Navigate to the Devices page using the sidebar and click Add Device.

VMware vCenter

Field Example
Device Type vCenter
Display Name Production vCenter
Hostname / IP vcenter.example.com
Port 443
Username administrator@vsphere.local
Password your-password
Verify SSL unchecked for self-signed certs

vCenter discovery pulls metrics from all ESXi hosts and VMs managed by that vCenter.

Standalone ESXi

Field Example
Device Type ESXi
Display Name ESXi-01
Hostname / IP 192.168.1.10
Port 443
Username root
Password your-password
Verify SSL unchecked for self-signed certs

Proxmox VE

Field Example
Device Type Proxmox
Display Name Home Lab Proxmox
Hostname / IP 192.168.1.20
Port 8006
Username root@pam
Password your-password
Verify SSL unchecked for self-signed certs

Proxmox discovery pulls metrics from all nodes in the cluster, including both QEMU VMs and LXC containers.

Monitoring options (per device)

The Add/Edit Device dialog has a Monitoring section:

Field Meaning
Poll interval (min) How often this device is polled (default 5). Lower it for near-real-time data, raise it for large/slow environments.
CPU / Memory / Storage alert % Optional critical thresholds. When set, the gauge for that metric turns red at/above the value and shades through orange/yellow below it. Leave blank to use the default colour scale.

After adding a device, the first poll runs immediately. Dashboard cards show No data yet for a few seconds until the first collection completes.


Exporting Data

CSV

On any device detail page, click Export CSV to download that device's metric history (timestamp, CPU/memory/storage %, capacity figures, VM counts) as a CSV file for reporting or analysis.

Prometheus

The endpoint GET /api/metrics/prometheus returns the latest metric for every device in Prometheus text-exposition format (gauges for CPU/memory/storage %, VM counts, and a vmdashboard_device_up series). It requires authentication, so configure a bearer token in your scrape job:

scrape_configs:
  - job_name: vmdashboard
    metrics_path: /api/metrics/prometheus
    bearer_token: "<a-jwt-from-the-app>"
    static_configs:
      - targets: ["dashboard-host:8080"]

Service Management

Task Command
Check status sudo systemctl status vmdashboard
Start sudo systemctl start vmdashboard
Stop sudo systemctl stop vmdashboard
Restart sudo systemctl restart vmdashboard
View logs (live) sudo journalctl -u vmdashboard -f
View last 100 lines sudo journalctl -u vmdashboard -n 100
Disable autostart sudo systemctl disable vmdashboard

Updating

Pull the latest code and re-run the installer. The installer preserves your runtime state — the database (dashboard.db), the Fernet encryption key (secret.key), the JWT signing key (jwt_secret.key), any vmdashboard.env overrides, and the backups/ directory are never overwritten.

cd /path/to/vmdashboard
git pull
sudo ./install.sh --port 8080

Database schema upgrades are automatic. On startup the app runs backend/migrate.py, which additively adds any new columns to the existing SQLite database (it never drops data) and backfills sensible defaults. The frontend is rebuilt and the service is restarted at the end.

Backing up before a major upgrade is still wise: copy backend/dashboard.db, backend/secret.key, and backend/jwt_secret.key somewhere safe first.


Changing the Port

Re-run the installer with the new port — it rewrites the service file and restarts:

sudo ./install.sh --port 9090

Uninstalling

Run the included uninstall script:

sudo ./uninstall.sh

It will ask you to confirm before removing anything, then stops and disables the service, removes the unit file, deletes /opt/vmdashboard (including the database and encryption key), and removes the vmdashboard system user.

System packages installed as dependencies (Python 3.12, Node.js) are intentionally left in place since they may be used by other software. To remove them manually:

sudo apt-get remove --purge python3.12 python3.12-venv python3.12-dev nodejs
sudo add-apt-repository --remove ppa:deadsnakes/ppa

Putting It Behind a Reverse Proxy (Optional)

If you want to serve the dashboard on port 80/443 using nginx:

sudo apt-get install -y nginx

Create /etc/nginx/sites-available/vmdashboard:

server {
    listen 80;
    server_name dashboard.example.com;

    location / {
        proxy_pass         http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection "upgrade";
        proxy_read_timeout 300s;
    }
}
sudo ln -s /etc/nginx/sites-available/vmdashboard /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

For HTTPS, use Certbot with the nginx plugin.


File Locations

Path Purpose
/opt/vmdashboard/ Application root
/opt/vmdashboard/backend/dashboard.db SQLite database (devices, metrics, VMs, users)
/opt/vmdashboard/backend/dashboard.db-wal, …-shm SQLite WAL sidecar files (leave in place)
/opt/vmdashboard/backend/secret.key Fernet encryption key for stored passwords
/opt/vmdashboard/backend/jwt_secret.key Auto-generated key used to sign JWT login tokens
/opt/vmdashboard/backend/vmdashboard.env Optional env-var overrides (not created by default)
/opt/vmdashboard/backend/dist/ Built frontend static files
/etc/systemd/system/vmdashboard.service Systemd service unit

Back up dashboard.db, secret.key, and jwt_secret.key together. secret.key is required to decrypt stored device credentials; jwt_secret.key keeps existing login sessions valid across a restore (losing it just forces everyone to log in again).


Configuration (environment variables)

The app reads a few optional environment variables. To set them, create /opt/vmdashboard/backend/vmdashboard.env (the systemd unit loads it automatically) and restart the service:

# /opt/vmdashboard/backend/vmdashboard.env
DASHBOARD_SECRET_KEY=<64-hex-char string>   # pin the JWT signing key explicitly
DASHBOARD_RETENTION_DAYS=90                  # delete metric rows older than this (0 = keep forever)
Variable Default Purpose
DASHBOARD_SECRET_KEY auto-generated jwt_secret.key Overrides the JWT signing key. Useful to share one key across multiple instances. Generate with python3 -c "import secrets; print(secrets.token_hex(32))".
DASHBOARD_RETENTION_DAYS 90 How long metric history is kept. The daily prune job deletes older rows. Set 0 to disable pruning.
sudo systemctl restart vmdashboard

Troubleshooting

Dashboard shows "No data yet" and never updates

Check the device's last error on the Devices page. Common causes:

  • Wrong credentials — re-add the device with corrected username/password
  • SSL error — uncheck "Verify SSL certificate" for self-signed certs
  • Network unreachable — ensure the server running the dashboard can reach the hypervisor on the configured port
  • vCenter permission denied — the account needs at least read-only access to the vSphere tree

Service fails to start

sudo journalctl -u vmdashboard -n 50 --no-pager

Common causes:

  • Port already in use — change the port with sudo ./install.sh --port <other>
  • Permissions error — sudo chown -R vmdashboard:vmdashboard /opt/vmdashboard

"Registration is closed" on first-time setup

An account already exists. Use the Sign In tab instead. If you need to reset, delete the database:

sudo systemctl stop vmdashboard
sudo rm /opt/vmdashboard/backend/dashboard.db
sudo systemctl start vmdashboard

This removes all devices, users, and metric history. The encryption key (secret.key) and JWT key (jwt_secret.key) are preserved, so on next start you go through first-time setup again.

Cannot connect to Proxmox — SSL error

Proxmox uses a self-signed certificate by default. Make sure Verify SSL is unchecked when adding the device.

vCenter "not authenticated" error

Use the full UPN format for the username: administrator@vsphere.local — not just administrator.


Security Notes

  • Credential encryption — device passwords are encrypted with AES-128 Fernet before being stored in SQLite. The key lives in secret.key.
  • JWT signing key — tokens are signed with a random 32-byte key generated on first run and stored in jwt_secret.key (mode 600). It is no longer a hardcoded value. To pin it explicitly (e.g. across multiple instances), set DASHBOARD_SECRET_KEY — see Configuration. Changing the key invalidates all existing login sessions.
  • Password hashing — account passwords are hashed with bcrypt.
  • Login rate limiting — the token endpoint is limited to 10 attempts per minute per IP to slow brute-force attempts.
  • Role-based access — viewer accounts cannot modify devices or users; all mutating API endpoints require an admin token.
  • Service hardening — runs as the unprivileged vmdashboard user with NoNewPrivileges, PrivateTmp, ProtectSystem=strict, ProtectHome, and ReadWritePaths scoped to the backend directory.
  • Internet exposure — if exposing beyond your LAN, place it behind nginx with HTTPS (see the reverse proxy section above).

About

Self-hosted infrastructure monitoring dashboard for VMware vCenter, ESXi, and Proxmox VE

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors