Files
GuofangandClaude Sonnet 5.5 fd79eaa407 Add a Rocky Linux 9 virtual machine
run-rocky9.py with its QEMU config, port forwards (SSH on 2226) and
cloud-init seed, modelled on the Fedora 44 launcher. Update vm-images for
the rocky9 download target.

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

253 lines
10 KiB
Markdown

# cloudhost
Start the required operating system with its distribution-specific launcher:
```bash
./run-debian13.py
./run-almalinux10.py
./run-rocky9.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:
```bash
./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:
```bash
./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, Rocky Linux, Fedora and Ubuntu:
```bash
./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:
```bash
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:
```bash
./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:
```bash
ssh -p 2223 guofang@localhost
```
AlmaLinux settings use the `ALMA_VM_` prefix. For example:
```bash
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`.
## Rocky Linux 9
Start a Rocky Linux 9 GenericCloud Base VM with:
```bash
./run-rocky9.py
```
The launcher downloads the `rocky9` image through the shared helper when it
is missing, creates `vm/rocky9/disk.qcow2`, and builds its NoCloud seed from
`seediso/rocky9/`. SSH is forwarded to host port `2226` by default:
```bash
ssh -p 2226 guofang@localhost
```
Like the Debian and Fedora VMs, the Rocky Linux VM hardware (8G memory, 8 CPUs, drives) is
defined in `qemu/rocky9/config.ini`, with the accelerators, machine type and
platform-specific devices in `qemu/rocky9/<os>-<arch>.ini`. Other Rocky Linux settings use the `ROCKY_VM_` prefix.
Run `./run-rocky9.py --help` for the complete list of overrides.
## Fedora 44
Start a Fedora 44 Cloud Base VM with:
```bash
./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:
```bash
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:
```bash
./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:
```bash
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:
```bash
./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`, `ROCKY_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.