← Back to Reviews
Self-Hosting / Retrospective

Kasm Workspaces — A Real Retrospective on Why We Walked Away

Kasm Workspaces (browser-based virtual desktops, with Proxmox auto-provisioning new agent VMs on demand) ran in this homelab for weeks — real testing, real bugs found and fixed, real autoscaling working correctly at the end. Then it got retired anyway. Not because it broke. Here's the honest arc, including three separate root causes hiding behind what looked like the exact same bug recurring.

Share on X

See our full install and permission-setup guide for the mechanics of getting Kasm's autoscaler talking to Proxmox in the first place. This piece is about what happened after it was running.

The same symptom, three genuinely different causes

Kasm's autoscaler kept doing the same thing: clone a new agent VM, boot it, wait for it to check in, never hear from it, destroy it, repeat — forever, every 10-11 minutes. The temptation on a recurring bug like this is to assume "same symptom, same cause, check the last fix." That assumption was wrong every single time it recurred.

  1. First cause: a missing non-interactive flag. The clone script never passed an EULA acceptance flag, so every fresh VM hung forever at an interactive install prompt with no terminal attached to answer it. Found by catching a clone before it got destroyed and reading its install log directly — the log's last line was the EULA text, cut off mid-prompt.
  2. Second, separate issue found while investigating the first: real disk contention. The agent template and every clone's disk lived on the same physical storage as an unrelated, latency-sensitive game server. Every clone/destroy cycle did a real tens-of-gigabytes read/write burst on that shared storage, measurably competing with the game server's own disk activity (confirmed via real I/O throughput monitoring during a live cycle). Fixed without moving the whole template: only the setting controlling where new clones' disks land got changed to a separate, otherwise-idle drive, while template reads stayed on the original storage — reads are cheap to share, writes aren't.
  3. Third recurrence, same day: a stale integration token stored in Kasm's own database, confirmed definitively via a direct API call comparison against a known-good token. Fixing this one is also where a real, separate mistake happened — see below.
The actual lesson from all three: never assume a recurring bug is the bug you already fixed. Same exact user-visible symptom, three unrelated root causes. Re-diagnose from scratch every time, especially on autoscaling/orchestration systems where "it destroys and retries" can mask almost any underlying failure equally well.

A real mistake made while fixing the third cause

Writing the new, valid token directly into Kasm's Postgres database via a plain SQL UPDATE seemed like the obvious fix. It wasn't — that column turned out to be encrypted at the application layer, not just at rest, and writing plaintext into it broke every future read silently. The visible result: an entire configuration section of the admin UI went empty, looking exactly like data had been deleted. It hadn't been — the row was just permanently unreadable without the app's own encryption key, which isn't something you can recover after the fact. Full generalizable writeup of this specific mistake (and how to avoid it) is its own guide: never write directly to an app-encrypted database column.

Recovery here used a same-morning backup restore — which then immediately surfaced a second, completely unrelated problem: the restored VM's disk filled up, crashing the app's own database, which the app's UI then reported as a licensing error. Nothing about licensing was actually wrong; the error message was just misleading about the real cause (a full disk). Worth remembering any time a self-hosted app reports something licensing- or auth-shaped: check basic resource health before trusting the app's own explanation of itself.

What was actually good about it

By the end, real autoscaling was working: agent VMs provisioned on demand, connected correctly, and got torn down cleanly when no longer needed. The core idea — browser-based virtual desktops with real elastic capacity instead of a fixed always-on pool — genuinely works once the integration points (the Proxmox token, the clone script's flags, storage placement) are all correct. None of the bugs above were fundamental to the platform; they were all integration-layer issues specific to wiring it into this particular Proxmox setup.

Why it got retired anyway

Not because of any of the above — everything listed here was fixed and working. The deployment was retired because Kasm ended up being adopted at work instead, making a second, separately-maintained homelab instance redundant rather than valuable. The VMs were stopped, not destroyed, and every piece of monitoring/ inventory was cleanly deregistered — a real "we could pick this back up quickly if we ever needed to, but we don't right now" retirement, not an abandonment born of frustration.

Verdict

Kasm Workspaces earned a genuinely positive verdict on its own technical merits — the autoscaling model works, and every bug hit along the way was an integration issue with this specific environment, not a flaw in the product itself. The real takeaway from this whole arc isn't about Kasm specifically: it's that a recurring bug with an identical symptom is not proof of an identical cause, and that "the fix" for one incident can introduce a completely separate, more subtle problem if you reach for a shortcut (raw SQL against a database you don't fully understand) instead of the tool actually designed for the job.