Import VM from OVA / OVF

Utilities~6 minView script

Imports an OVA / OVF package into Proxmox VE: extracts OVA archives, parses the OVF descriptor for vCPU / memory / NIC count and disk references, then creates the VM and imports each disk via qm importdisk to the chosen storage. Compatible with exports from VMware (ESXi / Workstation / Fusion), VirtualBox and ProxMenux itself.

What this does

Drops a complete VM into Proxmox from a portable package. After import, the VM is ready to start — but a few post-import touch-ups (NIC model, firmware, OS-type validation) are recommended for performance and compatibility.

File picker

On launch, the script offers two preset directories or a manual path:

  • /var/lib/vz/dump — the default Proxmox vzdump backup directory.
  • /var/lib/vz/template/iso — useful if you sftp'd the OVA there.
  • Manual path — for OVA / OVF files anywhere else on the host.

It then lists every .ova and .ovf file in the chosen directory.

Import VM file picker dialog

How the import works

OVA / OVF in
.ova → tar xf to /tmp/.proxmenux-import-* .ovf → use in place
Parse + dialogs
AWK reads OVF (name, vCPU, RAM, NICs, disks). User picks VMID / storage / bridge
qm create + importdisk
qm create $VMID qm importdisk (VMDK → qcow2) qm set --scsiN

OVF parsing

A gawk parser reads the OVF descriptor and pulls out the VM metadata. The parser uses the 3-argument form of match() which is gawk-specific (mawk — the default awk on Debian / Proxmox — does not support it). On the first import, the script auto-installs gawk via the canonical ensure_repositories + install_single_package pair if it's missing; subsequent imports start instantly. Fields extracted:

FieldSource in OVFDefault if missing
VM name<Name> (first match)imported-vm
vCPU countRASD ResourceType 3 → VirtualQuantity1
Memory (MiB)RASD ResourceType 4 → VirtualQuantity1024
NIC countcount of ResourceType 101
OS type/Linux/ or /Windows/ in descriptionother
Disk referenceshref attributes ending in .vmdk / .qcow2 / .img / .rawnone (import aborts)

Memory unit ambiguity

The parser assumes MiB. If the OVF declares memory in GB (e.g. some VMware exports do), the imported VM will have 1/1024th of the intended RAM. After import, double-check qm config $VMID | grep memory against the source VM's documented RAM and adjust with qm set $VMID --memory &lt;MiB&gt; if it's off by a factor of 1024 or 1024².

Import dialog flow

  1. VMID — defaults to the next available (pvesh get /cluster/nextid).
  2. VM name — defaults to the parsed OVF name; you can override.
  3. Target storage — menu of all storages with images content (from pvesm status -content images).
  4. Network bridge — menu of bridges (from ip link show type bridge); auto-picks if only one exists; defaults to vmbr0.
  5. Confirmation — summary dialog with VMID, name, vCPU, memory, NICs, storage, bridge and the list of disks to be imported. Cancel here = nothing changes.

VM creation

After confirmation, the script runs:

qm create $VMID \
    --name "$NAME" \
    --memory $MEMORY \
    --cores $VCPU \
    --ostype $OSTYPE \
    --scsihw lsi \
    --net0 e1000,bridge=$BRIDGE

# For each additional NIC:
qm set $VMID --netN e1000,bridge=$BRIDGE

SCSI controller defaults to lsi (LSI Logic) for VMDK compatibility. NICs default to e1000 (universal compatibility) on the chosen bridge.

Disk import loop

For each disk reference in the OVF:

  1. qm importdisk $VMID $disk_path $STORAGE — converts the VMDK to the storage-native format (e.g. qcow2 on local-lvm, raw on ZFS) and creates an unusedN: entry in the VM config.
  2. The script greps the config for the just-created unusedN reference.
  3. qm set $VMID --scsiN $unused_disk — attaches the disk as scsi0, scsi1, …
  4. qm set $VMID --delete unusedN — clears the now-redundant unused marker.

Boot is set to the first SCSI disk: qm set $VMID --boot c --bootdisk scsi0.

Recommended post-import touch-ups

The import deliberately uses lowest-common-denominator settings to maximise the chance the VM boots first try. Once you confirm it boots, switch to better defaults via the Proxmox UI or CLI:

SettingDefault after importRecommended (if guest supports)
NIC modele1000VirtIO (much faster, needs guest driver)
SCSI controllerLSIVirtIO SCSI single (modern Linux + Windows w/ VirtIO drivers)
Firmware (BIOS / UEFI)Proxmox default (BIOS)Match the source VM's firmware (mismatched = won't boot)
QEMU guest agentOffOn + install qemu-guest-agent in the guest (better backups, IP reporting)
OS typel26 / win10 / other (heuristic)Verify against the actual guest OS
DisplayDefaultVirtIO-GPU or SPICE (better console performance)

Firmware mismatch = no boot

If the source VM was UEFI but Proxmox creates it as BIOS (or vice-versa), the guest will not find a bootable disk. Check the OVF or the original VM's settings for FirmwareType / firmware and set the same in Proxmox: qm set $VMID --bios ovmf for UEFI; default is seabios for BIOS.

What is NOT imported

  • Specific NIC bridges — only the count. All NICs land on the bridge you picked at import time.
  • NIC model — defaults to e1000.
  • BIOS / UEFI firmware type — defaults to Proxmox default (BIOS).
  • PCI passthrough configuration.
  • TPM (vTPM).
  • Cloud-init drives.
  • Snapshots — only the current state.
  • USB / serial / parallel devices declared in the OVF.
  • VM tags / notes / start-on-boot options.

Troubleshooting

VM was created but disk import failed — orphan VM left behind

Known limitation. The script doesn't auto-clean a partial import. Destroy the orphan with:
qm destroy $VMID --destroy-unreferenced-disks 1
Then fix the underlying cause (likely disk space on the target storage) and re-import.

Imported VM has 8 MB of RAM (or 8 TB)

Memory unit ambiguity in the OVF parser. Off by a factor of 1024 → OVF used GB instead of MiB. Fix:
qm set $VMID --memory 8192    # 8 GiB

Imported VM doesn't boot — "No bootable device"

Most common cause: BIOS / UEFI mismatch. The VM was UEFI but Proxmox created it as BIOS. Set the matching firmware:
qm set $VMID --bios ovmf       # UEFI
# also add an EFI disk for the EFI vars:
qm set $VMID --efidisk0 $STORAGE:1,format=qcow2,efitype=4m,pre-enrolled-keys=1
Second-most-common: boot order points at scsi0 but the actual OS disk is scsi1. Edit the boot order in the VM Options tab.

VMware-exported Windows VM imports but BSODs on first boot

Windows is sensitive to disk controller changes. Either: (a) install VirtIO drivers before exporting from VMware, or (b) keep the SCSI controller as lsi (the default) and only switch to VirtIO SCSI after the guest boots and you can install the VirtIO drivers in Windows.

OVF parser reports 0 disks

The OVF descriptor uses an unusual disk reference style. Open the .ovf in a text editor and confirm each disk has a &lt;File ovf:href="...vmdk" ...&gt; entry. If the file extension is unusual (e.g. just .dat), rename it to .vmdk and update the OVF reference, then re-run.

awk: syntax error at or near , — parser fails on every OVA / OVF

The OVF parser uses gawk-specific syntax (3-argument match()) which mawk — the default awk on Debian / Proxmox — does not support. Recent versions of the script auto-install gawk on first use via the canonical ensure_repositories + install_single_package pair; if you're running an older copy, install it manually:
apt-get install -y gawk
Then re-run the import.

Network not working after first boot

The NIC model in Proxmox (e1000) may not match what the guest OS has drivers for, or the bridge you chose isn't the right one. From the VM's Hardware tab in Proxmox UI: change Network Device → Model. Also check ip a inside the guest — sometimes the interface comes up with a different name (eth0 vs ens18) and the guest's network config still references the old one.

Files involved

scripts/utilities/import_vm_ova_ovf.sh       # this script
/tmp/.proxmenux-import-*/                    # temp extraction dir for OVA
/etc/pve/nodes/<node>/qemu-server/<vmid>.conf  # created by qm create
<storage>/<vmid>/<vmid>-disk-<n>.<fmt>        # disk images, format depends on storage

Related