Opening an LXC console left a failed task on the Proxmox node:
failed waiting for client: timed out
TASK ERROR: command '/usr/bin/termproxy 5900 ... vzctlconsole101' failed
connectTerminal() called GET /api/{sid}/container/{vid}/terminal first,
which creates a termproxy session on the node, but only the `node` field
of the response was used - port and ticket were discarded. The ws
endpoint then created a second termproxy session and connected to that
one. Nobody ever attached to the first, so Proxmox waited ~10s for a
client and failed the task.
The console also rendered a black screen in dev: React StrictMode mounts
the effect twice, connect* are async, and the effect cleanup ran before
they had assigned wsRef/termRef, so it had nothing to clean up. Two
xterm instances ended up in the same container - the first one filled
the viewport while the live one was pushed out of the overflow-hidden
area, which is why the badge read "connected" over an empty screen.
- drop the redundant REST call; the ws endpoint owns the termproxy
- remove the now unused GET /api/{server_id}/container/{vmid}/terminal
- add a per-session cancellation guard: a stale connect closes its own
socket and disposes its own terminal without touching refs that may
already point at the live session
- route mount and the reconnect button through a single startSession()
that cancels and tears down the previous session first
- apply the same guard to the node shell page
network:view is no longer implied by server:view, and neither network:view
nor ipam:view is granted to the non-admin default roles (operator, user,
demo). The network topology, node/SDN interface configuration and IPAM are
administrative surfaces, not part of the baseline "can see servers"
umbrella, so they should be granted explicitly rather than inherited.
Clicking a guest card now navigates to /instances/:serverId/:vmid, the
same route used from the Instances list, with a hover highlight to
signal it's clickable.
Add a "scan exports" button next to the server field for NFS storages
that calls Proxmox's /nodes/{node}/scan/nfs and turns the export path
input into a select populated with the real exports found on the
target server, instead of requiring the path to be typed by hand.
Proxmox rejects lxc move_volume on a running container. Instead of
just disabling the button, show a modal that explains the container
will be stopped, walks through stop -> move -> start with progress,
and always restarts the container even if the move itself fails.
For VMs (and already-stopped containers) it's a plain confirm modal.
Proxmox rejects lxc move_volume on a running container
("cannot move volumes of a running container"), unlike qemu
move_disk which works live. Surface this as a disabled button
and hint instead of a raw 500 error.
Disk move was hardcoded to the QEMU move_disk Proxmox API and was
never reachable in the UI for LXC (no Hardware tab for containers,
and the disk list regex only matched VM device names).
- add move_container_disk() using lxc/{vmid}/move_volume
- add POST /api/{server_id}/container/{vmid}/disk/move endpoint
- route useMoveDisk by instance type (vm vs container prefix)
- recognize rootfs/mp\d+ as LXC disk devices
- add a Move disk card on the Settings tab for LXC instances
- filter target storage list by supported content type
(rootdir for LXC, images for VM) instead of showing all storages
Increase the progress bar width and label/detail font size for the
vCPU/RAM rows so they're easier to read at a glance, matching feedback
on the collapsed metrics panel added earlier.
Move CPU/RAM/Disk/Net/Disk I/O/Uptime out of the always-visible table
columns into a per-row expandable panel (opened by clicking the
instance name), matching VMmanager's disclosure UX. Adds a Parameters
link into the panel pointing to the instance settings tab, and
clearer stat cards for network/disk throughput.
- Export: use useReactFlow().getNodesBounds() (measured dimensions) instead
of the standalone helper, which treated every node's size as zero and
clipped the last row/column of the exported image
- Export: give edge paths an explicit inline stroke before capture -
html-to-image clones <svg> natively and skips computed-style inlining for
it, so edges came out with no stroke at all
- Enable the edge flow animation (was hardcoded off)
- Switch the graph from left-to-right to top-to-bottom, including flipping
every node's handle positions, and recolor edges from the barely-visible
border tone to the primary accent
Fix nested h-screen flexbox layout bug that let the noVNC canvas overflow
below the viewport until the browser zoom level was changed (missing
min-h-0 on flex children). Also add a fuller console control bar: power
menu (reboot/shutdown/hard reset/hard stop), extra-keys menu (Ctrl+Alt+Del,
Ctrl+Alt+Backspace, Tab, Esc, Ctrl+Alt+F1-F12), scale toggle, clipboard
paste to guest, and console screenshot. Adds a VM hard-reset backend
action (qemu status/reset) alongside the existing start/stop/restart/shutdown.
getViewportForBounds treats a numeric padding as a fraction of the
canvas size (not pixels) unless given a "Npx" string, so the padding=40
passed in the previous fix was read as 4000% padding and still
collapsed the zoom to its floor - the graph rendered small on a mostly
empty canvas exactly as before. Verified in-browser: PNG/SVG exports
now fill ~98% of the canvas instead of ~20%.
Forcing a 1200x800 minimum canvas made getViewportForBounds compute a
zoom above the 2x cap for small graphs, leaving the exported PNG/SVG
mostly empty with the graph rendered tiny in the corner.
Interactive infrastructure map (panel -> cluster -> node -> guest) rendered
with React Flow, backed by a single aggregated /api/network/topology endpoint
instead of fanning out over servers/nodes/SDN/VMs. Adds a netN NIC parser for
QEMU/LXC guest configs, status/threshold filters, canvas tools, and PNG/SVG
export.
The CT template select listed both the raw archive file name and the
headline on one line, which was long and hard to scan. Render the
headline alone and keep the file name in the title tooltip, matching
the convention already used on the images page. Falls back to the file
name when the repository provides no headline.
The dialog body is a grid whose implicit column is auto-sized, i.e.
max-content. Long unbreakable option labels (e.g. CT template file
names) widened that column and pushed the select fields and footer
buttons past the dialog edge.
Use grid-cols-[minmax(0,1fr)] on DialogContent to cap the track at the
dialog width, and apply the same guard to the Alert grid template.
Verified: dialog scrollWidth now equals clientWidth at both 1280px and
375px viewports, with no horizontal page overflow.
Add min-w-0 and overflow-hidden to SelectTrigger and min-w-0 to
SelectValue so long option labels (e.g. CT template names) and grid
columns no longer push select fields past the modal boundary. Fixes
overflow across all dialogs sharing the Select component.
Derive a human-readable OS name (e.g. Debian 13, Ubuntu 24.04) from the
vztmpl volid instead of showing the raw template path like
local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst in the instances list.
Applied at the display layer, so existing instances are fixed too.
- Surface a topbar indicator with a live count of active tasks
- Propagate exceptions from Proxmox LXC container creation instead of
swallowing them, and validate minimum password length
- Replace the Fedora catalog icon with the official logo artwork
Prevent edit/delete action buttons from overlapping with long template
names by using shrink-0 on icon and button containers with flex-1
min-w-0 on the text area. Make header and filter selects responsive
with flex-wrap and full-width on mobile breakpoints.
Add DNS name validation (RFC 952/1123) for VM, LXC and ISO instance
names on both backend and frontend. Proxmox rejects names with
underscores or special characters but the error was only surfaced as
a raw 400 from the API.
Also require Cloud-Init user and password fields for VM deploys
(highlighted when empty, Next button blocked), and fix numeric input
fields that showed "0" on clear and concatenated values like "04096".
After install_docker adds the user to the docker group, the change only
takes effect in a new login session. The script continued running in
the old session, docker info failed, and deploy exited with "Cannot
connect to Docker daemon" even though the daemon was running fine.
Now check_requirements detects this situation (sudo docker works but
docker doesn't, and the user IS in the docker group per /etc/group)
and re-execs the entire script under `sg docker` to activate the
supplementary GID without a logout/login cycle. A _DEPLOY_REEXEC
guard prevents infinite loops.
sudo cp preserves the source umask which can leave the file without
read permission for group/others. A bash script needs both read and
execute bits — without read, the shell cannot interpret it.
verify_nginx_running grepped for "running|healthy" in the human-readable
STATUS column of docker compose ps, but the column shows "Up Xs (health:
starting)" for the first 30s before the healthcheck passes — neither
word matches. With max_wait=20s the function always timed out and the
deploy script rolled back to the HTTP-only config even though the SSL
certificate was successfully obtained.
Switch to --format '{{.State}}' which returns the raw "running" state
immediately, and bump max_wait to 60s for slow first starts.
Previously install_pve_cli silently skipped installation when deploy.sh
was run without root, leaving the 'pve' command unavailable. Now it
tries sudo first (password is usually cached from docker operations)
and falls back to ~/.local/bin with automatic PATH configuration.
Remove the previous owner's SSH keys and apply the new owner's keys
(profile + library) when ownership is reassigned. If the new owner has
no keys, the old keys are simply removed.
QEMU VMs: updates cloud-init sshkeys via Proxmox API.
LXC containers: writes /root/.ssh/authorized_keys via exec.
The swap is best-effort — failures are logged but do not block the
ownership change.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Only show user-relevant filesystems by skipping snap/loop mounts
and /boot/* partitions in QEMU guest agent fsinfo response.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
volume_exists() only checked file presence, not content. A stale image
from a previous download (different URL/version) would be silently reused,
causing templates and VMs to be created from unpatched images even when
the mirror's checksum pointed to a newer patched build.
Add delete_volume() to ProxmoxClient storage mixin, and update both
_do_image_download_sync and _do_image_template_sync to delete the cached
volume and re-download whenever a checksum is provided, letting Proxmox
verify the new download server-side.