Proxmox VM Console Browser noVNC: The Safe Server-Side Relay Guide

proxmox-vm-console-browser-novnc.md
title Proxmox VM Console Browser noVNC: The Safe Server-Side Relay Guide
date
author VahaC
read 10 min read
category Self-Hosting
tags #container #Homelab #Proxmox #Stashboard
proxmox vm console browser novnc

Stashboard V8.6 adds a Proxmox VM console browser noVNC view: the built-in VNC screen of a running QEMU/KVM virtual machine, live in a browser tab, with full keyboard and mouse. It’s the VM twin of the browser LXC console from V6.6 (same master switch, same ticket flow, same audit table) with a completely different transport underneath. 🖥️

A VM has no pct exec and no guaranteed SSH, so the one console every VM has is the VNC display Proxmox already runs, the screen its own web UI opens. Here’s how the Proxmox VM console browser noVNC relay reaches that screen without your API token leaving the backend, how to switch it on, how to prove it works, and where it stops.

What the Proxmox VM Console Browser noVNC View Gives You

A VM’s modal on the Proxmox page now has a working Console tab. Click Connect and the VM’s screen appears in a noVNC canvas: BIOS, GRUB, installer, login prompt or desktop. That makes the Proxmox VM console browser noVNC view the tool for jobs SSH can’t do:

  • Installing an OS from the ISO you attached when you created the VM from the web UI.
  • Rescuing a VM with broken networking, where SSH is exactly what’s down.
  • Watching a boot that hangs at GRUB, a filesystem check or a kernel panic.

The canvas takes full keyboard and mouse input and scales the framebuffer to fit the panel without changing the guest’s resolution. Fill the window stretches the modal over the browser viewport; Full screen uses the Fullscreen API (Esc exits). The session survives switching to the Config or Stats tab; closing the modal disconnects it.

How the Proxmox VM Console Browser noVNC Relay Works

Proxmox exposes a VM’s screen through two endpoints: vncproxy mints a one-time VNC session, and vncwebsocket carries the raw RFB stream (the Remote Framebuffer protocol). Calling them from the browser would mean giving it a Proxmox credential, so Stashboard does it server-side:

  1. The browser sends an authenticated POST to /api/proxmox/connections/{id}/qemu/{vmid}/console/ticket. Gates are checked before any call to Proxmox.
  2. The backend calls POST /api2/json/nodes/{node}/qemu/{vmid}/vncproxy with websocket=1 and the API token in the Authorization header. Proxmox returns a one-time VNC ticket and a display port.
  3. The backend mints its own single-use connect ticket (32 random bytes, valid 30 seconds by default) and returns it with the VNC password, which is that one-time vncproxy ticket.
  4. The browser opens a WebSocket to …/qemu/{vmid}/console/ws?ticket=… on the binary subprotocol and hands it to noVNC. The server redeems the ticket once, for that host and VM only, re-checks the gates and enforces the session caps.
  5. The backend opens …/qemu/{vmid}/vncwebsocket?port=…&vncticket=… with the token in the header, the connection’s TLS setting and a 15-second connect timeout.
  6. A byte pump copies RFB frames both ways verbatim, counting bytes and watching for idleness.

The browser only ever holds two throwaway values: the connect ticket and the one-time VNC password. The long-lived API token never reaches the page, and that’s the whole reason the Proxmox VM console browser noVNC relay lives in the backend.

Prerequisites

Before you switch the Proxmox VM console browser noVNC view on, check these:

  • Stashboard 8.6.0 or newer.
  • A Proxmox VE host connected with an API token. The Proxmox pillar guide covers adding one. No SSH needed, unlike the LXC console, which SSHes to the node for pct exec.
  • VM.Console for that token on the VM. Proxmox checks it on both console endpoints. PVEVMUser includes it (plus power, backup and CD-ROM rights), and so does PVEVMAdmin.
  • A VM with a VGA display (the default).
  • WebSocket forwarding for /api on any reverse proxy in front of Stashboard. If the LXC console already works through it, you’re set.

Step-by-Step: Enable the Proxmox VM Console Browser noVNC Screen

1. Confirm the token can open a console

On the Proxmox node, list the token’s effective rights on the VM (use your own user, token name and VMID):

pveum user token permissions root@pam stashboard --path /vms/105

No VM.Console in the output? Grant a role that carries it:

pveum acl modify /vms/105 --tokens 'root@pam!stashboard' --roles PVEVMUser

⚠️ Two gotchas. Keep the single quotes, or interactive bash treats ! as history expansion. And new tokens use privilege separation by default: effective rights are the intersection of the token’s ACLs and its user’s, so granting the role to the user alone isn’t enough. See the pveum manual and user management docs.

2. Turn on the server-wide switch

Go to Settings → Guest console, tick Enable the guest console server-wide and click Save. It’s the LXC console’s existing switch, renamed from LXC console now that it governs both guest kinds, so it may already be on.

⚠️ Critical: this switch arms more than VM screens. On every opted-in host with SSH configured, it also enables the LXC shell, the LXC live-log tail and a shell on the Proxmox node itself. Turning it on “just for the Proxmox VM console browser noVNC view” turns those on too.

3. Opt the host in

On the Proxmox page, open the host’s menu (⋮ → Edit), tick Allow guest console and save. It’s per host and off by default. ⚠️ The same flag allows LXC and node shells on that host when SSH is configured, so start with your least important host.

4. Start the VM

The Proxmox VM console browser noVNC view attaches to a live VNC display, so the VM must be running. A stopped VM’s Console tab says VM is not running instead of offering Connect.

5. Connect

Click the VM’s card (or right-click it and choose Console), open the Console tab and click Connect. The status dot moves from connecting to connected and the screen appears. Click into the canvas to give it the keyboard; focus returns on its own when you come back to the tab.

There’s no Ctrl+Alt+Del button in 8.6, and your own OS may swallow that combination before the browser sees it. If a guest insists on it, use the Proxmox web UI for that one keystroke.

When It Says “Console Unavailable on This Host”

A failed Proxmox VM console browser noVNC session ends in a readable message, not a hung canvas. It can fail in two places.

Ticket (vncproxy) stage: a 409 with “The VNC console is unavailable on this host. The VM must be running and have a VGA console, and the API token needs the VM.Console privilege.” Check those three things.

WebSocket (vncwebsocket) stage: the relay closes the socket with the exact reason.

  • “Proxmox refused the VNC websocket: 401 — this PVE version rejects API-token auth for the console.” The known caveat: token acceptance on vncwebsocket varies by PVE version, and since vncproxy just accepted the same token, it’s the websocket endpoint refusing it. There’s no in-Stashboard workaround in 8.6; use the Proxmox web UI for that host’s VMs.
  • “Proxmox denied the VNC websocket: 403 — the API token needs the VM.Console privilege on this VM.” Back to step 1.
  • “VNC websocket upgrade timed out — a reverse proxy may not be forwarding WebSocket upgrades to Proxmox.” Something in front of port 8006 is eating the upgrade.

A browser-side “Console connection timed out” after 15 seconds usually means the proxy in front of Stashboard drops the upgrade, and “You already have 3 console session(s) open (limit 3)” is the shared cap. If the socket closes with no reason at all (some proxies strip it), the server log has the host’s exact answer (swap in your container name):

docker logs --tail 100 stashboard-app 2>&1 | grep -i "vncwebsocket upgrade failed"

One Audit Trail for LXC and VM Consoles

Every Proxmox VM console browser noVNC session that clears the ticket and the session caps writes a row to ProxmoxConsoleSessions, the same table the LXC console uses. Audit → Guest console (or View session history under the console) lists VM screens next to LXC shells: host and node, guest and VMID, start, end, duration, bytes in and out, and end reason. The Command column tells them apart: LXC rows show the shell, such as /bin/bash; VM rows read VNC console. A relay that fails to reach Proxmox still leaves an Error row with the reason, and a row orphaned by a crash is closed as Interrupted (server restart) on the next start.

The guardrails are shared too: by default 3 sessions per user and 5 per host, counted across LXC shells and Proxmox VM console browser noVNC sessions together, plus a server-side close after 600 seconds without traffic. Tune them with environment variables:

STASHBOARD_Stashboard__ProxmoxConsole__MaxSessionsPerUser=3
STASHBOARD_Stashboard__ProxmoxConsole__MaxSessionsPerHost=5
STASHBOARD_Stashboard__ProxmoxConsole__IdleTimeoutSeconds=600
STASHBOARD_Stashboard__ProxmoxConsole__TicketTtlSeconds=30

How to Verify Your Proxmox VM Console Browser noVNC Setup

Run this pass on a throwaway VM before you trust the Proxmox VM console browser noVNC view with anything real:

  1. Happy path. Connect to a running VM; the screen should appear within seconds. Type at the login prompt and move the mouse.
  2. Fit. Press Fill the window, then Full screen. The canvas should rescale both times.
  3. No token in the browser. With DevTools → Network open, Disconnect and Reconnect. The ticket response should hold only ticket, password, expiresInSeconds and webSocketPath, and the WebSocket URL nothing but ?ticket=.
  4. Replays fail. Reuse that WebSocket URL from the DevTools console: const ws = new WebSocket('<copied URL>', ['binary']); ws.onclose = e => console.log(e.code). It logs 1006: the ticket was spent on first use (and expires after 30 seconds anyway).
  5. Gates hold. Untick Allow guest console and reopen the VM’s Console tab: The console is not enabled for this host. Stop the VM: VM is not running. Restore both.
  6. Audit. Disconnect, then find a VNC console row in Audit → Guest console with non-zero bytes and Closed by client.
  7. Logs. docker logs stashboard-app 2>&1 | grep "VM console" should show an opened and a closed line with byte counts.

⚠️ If step 6 comes back empty, stop before you enable more hosts. An audit trail you trust but that doesn’t record is worse than none.

Risks and What’s Out of Scope

A Proxmox VM console browser noVNC session is the VM’s physical keyboard and monitor:

  • It sidesteps network-level protections. Firewall rules and SSH keys don’t apply, and whoever holds the console during a reboot can edit the GRUB boot line unless GRUB is password-protected.
  • Disconnecting doesn’t log you out. A root shell left on tty1 waits for whoever connects next, here or in the Proxmox UI.
  • Screen updates count as activity. The idle timer resets on bytes in either direction, so a constantly changing screen can keep an abandoned session open.
  • Some hosts won’t work while their PVE version refuses token-auth vncwebsocket relay.

Not part of the Proxmox VM console browser noVNC view in 8.6: SPICE (it needs a native client such as virt-viewer), audio, clipboard sync (you type, you don’t paste), USB redirection, and the serial termproxy console for VMs without a VGA device.

Proxmox VM Console Browser noVNC FAQ

Does the Proxmox VM console browser noVNC view need SSH?

No. It runs on the Proxmox API token, server-side. Only the LXC and node shells need SSH.

Does a Proxmox VM console browser noVNC session expose my API token?

No. The browser receives only a single-use connect ticket and a one-time VNC password.

Why does the Proxmox VM console browser noVNC view fail on one host but not another?

Usually a missing VM.Console privilege, a stopped VM, no VGA display, or a PVE version that refuses token auth on vncwebsocket. The WebSocket-stage message names the exact status Proxmox returned.

Bottom Line

With V8.6 the browser console stops being container-only. The Proxmox VM console browser noVNC view gives you a VM’s real screen (installers, boot menus, rescue shells) without opening the Proxmox web UI or handing your browser a Proxmox credential. Start with one host, one throwaway VM and the verification pass above. 🚀

New here? Read the Stashboard homelab dashboard overview. Stashboard is open source: code on GitHub, image on Docker Hub.

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.