nawasara / proxmox
Proxmox VE management dashboard for the Nawasara superapp framework — cluster-aware VM/LXC inventory, lifecycle operations, snapshot management, and resource monitoring.
Requires
- php: ^8.1
- illuminate/support: ^10.0|^12.0
- livewire/livewire: ^3.0
- nawasara/auth-primitives: *
- nawasara/search: *
- nawasara/sync: *
- nawasara/ui: *
- nawasara/vault: *
- spatie/laravel-permission: ^6.0
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
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:confirmdialogs that distinguish graceful from force-stop. - Auto re-sync. Every successful action chains a
SyncProxmoxVmsJobso 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
- Live (instant) CPU and Memory percentages from
- 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 typespct 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-fdand 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
- Open Nawasara →
/nawasara-vault - Choose the Proxmox group
- 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.
trueif your PVE has a trusted cert,falsefor self-signed
- Host.
- Click Test Connection. It should respond with the cluster version plus node count.
- Save
The package picks up credentials from Vault automatically.
Verification
- Sidebar. The "Proxmox" workspace appears with "Virtual Machines" and "Nodes" entries.
- Nodes page. The cluster summary cards (Nodes, VMs, vCPU, Memory, Storage) populate after the first sync.
- VMs page. The list shows every VM and LXC across the cluster.
- Click a row → Detail. Sparklines render, network interfaces and disks are listed, and the snapshot section is visible (if you have
proxmox.vm.snapshot). - Click Start / Shutdown on a non-template VM. The status badge shows a spinner; the table auto-refreshes when the task completes.
- 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. RoleKisaraConsoleholds onlyVM.Consoleon/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), nopct enter. Every LXC is setcmode=shell, so the console is a root shell inside the container with no login. ⚠️ Acmodechange on a running container is PENDING until it restarts — until then the console showslogin:. Read config withcurrent=1to 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_sessionswithchannel = 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 withCONSOLE_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