Skip to main content

KVM and libvirt

On a Linux host with KVM, libvirt runs the qcow2 image as an ordinary virtual machine. You copy the image to libvirt's image folder, give the machine your SSH key on a seed, and import the disk, either with virt-install from the command line or with virt-manager's Import existing disk image. UEFI, with or without Secure Boot, and BIOS both work.

Before you start​

  • A Linux host with KVM: /dev/kvm must exist. On Debian or Ubuntu, the packages are:

    sudo apt install qemu-system-x86 qemu-utils libvirt-daemon-system libvirt-clients virtinst ovmf xorriso
    sudo usermod -aG libvirt,kvm "$USER" # then sign out and in again
    ls -l /dev/kvm

    Add virt-manager for the graphical route.

  • Room for the machine: 2 vCPU, 4 GB of memory or more, and 40 GB or more of disk, as Hardware describes. virt-manager proposes 2 GB, which is too little.

  • A network the machine can reach the internet from: libvirt's default NAT network, or a bridge on your LAN.

  • Your SSH public key: the one line in the .pub file, such as ~/.ssh/id_ed25519.pub.

  • The file: the qcow2, antelao-ohm-<version>-amd64.qcow2.

Download​

Download the qcow2 from the table on the overview page, then check it before you import it. Run this in the folder you downloaded it to:

curl -fsSLO https://packages.antelao.io/raw/cosign.pub
sha256sum cosign.pub
curl -fsSLO https://images.antelao.io/ohm/stable/0.23.0/SHA256SUMS
curl -fsSLO https://images.antelao.io/ohm/stable/0.23.0/SHA256SUMS.sig
cosign verify-blob --key cosign.pub --signature SHA256SUMS.sig \
--insecure-ignore-tlog=true SHA256SUMS
sha256sum --check --ignore-missing SHA256SUMS

Verify the download says what must come out right. cosign 3 also prints a warning that --signature is deprecated, before Verified OK. The check still holds.

Give it your SSH key​

The machine reads your key from a seed: two small files, user-data and meta-data.

  1. Build seed.iso with the seed ISO builder on the overview page. Its What is on the disc shows the two files, if you would rather keep them as files: virt-install can make the seed itself from them.

  2. Or write the two files yourself. user-data:

    #cloud-config
    ssh_authorized_keys:
    - ssh-ed25519 AAAA... you@workstation

    and meta-data, which names the machine:

    instance-id: odoo-1-001
    local-hostname: odoo-1

    Then build the disc from them:

    xorriso -as genisoimage -output seed.iso -volid cidata -joliet -rock user-data meta-data

No seed? The machine's own screen shows the console address and a one-time sign-in code after the first boot.

Import​

Put the disk where libvirt can read it​

libvirt runs the machine as its own user, which cannot read your home folder. Copy the image, and the seed ISO, into /var/lib/libvirt/images. The first boot writes into the disk, so make one copy per machine and keep the download for the next one:

sudo cp antelao-ohm-<version>-amd64.qcow2 /var/lib/libvirt/images/odoo-1.qcow2
sudo cp seed.iso /var/lib/libvirt/images/odoo-1-seed.iso

A disk left in your home folder, or a disk backed by a file there, fails with Cannot access backing file ... Permission denied.

To give the machine more than 40 GB, grow the copy before its first start; the first boot uses the space:

sudo qemu-img resize /var/lib/libvirt/images/odoo-1.qcow2 100G

With virt-install​

UEFI, with the seed made by virt-install from your two files:

sudo virt-install --name odoo-1 --memory 4096 --vcpus 2 --osinfo debian13 --import \
--disk /var/lib/libvirt/images/odoo-1.qcow2,bus=virtio \
--cloud-init user-data=user-data,meta-data=meta-data \
--network network=default,model=virtio \
--boot uefi --noautoconsole

--boot uefi picks firmware with Secure Boot on and Microsoft's keys enrolled where your OVMF package offers it. The image boots under Secure Boot.

BIOS, with the seed ISO as a CD-ROM:

sudo virt-install --name odoo-1 --memory 4096 --vcpus 2 --osinfo debian13 --import \
--disk /var/lib/libvirt/images/odoo-1.qcow2,bus=virtio \
--disk /var/lib/libvirt/images/odoo-1-seed.iso,device=cdrom \
--network network=default,model=virtio --noautoconsole

virt-install answers Domain is still running. Installation may be in progress. That is expected with --import; there is nothing to wait for.

With virt-manager​

virt-manager has no field for a key on an imported disk, so the seed ISO goes in as a CD-ROM.

  1. File > New Virtual Machine. Choose Import existing disk image and click Forward.

  2. Browse to the images pool, /var/lib/libvirt/images, select odoo-1.qcow2 and click Choose Volume. Under Choose the operating system, type debian 13 and pick Debian 13. Forward.

  3. Memory: 4096 or more. virt-manager proposes 2048. CPUs: 2. Forward.

  4. Name the machine, tick Customize configuration before install, and choose the network under Network selection, such as Virtual network 'default' : NAT. Finish.

  5. In the configuration window, Overview > Firmware: UEFI, or BIOS. Both boot. Click Apply.

  6. Add Hardware > Storage: choose Select or create custom storage, enter /var/lib/libvirt/images/odoo-1-seed.iso, and set Device type to CDROM device. The bus becomes SATA. Finish.

  7. Boot Options: leave only VirtIO Disk 1 ticked. The seed is a data disc and does not need to boot.

  8. Click Begin Installation. The machine's console window opens.

Start it and wait for the first boot​

The machine starts as soon as virt-install or Begin Installation creates it. Find its address:

sudo virsh domifaddr odoo-1

The console shows boot messages, then a login prompt. The login prompt appearing does not mean the work is done. The first boot installs the server in the background, which takes about 4 minutes, longer on a slow connection or slow disks. Sign in over SSH meanwhile and the login message says how far it is.

During and after the first boot the console fills with kernel messages, such as Failed to query local AF_VSOCK CID and lines about veth and bridge ports, and they print over the login prompt. Nothing is wrong: press Enter for a fresh login: line.

Reach the console​

Sign in over SSH as debian with your key, using the address virsh domifaddr showed:

ssh debian@192.0.2.173

The login message is shown when you sign in over SSH, not on the machine's screen. Once the first boot is done, it shows the console's address. Read the administrator's first password:

sudo cat /root/antelao-ohm-handoff.json

Then open the console through an SSH tunnel from the computer that runs your browser, which opens no port on the machine:

ssh -N -L 5322:127.0.0.1:5322 debian@192.0.2.173

Browse to https://localhost:5322/ and accept the self-signed certificate once. On libvirt's default NAT network the machine is reachable from the host only, so run the tunnel there, or put the machine on a bridge to your LAN. From here, carry on with the installation page:

  1. Check the server
  2. Reach the console
  3. Sign in and finish the setup
  4. Create your first instance

Platform notes and troubleshooting​

  • Cannot access backing file ... Permission denied. The disk, or the file it is backed by, is in a home folder. Copy the image into /var/lib/libvirt/images, as above.
  • SSH refuses the key. Sign in as debian, and check that user-data starts with #cloud-config and holds the public key, on one line. The seed is read at the first boot only, so make a fresh copy of the image and create the machine again.
  • Nothing reaches the server from outside. Ports 80 and 443 must reach the machine before Let's Encrypt can issue certificates for your instances. Keep the console's port 5322 closed.
  • The first boot failed. The login message says FAILED with the reason. See What the first boot does for how to run it again.