
Stream Deck Proxmox Monitor: A Safer Read-Only LXC Setup
If you have an Elgato Stream Deck sitting in a drawer, it makes a surprisingly good Proxmox monitoring panel. You stop opening the web interface every time you want to check CPU load, guest status, network traffic, or whether a service is up, because that data sits on physical keys next to the server. I care less about the hardware, though, than about how the build is put together.
A recent project put the monitoring agent in its own unprivileged LXC, gave it a read-only Proxmox API token, passed the Stream Deck USB device into that container, and used the keys to show host and VM status. You can page through host metrics, guest state, network throughput, a manual speed test, and simple HTTP health checks. That is a lot better than running some random Python process as root on the hypervisor. If you want a physical Proxmox dashboard, keep it read-only, isolated, and easy to throw away.
What can a Stream Deck actually show from Proxmox?
Almost any status data the Proxmox API exposes can be squeezed into a small tile. The project behind this post currently builds five pages. The Host page shows CPU usage, RAM, disk usage, swap, load average, and uptime. The Guests page lists VMs and LXCs as running or stopped, with CPU utilization. The Network page aggregates traffic and picks out the biggest talkers, and the Speedtest page runs an actual internet speed test from the monitoring container. The Health page checks configured HTTP or HTTPS endpoints and shows each service as a green or red tile.
For a physical panel, that is about the right amount. A Stream Deck is not Grafana, and cramming graphs, logs, storage latency histograms, and twenty alerts onto a few tiny LCD keys would ruin it. It works best when each tile answers one short question: is the host overloaded, is Home Assistant running, which VM is eating bandwidth, is the reverse proxy responding, is storage filling up? When you need more detail, open your real monitoring system; the Stream Deck is the thing you glance at before you do.
For wider monitoring and infrastructure ideas, the Mr.PlanB Proxmox hub covers the platform beyond this one dashboard experiment.
Why run the monitoring agent inside an LXC?
Because the Proxmox host should stay boring. The Stream Deck agent is a third-party Python process. It talks to USB hardware, polls APIs, renders images, runs network checks, and pulls in packages such as hidapi, libusb, Pillow, Requests, and a Stream Deck library. None of that belongs on the hypervisor without a strong reason.
The project creates an unprivileged Debian LXC instead and runs the agent there as a dedicated non-root user. That gives the experiment a clean failure boundary. If a Python package breaks, restart the container. If the config turns into a mess, rebuild it. If you lose interest, delete it. And if someone compromises the agent through a dependency or a health-check target, they land in an unprivileged container, not directly in the Proxmox host environment. The LXC can still be broken into, but the blast radius is much smaller.
Proxmox describes unprivileged containers as using user namespaces, so UID 0 inside the container maps to an unprivileged UID on the host. For a small utility workload like this one, that is the isolation you want.
What Proxmox permissions should the panel have?
Just enough to read status. The reference implementation creates a dedicated Proxmox user and assigns the built-in PVEAuditor role at /. That role is meant for read-only visibility. The agent authenticates with an API token and polls the Proxmox REST API over HTTPS.
What matters is what the panel cannot do. It cannot start or stop a VM, delete storage, change a network bridge, modify a container, or alter cluster settings. That is the right default. A monitoring panel has no reason to hold admin rights just because the API offers them.
Someone in the community described a different Stream Deck setup where a button opens Remote Desktop or PuTTY depending on the VM. That is still fairly harmless, since the button launches a client application and doesn't change infrastructure state through the Proxmox API.
You can see where this goes, though. Once there are physical buttons, somebody will want a "restart VM" key, a "shutdown node" key, or a giant red "do not press" key. Fine in a lab, but those actions should not use the monitoring service's credentials. If you add write actions, build a separate control path with its own credentials and explicit safeguards. Don't slip admin rights into the monitoring token.
How does the USB passthrough work?
This is the least elegant part of the build. The Stream Deck plugs into the Proxmox host, but the Python agent runs inside an unprivileged LXC, so the container needs access to the USB device. The project allows USB character devices and bind-mounts the host's /dev/bus/usb tree into the container. The LXC configuration includes the equivalent of:
lxc.cgroup2.devices.allow: c 189:* rwm
lxc.mount.entry: /dev/bus/usb dev/bus/usb none bind,optional,create=dir
A udev rule on the host then sets permissions for Elgato devices using USB vendor ID 0fd9.
Why mount the whole USB bus tree and not a single device path? USB device numbers change. A Stream Deck that shows up under one /dev/bus/usb/... path can come back under a different one after you unplug and reconnect it. Binding the whole tree lets the container see the re-enumerated device without a config edit each time.
That's convenient, and it also exposes more than passing one fixed device node would. In this design the practical restriction comes from host-side device permissions and the fact that the LXC is unprivileged. If the host has other sensitive USB devices attached, review what you're exposing before copying the configuration.
On a dedicated homelab host with one Stream Deck plugged in, I can live with that compromise. On a production server with USB security keys, license dongles, backup media, or other privileged peripherals, I would be much more careful.
Why can the Stream Deck disappear after unplugging it?
USB libraries don't always recover cleanly when a device is removed. The author ran into this with hidapi and libusb: after unplugging and reconnecting the Stream Deck, the process could stop finding the device. Restarting the whole monitoring service cleared the stale state, so the project added watchdog-style behavior. If no Stream Deck is detected for a configured amount of time, the process exits and systemd starts it again with fresh USB library state.
Ideally the library stack would handle every reconnect perfectly. In practice the fix is "device gone too long, restart the tiny service," and that's a sensible way to build for the hardware you actually have. For a monitoring appliance it's an acceptable recovery strategy, because the service holds so little state that restarting it costs almost nothing.
Why does the panel dim after inactivity?
Mostly so static images aren't lit all the time. The build dims the Stream Deck after 25 seconds without a button press and wakes it as soon as a key is touched. The repository notes that power savings aren't the main reason, since Stream Deck devices draw very little power anyway. The goal is to avoid the same bright tiles glowing all day and night.
It's a small detail, but it makes the project feel like an appliance and less like a demo. When everything is normal, the panel fades into the background. Touch it when you want information. When something needs attention, the key colors should make that obvious without you pressing anything.
Is this better than Grafana or the Proxmox UI?
No, it does a different job. Grafana is better for historical metrics, dashboards, correlations, alerting, and trends. The Proxmox UI is where you actually administer things. A proper monitoring stack handles notifications. The Stream Deck gives you ambient awareness.
It's most useful when the Proxmox host is in the same room as your desk, rack, lab bench, or office. You can see that all guests are green without switching windows, notice one VM pushing unusual bandwidth, or press a key for a quick speed test. It won't replace your monitoring, but you'll open it less often. That sounds minor until you count how many times a day homelab admins check the same few status values.
What would make the panel more useful?
It would probably gain more from better signals than from more raw metrics. A backup tile could show the age of the last successful backup, and a storage tile could turn amber when a ZFS pool becomes degraded. A Ceph tile could summarize HEALTH_OK, HEALTH_WARN, or HEALTH_ERR. A UPS tile could show mains power, battery percentage, and runtime remaining, while a cluster tile could show quorum state. A PBS tile could show whether the last datastore verification completed successfully. A certificate tile could warn when an important TLS certificate has fewer than 30 days left, and a patch tile could flag pending Proxmox updates without installing them.
Every one of those is still read-only, which is where I'd keep it. A physical dashboard that tells you what deserves a closer look, and can't change anything, stays useful and low risk. Once it turns into a control console, every button needs a lot more thought.
Should you copy the install scripts directly?
Read them first. The project ships two scripts that create the LXC, set up USB passthrough, create the API user and token, install dependencies, and configure the systemd service. Handy for a homelab project, but it's also root-level automation running on a Proxmox host.
According to the author, the scripts were written with AI assistance. That isn't good or bad on its own. What helps is that the repository is small enough to read in one sitting.
Before running any community setup script as root, read the parts that:
- modify
/etc/pve/lxc - create Proxmox users or tokens
- edit udev rules
- change USB device permissions
- install packages
- download Python dependencies
- create systemd units
You don't have to distrust the author. You do have to know what your hypervisor is being asked to do, and that goes for every convenience script.
A Proxmox Health Check is useful for reviewing the host itself, but you should still understand community automation before it becomes part of that host.
The best physical Proxmox panel should be boring
The Stream Deck is the flashy part, and the good engineering decisions are much harder to spot. The agent runs in its own unprivileged LXC as a non-root user. It uses a read-only API token and polls with GET requests. You can rebuild it without touching the hypervisor. When USB reconnects fail, it restarts a small stateless service and leaves the host alone.
That's why this is more interesting than a novelty dashboard. It shows a pattern worth using for homelab tooling in general: put convenience tools close to your infrastructure, but don't give them the same authority as the infrastructure.
A Stream Deck full of green and red tiles is fun, and one that can't accidentally destroy anything is better.
Frequently Asked Questions
Can an Elgato Stream Deck monitor Proxmox?
Yes. A small Python agent can poll the Proxmox API and show CPU, RAM, disk, guest, network, and service-health data on Stream Deck keys.
Should a Stream Deck monitoring tool have Proxmox admin permissions?
No. Give it a dedicated API token with the built-in PVEAuditor role, or another narrowly scoped read-only role, so the panel cannot start, stop, or modify workloads.
Why run the Stream Deck agent in an LXC?
An unprivileged LXC keeps the USB-facing Python process off the Proxmox host itself. If the agent breaks or gets compromised, the container boundary and the read-only API token limit what it can do.