Files
2026-09-15 15:24:03 -04:00

7.3 KiB
Raw Permalink Blame History

Base images and installation media

Every session boots a throwaway overlay over a frozen base image. Nothing the agent installs survives. So there has to be a way to put software into the base, and it has to be a way the agent cannot reach.

That is the Tool Server VM Maintenance app, in your applications menu and on your desktop. It starts polkit-gated systemd units and touches nothing itself.

Frozen means the owner write bit

Not a flag, not a database — chmod u-w on the qcow2. Six places test it and they all test the same bit, so ls -l tells you the truth:

sudo stat -c '%n %a' /var/lib/owuivm/base/*.qcow2
# 444 = frozen

Consequences:

  • Frozen + Start boots a throwaway copy. This is exactly what the agent gets, and you can rehearse it with no risk of changing anything.
  • Unfrozen + Start boots the base itself, and changes are kept.
  • Nothing re-freezes automatically. What catches a forgotten thaw is that vmd refuses to open a session while a base is writable — the agent stops working rather than quietly writing to your original.
  • Freezing re-records the image's checksum, which retires any saved fast-start machine. The app shows that as stale; press Save fast start again.

The quick way: import a prebuilt image

Building takes an afternoon. Downloading a finished one takes a coffee, and for Windows it is the difference between clicking through an installer in a VNC console and not.

sudo ./vm/images/import.sh ubuntu      # ~9.6 GB
sudo ./vm/images/import.sh windows     # ~41 GB
sudo ./vm/images/import.sh both

They come from https://nextcloud.grantlan.com/s/OWUIToolsVMDisks, are checksum-verified against a manifest published beside them, and are installed frozen and owned correctly — which is the real reason this is a script rather than a list of curl commands. Three things have to be exactly right or it fails much later, in ways that do not point at their cause:

  • the owner must be owuivmadm, or the maintenance tool cannot thaw it;
  • the mode must be 0444, because frozen is the owner write bit and nothing else — a 0644 base means vmd refuses every session with "freeze it and try again";
  • the .sha256 must land beside the disk, or every saved fast-start machine is treated as stale and sessions silently boot from cold.

The download resumes: the server supports range requests, so ^C and re-run picks up where it stopped rather than starting the 41 GB again. It checks you have the space before it begins, and it refuses to overwrite a base image that is already frozen — a part-downloaded one is writable by definition, which is how it tells the two apart and why resuming works at all.

Hosting your own is one variable:

sudo OWUIVM_IMAGE_SOURCE=https://files.example.com/s/TOKEN ./vm/images/import.sh ubuntu

Any web server will do — the script only ever does a ranged GET and verifies what it gets.

What is in them

Ubuntu 26.04 desktop with the guest agent, static networking, a Chromium and Firefox to drive, and the first-boot noise (cloud-init, unattended upgrades, wait-online) turned off. Windows 11 with virtio drivers, the in-guest broker and an auto-logging-on local administrator.

Nothing personal is in either: they are installers run to completion and then frozen, with no accounts, keys or data beyond what the installer creates. The guest password is documented in vm/images/ubuntu/user-data and is not a secret — there is no network path to either machine.

On Windows licensing: the image contains an unactivated Windows 11. Whether you may run it, and for how long, is between you and Microsoft's terms — an unactivated install works with cosmetic nags, and an evaluation build expires. If that matters to you, build your own from media you are licensed for; the manual procedure is below and the result is identical.

Or build them yourself

Everything below produces the same thing from scratch, and is the right path if you want to change what is in the image.

Getting installation media

Two ways, and the app's way is easier.

From the app

On a machine with no disk yet, press Insert disc…, pick an .iso, and watch it copy. It is checked before it is accepted — a download that was really an HTML error page is rejected there and then, rather than becoming a machine that will not boot for no visible reason.

The copy happens as you, out of your own home directory, because the privileged units run with ProtectHome=yes and could not read ~/Downloads even if asked. It lands in a staging directory you own, and the unit only checks it and moves it.

From the command line

sudo ./vm/images/fetch.sh ubuntu     # downloads, verifies against Canonical's SHA256SUMS
sudo ./vm/images/fetch.sh virtio     # the virtio-win drivers, for Windows
sudo ./vm/images/fetch.sh windows /path/to/Win11.iso   # you supply this one

Media lives in /var/lib/owuivm/iso. Which file belongs to which machine is the iso glob in ../../configs/vms.toml — ubuntu*.iso and [Ww]in*.iso.

It is not *.iso, and that matters. The rule is "newest match wins", so with an Ubuntu disc sitting next to a Windows one, a *.iso pattern is how a Windows install quietly boots the Ubuntu installer.

Building Ubuntu

sudo ./vm/images/ubuntu/build.sh    # ~25 minutes, unattended

An autoinstall: it repacks the ISO with a seed, boots it headless, installs, adds the guest agent, sets static networking, then freezes the result and records its checksum.

It refuses to overwrite an existing base. Delete the old one first if you mean to rebuild.

Building Windows

No unattended path — it is driven by hand through the app.

  1. Put Win11_*.iso and virtio-win.iso in the library.
  2. Press Install from ISO on the Windows row. The console opens.
  3. Click through setup. Load the virtio storage driver from the second CD (amd64\w11) when the installer says it cannot find a disk.
  4. When Windows is installed and logged in, press Shut down.
  5. Press Installed — remove disc.
  6. Press Freeze.

Nothing on this host can work out for itself that an install has finished, and the one time something tried — treating a disk over 512 MB as done — it declared a half-finished install complete and left the machine at an EFI shell. So step 5 is a person saying so.

Making sessions start faster

Save fast start boots the image once and saves the running machine to disk. Sessions then resume from it: about 30 seconds instead of 90–115, and on Windows that includes PowerShell's cold start.

Requires the image to be frozen and shut down. A saved machine is tied by checksum to the exact image it came from, so changing the image retires it — which is correct, and is why the app tells you when it has gone stale rather than silently booting cold forever.

Renaming a machine

Rename changes what it is called in the app and in session reports. The id never changes: it names the disk, the systemd unit instance, the saved-machine directory, and the value the assistant passes as os, and it appears in regex allowlists inside the privileged launch scripts.

Renames are stored in /var/lib/owuivm/registry/vm-names.toml and merged over vms.toml, so the registry keeps its comments. Delete that file to go back to the shipped names.