Files
cloudhost/README.md
T
guofangandClaude Sonnet 5.5 fc8134ecf9 Use virtio-net and virtio-gpu on arm64 again
The base image now carries the VirtIO drivers, which restores the 2304x1440
display that ramfb had lost.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-02 22:09:07 +08:00

9.5 KiB

cloudhost

Start the required operating system with its distribution-specific launcher:

./run-debian13.py
./run-almalinux10.py
./run-fedora44.py
./run-ubuntu2604.py
./run-windows11.py

All virtual machines use OVMF/UEFI firmware. Each launcher creates a private, persistent OVMF_VARS_4M.fd variable store in the VM state directory.

Closing the QEMU window stops a foreground VM. To keep the launcher in the background while still showing the graphical window:

./run-debian13.py --daemon

The launcher uses KVM when /dev/kvm is accessible, forwards host port 2222 to guest port 22, and creates vm/debian13/disk.qcow2 as a 20G writable overlay with the original qcow2 image as its backing file. The base image therefore stays unchanged. Run ./run-debian13.py --help for the supported environment variables.

The Debian VM hardware (8G memory, 8 CPUs, drives) is defined in the QEMU config file qemu/debian13/config.ini; the machine type and architecture-specific devices are in qemu/debian13/<os>-<arch>.ini (os linux or darwin, arch amd64 or arm64), together with the accelerators. Edit these files to change the settings. The launcher fills in the ${...} file path placeholders of qemu/debian13/config.ini, writes the result to vm/debian13/qemu.ini and starts QEMU with -readconfig for that file followed by the one for the host system and guest architecture. QEMU arguments given after -- override the config files, for example ./run-debian13.py -- -m 4G -smp 4.

The launchers accept --state-dir DIR to keep the VM disk, seed ISO, UEFI variables, PID file and console log in DIR instead of the default vm/<name>/. The option takes precedence over the corresponding *_STATE_DIR environment variable:

./run-debian13.py --state-dir /srv/vms/debian13-test --daemon

With --download-only, a launcher only downloads the media it would fetch automatically and then exits without creating a VM disk or starting QEMU: the base image for Debian, AlmaLinux, Fedora and Ubuntu:

./run-fedora44.py --download-only

If vm/debian13/seed.iso is missing, the launcher automatically builds it from seediso/debian13/user-data, seediso/debian13/meta-data, and seediso/debian13/network-config before starting the VM.

Image download URLs and implementation are maintained in the vm-images submodule. Clone this repository with its submodules, or initialize it later:

git submodule update --init --recursive

The launchers prefer vm-images/download-images.sh when the submodule is initialized. Otherwise, they fall back to ../vm-images/download-images.sh for compatibility with the previous sibling-repository layout. Set VM_IMAGE_HELPER to use another helper path explicitly.

If the Debian base image is missing, the launcher calls the selected image helper with debian13.

AlmaLinux 10

Start an AlmaLinux 10 Generic Cloud VM with:

./run-almalinux10.py

When the shared AlmaLinux image is missing, the launcher calls the selected image helper with almalinux10. It creates the writable overlay vm/almalinux10/disk.qcow2 and uses the NoCloud configuration in seediso/almalinux10/. SSH is forwarded to host port 2223 by default:

ssh -p 2223 guofang@localhost

AlmaLinux settings use the ALMA_VM_ prefix. For example:

ALMA_VM_MEMORY=4G ALMA_VM_CPUS=4 ALMA_VM_SSH_PORT=2224 ./run-almalinux10.py

Run ./run-almalinux10.py --help for all supported settings. The seed ISO is stored alongside the VM disk at vm/almalinux10/seed.iso. If it already exists after editing its source files, rebuild it explicitly with ./seediso/almalinux10/build-seed.sh vm/almalinux10/seed.iso.

Fedora 44

Start a Fedora 44 Cloud Base VM with:

./run-fedora44.py

The launcher downloads the fedora44 image through the shared helper when it is missing, creates vm/fedora44/disk.qcow2, and builds its NoCloud seed from seediso/fedora44/. SSH is forwarded to host port 2224 by default:

ssh -p 2224 guofang@localhost

On the first boot, cloud-init updates package metadata and installs Fedora's GNOME package group through its native package module, then reboots the guest. Keep the VM running until this initial installation and reboot have completed.

Like the Debian VM, the Fedora VM hardware (8G memory, 8 CPUs, drives) is defined in qemu/fedora44/config.ini, with the accelerators, machine type and platform-specific devices in qemu/fedora44/<os>-<arch>.ini. Other Fedora settings use the FEDORA_VM_ prefix. Run ./run-fedora44.py --help for the complete list of overrides.

Ubuntu 26.04

Start an Ubuntu 26.04 LTS (Resolute Raccoon) cloud image VM with:

./run-ubuntu2604.py

The launcher downloads the ubuntu2604 image through the shared helper when it is missing, creates vm/ubuntu2604/disk.qcow2, and builds its NoCloud seed from seediso/ubuntu2604/. Like the Debian seed, it injects the current user's SSH public key and points APT at the USTC mirror (ubuntu-ports on arm64). SSH is forwarded to host port 2225 by default:

ssh -p 2225 guofang@localhost

On the first boot, cloud-init installs ubuntu-desktop-minimal (GNOME) and ibus-table-wubi, makes the graphical target the default and reboots the guest. Keep the VM running until this initial installation and reboot have completed.

The VM hardware (8G memory, 8 CPUs, drives) is defined in qemu/ubuntu2604/config.ini, with the accelerators, machine type and platform-specific devices in qemu/ubuntu2604/<os>-<arch>.ini. Other Ubuntu settings use the UBUNTU_VM_ prefix. Run ./run-ubuntu2604.py --help for the complete list of overrides.

Windows 11 23H2

On first boot, the Windows 11 launcher creates a writable system-disk overlay from the shared Windows 11 QCOW2 base image:

./run-windows11.py

It creates a persistent 64G disk at vm/windows11/disk.qcow2 as a QCOW2 overlay on the base image and nothing else: the launcher only creates the differential disk and starts QEMU. The base image is generic and holds nothing but Windows (see vm-images/README.md): no account, no SSH, no other hardware-specific drivers, no machine identity. Like a cloud image, each VM is configured on its first boot, from the seed ISO.

Whenever the disk does not exist yet, the launcher also mounts the seed ISO vm/windows11/seed.iso (beside the disk; built from seediso/windows11/ when missing or outdated, with the OpenSSH zip and the host's SSH public key, $SSH_PUBLIC_KEY_FILE or the first of ~/.ssh/id_ed25519.pub, id_ecdsa.pub, id_rsa.pub). Windows reads the Unattend.xml in the root of that CD-ROM during its specialize and OOBE passes: host name WIN11, time zone, Remote Desktop on 0.0.0.0:3389 (all host interfaces; connect to localhost:3389 on the host itself), the local administrator guofang (initial password wang; change it after first login) and automatic logon. At the first logon it runs Configure-Windows.ps1 from the seed ISO, which installs the OpenSSH Server from the zip with the SSH key (connect with ssh guofang@localhost -p 2222), turns off Windows Update and copies the numbered installer scripts (seediso/windows11/NN-*.bat and .ps1) to the desktop folder Tools. Later starts do not mount the seed ISO.

The base image carries the VirtIO drivers (build-windows-base.sh installs them from the virtio-win ISO before generalizing), so on arm64 the VM uses virtio-net and virtio-gpu (2304x1440 on macOS); amd64 uses an IDE disk and an e1000e NIC. The SPICE vdagent and QEMU Guest Agent come with the VirtIO guest tools, so host/guest clipboard integration and the guest agent are not available unless you install those tools in the VM yourself. The Windows VM hardware (8G memory, 8 CPUs, system disk, devices) is defined in qemu/windows11/config.ini, with the accelerators and machine type in qemu/windows11/<os>-<arch>.ini; the launcher renders the former to vm/windows11/qemu.ini and loads both with -readconfig. Only the network (see Port forwards) and the seed ISO are still set by the launcher. QEMU arguments after -- override the config files, for example ./run-windows11.py -- -m 4G -smp 4.

The launcher has no installation options and stops with a hint if the base image is missing. Make the base image once with vm-images/build-windows-base.sh, which is self-contained in vm-images/ (its own answer file, QEMU config and installation logic, written in bash): it installs Windows unattended from the ISO into a scratch disk, runs sysprep as its last step and stores the disk as the read-only base image. Override the base QCOW2, seed ISO, RDP port, or SSH port with the WIN11_VM_ environment variables shown by ./run-windows11.py --help.

Port forwards

The host ports forwarded to the guest are not in the QEMU config files (a config file section cannot hold more than one hostfwd) but in one file per VM, qemu/<vm>/forwards.conf, which the launcher turns into the -netdev argument. Each line is LABEL HOST_PORT GUEST_PORT; # starts a comment:

# qemu/windows11/forwards.conf
RDP  3389  3389
SSH  2222  22

Add a line to forward another port. A rule whose host port is already in use is skipped with a warning. ALMA_VM_FORWARDS, FEDORA_VM_FORWARDS, UBUNTU_VM_FORWARDS, VM_FORWARDS (Debian) and WIN11_VM_FORWARDS select another file. ALMA_VM_SSH_PORT, WIN11_VM_RDP_PORT, WIN11_VM_SSH_PORT and --rdp-port/--ssh-port still replace the host port of the rule with the label SSH or RDP. The launchers import vmforwards.py from the repository root.