7.3 KiB
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 — a0644base means vmd refuses every session with "freeze it and try again"; - the
.sha256must 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.
- Put
Win11_*.isoandvirtio-win.isoin the library. - Press Install from ISO on the Windows row. The console opens.
- Click through setup. Load the virtio storage driver from the second CD
(
amd64\w11) when the installer says it cannot find a disk. - When Windows is installed and logged in, press Shut down.
- Press Installed — remove disc.
- 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.