Search by

nawasara / proxmox

pringgojsnawasara

Proxmox VE management dashboard for the Nawasara superapp framework — cluster-aware VM/LXC inventory, lifecycle operations, snapshot management, and resource monitoring.

Package info

github.com/nawasara/proxmox

pkg:composer/nawasara/proxmox

Statistics

Installs: 405

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.7.6 2026-11-06 02:22 UTC

README

Proxmox VE management for the Nawasara superapp framework: VM and LXC inventory, lifecycle control (start/stop/shutdown/reboot), snapshot management, live resource metrics, and a one-click console deep link. Everything is surfaced from a local DB snapshot for speed and mutated through queue jobs for auditability.

Features

  • Cluster-aware inventory. A single API token covers every node in a PVE cluster; one-shot fetch via /cluster/resources?type=vm.
  • VM / LXC list. Paginated, filterable by node, status, type, and template; running/stopped/paused chips with live counts.
  • Lifecycle actions. Start, graceful shutdown, force stop, and reboot, with wire:confirm dialogs that distinguish graceful from force-stop.
  • Auto re-sync. Every successful action chains a SyncProxmoxVmsJob so the UI reflects real Proxmox state (uptime, mem usage, locks) immediately after.
  • Live status badges. An in-row spinner while a queued/running action is in flight; a red "X failed" hint for 5 minutes after a failure.
  • Task log viewer. A terminal-styled modal that streams the Proxmox task log (/nodes/{n}/tasks/{upid}/log) for any past action.
  • Detail modal with:
    • Live (instant) CPU and Memory percentages from /status/current
    • 1h CPU and Memory sparklines from RRD AVERAGE (peak / avg supporting metrics)
    • Network interfaces parsed (MAC, bridge, firewall flag) from getVmConfig()
    • Disks listed with the raw config string per device
    • OS type, boot order, description
  • Snapshot management. List, create (with optional vmstate / RAM capture for qemu), rollback, and delete; UPID-tracked with an up-to-10-minute timeout.
  • Console. A full-screen xterm.js tab connected through the nginx relay /__proxmox-ws/. QEMU uses its own text console; LXC opens the node shell and types pct enter <vmid>, so no container password is needed. Termproxy tickets need a username + password session (API tokens are refused). The websocket auth line must carry the termproxy ticket: since PVE 8.4.21 termproxy runs with --ticket-fd and rejects the session ticket, which closed every console until v0.7.3. The session ticket only travels inside the websocket URL, where nginx turns it into the handshake cookie.
  • Cluster overview. Node summary cards (CPU / RAM / storage totals plus per-node detail); polls every 30s idle, every 4s while a sync is in flight.
  • Sync info bar showing the last successful sync time, status counts, and a link to the audit log.

The package follows the DB-cache plus queue pattern from nawasara/sync: reads come from local snapshot tables; writes dispatch queue jobs that hit the Proxmox API and update the snapshot via content-hash diffing.

Capacity alerts

Runs hourly (nawasara-proxmox:check-capacity) and warns before a disk fills up. It was added after the production database went down because its disk was full, with no warning at all. The data had been syncing every 15 minutes for months; nothing was reading it and saying "this is about to become a problem."

It fires only when both hold: usage is past the threshold, and the free space left is genuinely small (default 20 GB). Percentage alone misleads on large disks. One production machine sits at 84.6% with 151 GB free, and an alert that fires when nothing needs doing is the fastest way to teach people to ignore it.

It resolves itself once space frees up, so a badge that stays lit never buries the alert that is actually new.

QEMU VMs are not covered

Proxmox only reports in-guest disk usage for LXC. For QEMU the API returns 0 unless qemu-guest-agent is installed, and in Ponorogo all 20 QEMU VMs report 0.

Those machines are skipped, not treated as 0%. Treating them as empty would paint the dashboard green for machines whose state is simply unknown, the same false confidence that let the outage through. The skipped count is logged every run so the gap stays visible.

Install the guest agent inside a VM and it joins the check automatically.

Thresholds are .env-tunable: PROXMOX_DISK_WARNING, PROXMOX_DISK_CRITICAL, PROXMOX_DISK_MIN_FREE_GB, PROXMOX_MEM_WARNING, PROXMOX_MEM_CRITICAL.

Guide (Indonesian): docs/panduan/pemantauan-kapasitas.md

Installation

composer require nawasara/proxmox
php artisan migrate
php artisan db:seed --class="Nawasara\Proxmox\Database\Seeders\PermissionSeeder" --force

The package is auto-discovered by Laravel, so no manual provider registration is required.

Proxmox API Token Setup

The package authenticates with a PVE API Token, which can be revoked or scope-restricted from the Proxmox UI without touching the underlying user.

1. Sign in to the Proxmox web UI

Open https://your-proxmox-host:8006 and sign in as root@pam (or any user with Sys.Audit plus VM.* permissions on /).

2. Open API Tokens

Navigate to Datacenter → Permissions → API Tokens.

3. Create a token

Click Add:

  • User. Choose the user that owns the token (e.g. root@pam).
  • Token ID. A short identifier (e.g. nawasara).
  • Privilege Separation. Uncheck if you want the token to inherit the user's permissions, or leave it checked and assign granular permissions separately (recommended for least-privilege).
  • Expire. Leave empty for permanent.

Click Add. The dialog displays the token secret once, so copy it now.

The token is identified by {user}@{realm}!{tokenid} (e.g. root@pam!nawasara).

4. Grant permissions

If you used Privilege Separation, the token has no permissions until you grant them:

Datacenter → Permissions → Add → API Token Permission:

Path Role Used for
/ PVEAuditor Read cluster, nodes, VM list, status
/vms/<vmid> (or /vms) PVEVMAdmin Lifecycle actions, snapshots
/nodes/<node> PVEAuditor Per-node detail, RRD data

For a quick start, grant PVEAdmin on / to a single dedicated token, then narrow it down later.

5. Self-signed certificates

If your Proxmox cluster uses a self-signed certificate (the default on fresh installs), set Verify SSL to false in the Vault configuration below. For production, install a trusted certificate and keep verification on.

Storing credentials in Vault

  1. Open Nawasara → /nawasara-vault
  2. Choose the Proxmox group
  3. Fill in:
    • Host. https://pve.example.go.id:8006 (no trailing slash, include the port)
    • Token ID. The full identifier user@realm!tokenname
    • Token Secret. The value displayed once in step 3
    • Verify SSL. true if your PVE has a trusted cert, false for self-signed
  4. Click Test Connection. It should respond with the cluster version plus node count.
  5. Save

The package picks up credentials from Vault automatically.

Verification

  1. Sidebar. The "Proxmox" workspace appears with "Virtual Machines" and "Nodes" entries.
  2. Nodes page. The cluster summary cards (Nodes, VMs, vCPU, Memory, Storage) populate after the first sync.
  3. VMs page. The list shows every VM and LXC across the cluster.
  4. Click a row → Detail. Sparklines render, network interfaces and disks are listed, and the snapshot section is visible (if you have proxmox.vm.snapshot).
  5. Click Start / Shutdown on a non-template VM. The status badge shows a spinner; the table auto-refreshes when the task completes.
  6. Click "Lihat Log". The modal shows the Proxmox task log for the most recent action.

Error handling reference

Symptom Cause Fix
HTTP 401 on test connection Token ID or secret typo Re-paste from PVE; the full ID format is user@realm!tokenname
HTTP 403 on lifecycle action Token lacks VM.PowerMgmt on /vms/<id> Grant PVEVMAdmin on /vms (or the specific path)
HTTP 500: Not a HASH reference Mutation sent without a form body (legacy bug) Already handled; the client uses asForm() for all POST mutations
cURL: SSL certificate problem Self-signed cert plus verify_ssl=true Set Vault verify_ssl to false, or install a trusted cert
Action stuck at "Starting..." forever Task did not appear in /tasks/{upid}/status Check Proxmox /var/log/pveproxy/access.log; raise the job timeout if the task is genuinely slow
VMs missing from the list Token cannot see them The token needs at least PVEAuditor on the path containing the VMs (/vms or /pool/<poolname>)

Permissions

Permission Description
proxmox.node.view View cluster and node list
proxmox.vm.view View VM/LXC list and detail
proxmox.vm.lifecycle Start, stop, shutdown, reboot
proxmox.vm.snapshot Create, rollback, delete snapshots
proxmox.vm.console Open the noVNC console
proxmox.sync.execute Trigger a manual cluster re-sync

All permissions are auto-assigned to the developer role by the seeder.

Container console for PICs (Akun Kisara)

A container's PIC can open its console from Akun Kisara, on its own host (console.ponorogo.go.id, config kisara_console.host). KisaraConsole issues the link; KisaraConsoleController serves the page.

  • Proxmox account kisara-console@pve, never root@pam. Role KisaraConsole holds only VM.Console on /vms: it opens container consoles and is refused the node shell (403), configs (403) and power actions. Credentials live in Vault (proxmox.kisara_console_*). A ticket leaked from the internet opens one console, not the cluster.
  • Straight to the container (/lxc/{vmid}/termproxy), no pct enter. Every LXC is set cmode=shell, so the console is a root shell inside the container with no login. ⚠️ A cmode change on a running container is PENDING until it restarts — until then the console shows login:. Read config with current=1 to see what is actually in force.
  • No panel session on that page. Who may open it is decided by nawasara/asn-portal (active PIC in the registry + a recent sign-in). The link is single-use (ticket_ttl, 60 s) and bound to the requester's IP when the portal forwards it; heartbeat/close are accepted only from the browser session that opened the page.
  • LXC only: QEMU has no cmode, and its console asks for a login.
  • Sessions are logged in nawasara_proxmox_console_sessions with channel = kisara, separate from panel sessions (panel).
  • The host must reach Nawasara's nginx: add it as a public hostname on the Cloudflare tunnel (dashboard-managed). The /__proxmox-ws/ relay serves it unchanged, and the websocket uses the console host itself.

Console session recordings

Every console session — panel and Akun Kisara — is recorded by the console-recorder sidecar (docker/console-recorder in the app repo), which sits between nginx's /__proxmox-ws/ relay and Proxmox and writes asciicast v2 files to storage/app/console-recordings. Play them from Riwayat Console → Putar rekaman (permission proxmox.console.history).

  • Output only. Keystrokes are not recorded: a password typed at a prompt is never echoed, so recording the screen never stores it. The first browser message (user:ticket) is not recorded either.
  • Fail-closed. The websocket URL carries rec=<session id>.<HMAC>, signed with CONSOLE_RECORDER_SECRET (same value in the app and the recorder). The recorder refuses any session without a valid mark, so no console can run unrecorded, and nobody can point their session at another session's file. Files are never overwritten (<id>-<ms>.cast).
  • Retention 90 days (CONSOLE_RECORDING_RETENTION_DAYS), pruned daily at 03:30 WIB. Session metadata (who, when, how long) is kept.
  • 50 MB cap per session; past it the console keeps working and the recording is marked truncated.
  • Without a recorder (dev), the entrypoint points the relay straight at Proxmox and nothing is recorded.

PIC per VM (through nawasara/registry)

Every VM and LXC container is mirrored into nawasara/registry as a Server / VM asset (VmRegistrySync, run at the end of each VM sync), so it gets a primary PIC and backup PICs the same way a domain or cPanel account does — set from the VM list's OPD & PIC menu, which opens the registry's own modal. The PICs then see their servers in Akun Kisara (GET /account/servers in nawasara/asn-portal).

  • Keyed by package_ref = proxmox, external_id = vmid — not the proxmox row id. The VM sync hard-deletes and recreates rows for VMs that vanish and come back; the PIC must survive that.
  • A VM that leaves the cluster is marked inactive, never deleted, so its PIC history stays. Asset status follows existence, not power: a stopped VM still has an owner.
  • If the sync read no VMs at all, nothing is deactivated — an empty list means the API was unreachable, and deactivating would empty every PIC's Akun Kisara at once.
  • Templates are skipped. Registry is a soft dependency (class_exists): without it the column and menu simply do not appear.
  • Identifier is name (#vmid): names repeat across the cluster.

Future cross-link with iTop

The nawasara_proxmox_vms table reserves an itop_server_id column (nullable, indexed). When the nawasara/itop integration ships, the sync job will populate this with the matched ItopServer.id (where finalclass = VirtualMachine) so a single VM can be navigated from either side.

Author

Pringgo J. Saputro <odyinggo@gmail.com>

License

MIT