Skip to content

Create a Local VM on Linux (QEMU/libvirt) ​

On a Linux host you can run a meltcloud Nest or Machine as a local VM using QEMU/KVM, managed with libvirt.

VM Settings ​

SettingNestMachine
Architecturehost arch (amd64/arm64)host arch (amd64/arm64)
vCPU4+2+
RAM10 GiB+4 GiB+
Disk≥ 200 GiB≥ 30 GiB (depends on the amount of container images)
NetworkingDefault (NAT)Default (NAT)
Nested virtualizationnot requiredoptional, required for Elastic Node Pools
Boot mediaNest installer .isoEnrollment Image .iso

Prerequisites ​

Install packages ​

Install libvirt and qemu-system-x86 for your distro. The following installs it on Ubuntu 24.04+:

shell
sudo apt install qemu-system-x86 libvirt-daemon-system ovmf

Add your user to the libvirt group so you can manage VMs without root:

shell
sudo usermod -aG libvirt $USER

Log out and back in for the group change to take effect.

Start the default network ​

libvirt ships a default NAT network that provides DHCP and internet access. Make sure it is active:

shell
sudo virsh net-start default
sudo virsh net-autostart default

Copy the ISO ​

Create a directory for VM images and copy your .iso into it:

shell
# placed under /var/lib/libvirt so libvirt can traverse into it
sudo mkdir -p /var/lib/libvirt/melt-vms
sudo chown $USER:kvm /var/lib/libvirt/melt-vms

Copy the ISO you need: the Nest installer if you're setting up a Nest, or the Enrollment Image if you're enrolling a machine:

shell
cp /path/to/nest-installer-v*-amd64.iso /var/lib/libvirt/melt-vms/
shell
cp /path/to/enrollment-image-amd64.iso /var/lib/libvirt/melt-vms/

Create the VM ​

shell
VMDIR=/var/lib/libvirt/melt-vms
ISO_PATH=$VMDIR/nest-installer-v*-amd64.iso

# create the disk (adjust size as needed, minimum 200 GiB; qemu's G suffix = GiB)
qemu-img create -f qcow2 $VMDIR/melt-nest.qcow2 200G

# write the VM definition
cat > $VMDIR/melt-nest.xml << EOF
<domain type='kvm'>
  <name>melt-nest</name>
  <!-- RAM: 10 GiB minimum -->
  <memory unit='GiB'>10</memory>
  <!-- CPU: 4+ vCPUs recommended -->
  <vcpu>4</vcpu>
  <os firmware='efi'>
    <type arch='x86_64'>hvm</type>
    <boot dev='hd'/>
    <boot dev='cdrom'/>
  </os>
  <features>
    <acpi/>
  </features>
  <cpu mode='host-passthrough'/>
  <devices>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <!-- adjust path if you changed the qemu-img command above -->
      <source file='$VMDIR/melt-nest.qcow2'/>
      <target dev='vda' bus='virtio'/>
    </disk>
    <disk type='file' device='cdrom'>
      <source file='$ISO_PATH'/>
      <target dev='sda' bus='sata'/>
      <readonly/>
    </disk>
    <interface type='network'>
      <source network='default'/>
      <model type='virtio'/>
    </interface>
    <serial type='pty'>
      <target port='0'/>
    </serial>
    <console type='pty'>
      <target type='serial' port='0'/>
    </console>
  </devices>
</domain>
EOF

# define, start, and connect to the console
virsh define $VMDIR/melt-nest.xml
virsh start melt-nest --console
shell
VMDIR=/var/lib/libvirt/melt-vms
ISO_PATH=$VMDIR/enrollment-image-amd64.iso
# change the name to create multiple machines (e.g. worker1, worker2)
VM_NAME=worker1

# create the disk (adjust size as needed, minimum 30 GiB; qemu's G suffix = GiB)
qemu-img create -f qcow2 $VMDIR/$VM_NAME.qcow2 30G

# write the VM definition
cat > $VMDIR/$VM_NAME.xml << EOF
<domain type='kvm'>
  <name>$VM_NAME</name>
  <!-- RAM: 4 GiB minimum -->
  <memory unit='GiB'>8</memory>
  <!-- CPU: 2+ vCPUs -->
  <vcpu>2</vcpu>
  <os firmware='efi'>
    <type arch='x86_64'>hvm</type>
    <boot dev='hd'/>
    <boot dev='cdrom'/>
  </os>
  <features>
    <acpi/>
  </features>
  <cpu mode='host-passthrough'/>
  <devices>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <!-- adjust path if you changed the qemu-img command above -->
      <source file='$VMDIR/$VM_NAME.qcow2'/>
      <target dev='vda' bus='virtio'/>
    </disk>
    <disk type='file' device='cdrom'>
      <source file='$ISO_PATH'/>
      <target dev='sda' bus='sata'/>
      <readonly/>
    </disk>
    <interface type='network'>
      <source network='default'/>
      <model type='virtio'/>
    </interface>
    <serial type='pty'>
      <target port='0'/>
    </serial>
    <console type='pty'>
      <target type='serial' port='0'/>
    </console>
  </devices>
</domain>
EOF

# define, start, and connect to the console
virsh define $VMDIR/$VM_NAME.xml
virsh start $VM_NAME --console

Exit the console with Ctrl+5. To reconnect later:

shell
virsh console melt-nest

To clean up a VM:

shell
virsh destroy melt-nest
virsh undefine melt-nest --nvram

Next Steps ​

  • Nest: follow the on-screen TUI installer.
  • Machine: after it boots from the Enrollment Image it enrolls automatically and appears under Machines. Continue with Assign to a Machine Pool.

Troubleshoot ​

Nested virtualization not working ​

Nested virtualization is enabled by default on most recent Linux distributions. If it is not working, enable it manually:

shell
# Intel
echo "options kvm_intel nested=1" | sudo tee /etc/modprobe.d/kvm-nested.conf
sudo modprobe -r kvm_intel && sudo modprobe kvm_intel

# AMD
echo "options kvm_amd nested=1" | sudo tee /etc/modprobe.d/kvm-nested.conf
sudo modprobe -r kvm_amd && sudo modprobe kvm_amd

Verify with:

shell
cat /sys/module/kvm_intel/parameters/nested   # or kvm_amd

The VM must also use <cpu mode='host-passthrough'/> (already included in the XML definitions above).

Running on ARM (aarch64) hosts ​

This guide uses x86_64 examples, but ARM hosts work too. Adapt the following:

  • Install qemu-system-arm instead of qemu-system-x86, and qemu-efi-aarch64 instead of ovmf.
  • In the XML definitions, change <type arch='x86_64'>hvm</type> to <type arch='aarch64'>hvm</type>.
  • Use the arm64 variants of the installer and enrollment ISOs (e.g. nest-installer-v*-arm64.iso).

Other issues ​

If the VM has trouble booting or enrolling, check the Enrollment Images – Troubleshooting section.