Migrating VirtualBox VMs to KVM/Proxmox VE: Converting VDI to QCOW2 and Fixing VirtIO Boot Errors

Virtualization tutorial - IT technology blog
Virtualization tutorial - IT technology blog

Comparing Migration Methods from VirtualBox to KVM/Proxmox

It’s 2:00 AM, and PagerDuty is sounding alarms. A temporary database running inside VirtualBox on a developer workstation has crashed due to a host power supply failure. Your mission: immediately migrate this entire 80GB virtual machine to a production Proxmox VE cluster. You have 3 technical approaches available:

  • Option 1: Export to OVA/OVF and re-import. VirtualBox bundles the complete VM into a compressed .ova archive. You then extract it on Proxmox to retrieve the disk image.
  • Option 2: Network disk cloning with Clonezilla or Veeam Agent. You attach rescue ISOs on both ends, open network ports, and stream data block-by-block.
  • Option 3: Direct disk conversion using qemu-img. Copy only the .vdi file, convert it directly to QCOW2 or RAW format, and attach it to a newly created VM.

Real-World Evaluation of Each Approach

During an active outage, every minute of downtime costs money. Here is a practical breakdown of how these methods compare:

1. Exporting OVA/OVF

  • Pros: Intuitive GUI-based workflow. The export preserves RAM allocation and vCPU core counts automatically.
  • Cons: Extremely slow. VirtualBox takes roughly 25 minutes to compress an 80GB virtual disk into an OVA file. On top of that, you spend another 15 minutes transferring the file over the network with rsync and untarring it. That totals nearly 45 minutes wasted purely on intermediate data handling.

2. Using Clonezilla or Network Agents

  • Pros: Eliminates concerns over virtualization disk format incompatibilities between Oracle and QEMU.
  • Cons: Tedious setup. You must configure static IPs on both endpoints within live ISO environments. If local network congestion occurs or the source machine disconnects halfway through, the entire transfer process must start over from scratch.

3. Direct Conversion with qemu-img

  • Pros: The fastest method. Converting an 80GB VDI file (holding 30GB of actual data) to QCOW2 takes only 3 to 5 minutes on an NVMe drive. The QCOW2 format natively supports fast snapshots and thin provisioning.
  • Cons: Only the virtual disk is preserved. Network interfaces, UEFI/SeaBIOS boot modes, and storage controllers must be configured manually in Proxmox.

Solution Choice: Why Prioritize qemu-img?

For urgent migration scenarios, direct disk conversion is always the shortest path. It cleanly detaches the guest from the legacy VirtualBox hypervisor layer, preventing legacy driver clutter from Oracle Guest Additions from leaking into the new host environment.

In my 3-node Ceph-backed Proxmox homelab, every import workflow from VMware or VirtualBox is standardized using qemu-img and qm importdisk. This approach is straightforward to script in Bash and gives you granular control over every hardware parameter.

Step-by-Step Implementation Guide

Step 1: Shut Down the VM and Transfer the VDI File to the Server

Perform a clean VM shutdown in VirtualBox using ACPI Shutdown or Power Off. Never use Save State, as frozen RAM states will compromise filesystem integrity.

Use rsync to transfer the VDI file to Proxmox. The --sparse flag is crucial here, as it skips empty blocks to save substantial network bandwidth:

rsync -avP --sparse /home/dev/VirtualBox\ VMs/app-db/app-db.vdi [email protected]:/var/lib/vz/dump/

Over a 1Gbps LAN, a VDI file containing 30GB of real data takes approximately 4 to 5 minutes to finish transferring.

Step 2: Convert VDI to QCOW2

SSH into your Proxmox node. First, inspect the source file structure:

qemu-img info /var/lib/vz/dump/app-db.vdi

Next, convert it to QCOW2. Note: do not use the -c (compression) flag for production disks, as compressed images degrade random I/O performance (random IOPS):

qemu-img convert -p -f vdi -O qcow2 /var/lib/vz/dump/app-db.vdi /var/lib/vz/images/app-db.qcow2

The -p flag displays a real-time progress bar, allowing you to monitor the completion status closely.

Step 3: Create the VM and Import the Disk in Proxmox

Create a new virtual machine (e.g., VM ID 105) via the Web UI or CLI. Match the resource specifications to the original system (4 vCPU, 8GB RAM). Delete the default virtual disk generated by the creation wizard.

Run the command to import the disk into your target storage pool (e.g., local-lvm):

# Import the disk into VM 105
qm importdisk 105 /var/lib/vz/images/app-db.qcow2 local-lvm

# Attach disk to SATA bus instead of VirtIO to prevent initial boot failures
qm set 105 --sata0 local-lvm:vm-105-disk-0
qm set 105 --boot order=sata0

Step 4: Resolve VirtIO Driver Issues (Preventing BSOD and Kernel Panics)

This is where 90% of engineers hit a roadblock during migrations. The original VirtualBox VM was configured to load standard SATA/IDE drivers. If you immediately attach the disk to a VirtIO SCSI controller, the operating system will fail to boot.

Windows will throw an INACCESSIBLE_BOOT_DEVICE Blue Screen of Death (BSOD). Linux will drop into a dracut Emergency Shell or panic with kernel panic: Unable to mount root fs because the initramfs image lacks VirtIO kernel modules.

Method 1: Resolving on Windows Server / Windows 10/11

  1. Keep the boot disk on the SATA (or IDE) bus. Windows ships with generic SATA storage drivers and will reach the desktop login screen normally.
  2. Download the official VirtIO ISO from Fedora/Red Hat (virtio-win.iso) and mount it to the VM’s virtual CD-ROM drive.
  3. Add a dummy 1GB secondary virtual disk attached to a VirtIO SCSI bus.
  4. Boot Windows. Open Device Manager, where you will see the SCSI Controller marked with a yellow warning triangle. Right-click it, select Update driver, and browse to the mounted VirtIO CD drive.
  5. Install the qemu-guest-agent package found on the ISO as well, allowing Proxmox to report guest IP addresses and handle graceful ACPI shutdowns.
  6. Shut down the VM, delete the temporary 1GB disk, and switch the primary drive from sata0 to scsi0 (VirtIO SCSI Single, enabling both Discard and SSD Emulation). Power the VM back on to enjoy native, high-performance I/O throughput.

Method 2: Resolving on Linux (Debian, Ubuntu, RHEL, Rocky)

Boot the Linux guest via the SATA bus. Log in as root and add the required VirtIO modules to the initramfs before swapping the storage controller.

On Ubuntu / Debian, append the required modules to the configuration file:

# Add VirtIO drivers to early boot loading list
cat <<EOF >> /etc/initramfs-tools/modules
virtio
virtio_ring
virtio_pci
virtio_scsi
virtio_blk
EOF

# Rebuild initramfs for all installed kernels
update-initramfs -u -k all

On RHEL / CentOS / Rocky Linux, use dracut to force-load the drivers:

dracut --force --add-drivers "virtio virtio_pci virtio_ring virtio_scsi virtio_blk" /boot/initramfs-$(uname -r).img $(uname -r)

Once the rebuild finishes, shut down the VM. In the Proxmox Hardware tab, detach the sata0 disk and re-attach it as scsi0 using the VirtIO SCSI Single controller. The VM will now boot seamlessly in seconds, delivering 3x to 4x higher storage throughput compared to the legacy SATA controller.

Share: