Máquinas virtuales KVM a fondo

Por: Artiko
proxmoxproxmox-vekvmqemuvirtiocpupassthroughqmvirtualizacion

Máquinas virtuales KVM a fondo

Creas una VM por la interfaz web, todo funciona, y decides automatizar el proceso con un script que llama a qm create con las mismas opciones que rellenaste en el wizard. La VM que sale del script es más lenta, no admite IO threads y su CPU no soporta las instrucciones que espera la distribución. No has hecho nada mal: el backend de Proxmox VE y la interfaz web no tienen los mismos valores por defecto, y esa divergencia es la primera fuente de sorpresas cuando pasas del clic al comando.

En el capítulo 2 viste que qm no es más que un cliente de la misma API REST que usa la GUI, y que la configuración de cada VM vive en /etc/pve/qemu-server/<VMID>.conf dentro de pmxcfs. Este capítulo abre ese fichero y explica qué significa cada clave: por qué scsihw decide si puedes usar iothread, por qué memory es el máximo y no el mínimo, por qué boot: order= puede dejar una VM sin arrancar tras añadir un disco, y qué hay que tocar en el host para que un dispositivo PCIe llegue entero a un huésped.

Al terminar tendrás un modelo mental completo del hardware virtual de QEMU en Proxmox VE 9.2 (QEMU 11.0 sobre Debian 13 Trixie, kernel 7.0), sabrás traducir cualquier pantalla del wizard a su opción de CLI exacta, y tendrás un método de diagnóstico que empieza y casi siempre termina con qm showcmd --pretty.

Dispositivos emulados frente a paravirtualizados: por qué virtio

QEMU corre en el host como proceso root, porque necesita acceso directo a dispositivos de bloque y PCI. Ese proceso presenta al huésped un conjunto de hardware que puede ser de dos naturalezas.

Los dispositivos emulados reproducen hardware real byte a byte: un controlador IDE, un SATA, un LSI 53C895A, una NIC Intel e1000. Cualquier sistema operativo los reconoce sin drivers adicionales porque lleva décadas soportándolos, pero cada operación de IO se traduce en un ida y vuelta caro entre el huésped y el emulador.

Los dispositivos paravirtualizados (virtio) rompen la ilusión a propósito: el huésped sabe que está virtualizado y coopera con el hipervisor mediante colas compartidas en memoria. Necesita un driver, que en Linux viene en el kernel desde hace años y en Windows hay que instalar a mano (eso es el capítulo 4).

La documentación oficial cuantifica la diferencia sin adornos: usar el controlador de disco genérico virtio en lugar de un IDE emulado duplica el throughput secuencial de escritura medido con bonnie++(8), y la interfaz de red virtio puede dar hasta tres veces el throughput de una e1000 emulada medido con iperf(1). La regla práctica es corta: virtio siempre que el huésped lo soporte, emulación solo como plan B para sistemas antiguos o para el arranque de un instalador que todavía no tiene el driver cargado.

El wizard Create VM tab por tab y su equivalente exacto en CLI

El endpoint es POST /nodes/{node}/qemu y qm create <vmid> [OPTIONS] es un envoltorio sobre él. qm set <vmid> [OPTIONS] es la versión síncrona de PUT /nodes/{node}/qemu/{vmid}/config; la propia man page advierte que para acciones que impliquen hotplug o asignación de almacenamiento conviene usar el método POST.

Tab General

Campo GUIClave en la configOpción CLIDefault
Nodenodo destinonodo actual
VM IDnombre del fichero<vmid> posicionalsiguiente libre
Namename--name
Resource PoolACL--pool
Start at bootonboot--onboot0
Start/Shutdown orderstartup--startup order=N,up=S,down=S

Los VMID menores de 100 están reservados para uso interno. El rango válido del API es 100 a 999999999 y el VMID debe ser único a nivel de cluster, no de nodo: es el nombre del fichero dentro de pmxcfs, que se replica a todos los miembros.

Tab OS

El ISO se adjunta como ide2: <storage>:iso/<fichero>,media=cdrom (cdrom es alias de ide2). El campo importante es ostype, cuyo default es other y cuyos valores válidos son l24, l26, other, solaris, w2k, w2k3, w2k8, win10, win11, win7, win8, wvista y wxp.

ostype no es cosmético. Determina cuatro comportamientos reales: uno, activa localtime en Windows, porque su RTC va en hora local y el de Unix en UTC; dos, fija el citype por defecto de cloud-init (nocloud en Linux, configdrive2 en Windows); tres, fija (pin) la machine version en la creación para huéspedes Windows; cuatro, habilita los flags de hotplug USB con ostype l26 o Windows posterior a 7.

Tab System y las dos divergencias que rompen scripts

Campo GUIClaveDefault del backendLo que pone la GUI
Graphic cardvgastdstd, cirrus en Windows XP y anteriores
Machinemachinepcpc en Linux, q35 en Windows 11
Firmware / BIOSbiosseabiosseabios, obligado ovmf en Windows 11
SCSI Controllerscsihwlsivirtio-scsi-single
Qemu Agentagentenabled=0desmarcado
CPU typecpukvm64x86-64-v2-AES

Advertencia: estas dos últimas filas son la causa número uno de VMs creadas por CLI que rinden peor que sus gemelas creadas por GUI. Si llamas a qm create sin --scsihw, obtienes un LSI 53C895A emulado y no podrás activar iothread en discos SCSI. Si llamas sin --cpu, obtienes kvm64, que es el nivel x86-64-v1 y con el que varias distribuciones modernas ni siquiera arrancan.

La cita oficial lo dice tal cual: el default del backend es kvm64, que funciona en esencialmente cualquier CPU host x86-64, y el default de la interfaz al crear una VM nueva es x86-64-v2-AES, que requiere una CPU host a partir de Westmere en Intel o de la cuarta generación de Opteron en AMD.

flowchart TD
    A["Elegir ostype"] --> B{"Windows 11 / 2022 / 2025"}
    B -->|"Si"| C["machine q35 + bios ovmf"]
    B -->|"No"| D["machine pc + bios seabios"]
    C --> E["efidisk0 con efitype 4m y pre-enrolled-keys 1"]
    E --> F["tpmstate0 version v2.0"]
    F --> G["scsihw virtio-scsi-single"]
    D --> G
    G --> H["scsi0 con cache discard ssd iothread"]
    H --> I{"Cluster homogeneo"}
    I -->|"Si"| J["cpu host"]
    I -->|"No"| K["cpu x86-64-v2-AES o el minimo comun"]
    J --> L["memory mas balloon"]
    K --> L
    L --> M["net0 virtio bridge vmbr0"]
    M --> N["boot order scsi0"]
    N --> O["agent enabled 1"]
    O --> P{"Cloud-init"}
    P -->|"Si"| Q["ide2 cloudinit mas serial0 socket mas vga serial0"]
    P -->|"No"| R["ide2 con el ISO de instalacion"]
    Q --> S["qm template"]
    R --> T["Instalar el SO y los drivers virtio"]

La rama de la derecha, con qm template y cloud-init, es el capítulo 5. Aquí nos quedamos con la construcción manual.

Machine type: i440fx, q35 y virt

El machine type es la placa base virtual. Proxmox VE ofrece dos en x86 y una en arm64.

pc (Intel 440FX)q35 (Intel 82Q35)virt (arm64)
Año de diseño19962007genérico UEFI
Bus PCIe virtualNo, solo PCI
PCI passthrough
PCIe passthroughNo
vIOMMU IntelNoRequerido
legacy-igdRequerido (pc-i440fx)No soportado
Disponible enx86x86solo arm64

La cita del capítulo de passthrough matiza algo que se malinterpreta a menudo: el passthrough PCI está disponible en i440fx y q35, pero el passthrough PCIe solo en q35. Eso no significa que un dispositivo PCIe pasado como PCI funcione a velocidades PCI; pasarlo como PCIe simplemente activa un flag para el huésped, y algunas aplicaciones del huésped se benefician de él. La sintaxis completa de la clave admite más que el tipo:

machine: [[type=]<machine type>] [,aw-bits=<number>] [,enable-s3=<1|0>] [,enable-s4=<1|0>] [,viommu=<intel|virtio>]
  • aw-bits (32-64) fija el ancho del espacio de direcciones del vIOMMU. El vIOMMU Intel admite 39 o 48 bits; el VirtIO cualquier valor entre 32 y 64.
  • enable-s3 y enable-s4 controlan los estados de suspensión ACPI. Desde los machine types 9.2+pve1 ambos son false por defecto; en versiones anteriores eran true.
  • viommu acepta intel (que exige q35) o virtio.

Versionado +pveX y política de deprecación

Cada machine type está versionado en QEMU (pc-q35-11.0) y Proxmox añade una revisión downstream +pveX, donde X vale 0 y se omite en la primera revisión de cada versión de QEMU. Es decir, pc-q35-9.2 es exactamente pc-q35-9.2+pve0.

El comportamiento por sistema operativo es distinto y conviene tenerlo claro:

  • Windows: la machine version se fija en la creación, porque Windows es sensible a cambios de hardware virtual incluso entre arranques en frío. Cambiarla altera, por ejemplo, la enumeración de NICs y la máquina pierde la configuración de red.
  • Linux y el resto: se usa Latest, con lo que tras un arranque en frío se emplea la última versión soportada por el binario QEMU instalado.
  • La live migration y los snapshots con RAM conservan la machine version original, que queda registrada en la clave runningmachine de la configuración.

Gotcha: desde QEMU 10.1, las machine versions se eliminan de upstream a los seis años. En Proxmox VE las releases mayores salen aproximadamente cada dos años, de modo que una release mayor soporta las machine versions de unas dos releases mayores anteriores. En números: PVE 8 no aplicaba la política y su baseline era la machine version 2.4; el baseline de PVE 9 es la 6.0 (el último binario esperado en la serie es QEMU 11.2, que retira todo lo anterior a 6.0), y el baseline previsto de PVE 10 es 8.0.

El procedimiento oficial para subir la machine version de una VM es: backup funcional, cambio en Hardware → Machine o qm set <vmid> --machine pc-q35-11.0, y preparación para reinstalar drivers en algunos escenarios. El punto delicado son los snapshots con RAM tomados con versiones antiguas: no hay forma de cambiar la machine version de un snapshot, hay que cargarlo para rescatar los datos.

Bug conocido de 9.2 (Bugzilla #7825): las VMs Windows 11, 2022 y 2025 con cpu: host y Virtualization-Based Security activada pueden congelarse de forma intermitente en hosts Intel, mostrando 100% de CPU en el resumen. El fix llegó en qemu-server 9.2.0 con la machine version 11.0+pve2. Las VMs con machine 11.0 o 11.0+pve1 están potencialmente afectadas y hay que subirlas a 11.0+pve2 o superior; las anteriores a 11.0 no lo están si el paquete qemu-server es 9.2.0 o posterior.

Firmware: SeaBIOS, OVMF, EFI disk, Secure Boot y TPM

bios: <ovmf | seabios>    # default seabios

SeaBIOS es el default, existe solo en x86 y es la elección correcta para la mayoría de instalaciones estándar. OVMF es la implementación UEFI, es obligatoria para Windows 11, recomendada para GPU passthrough y la única opción en arm64, donde la build ARM se llama AAVMF y bios=seabios sencillamente no existe.

Los tres escenarios donde OVMF deja de ser opcional son Windows 11, el passthrough de GPU y los discos de arranque de más de 2 TB con tabla GPT.

Hay dos cuidados propios de OVMF que cuestan tiempo la primera vez. Uno. Sin un display “correcto”, la consola sale con una resolución mínima; se corrige fijando la resolución en el menú OVMF (tecla ESC durante el arranque) o usando SPICE como display type. Dos. El arranque PXE con OVMF requiere un dispositivo RNG: el firmware deshabilita PXE en huéspedes sin generador de números aleatorios por razones de seguridad, y se soluciona con qm set <vmid> -rng0 source=/dev/urandom.

El EFI disk

Con OVMF hace falta un disco EFI donde persistir el boot order y las variables EFI. Se incluye en backups y snapshots, y solo puede haber uno.

qm set 210 -efidisk0 local-lvm:1,efitype=4m,pre-enrolled-keys=1
Sub-opciónValoresDefaultNotas
efitype2m | 4m2m en el API, 4m en la GUISolo 4m soporta Secure Boot y tiene más espacio. Ignorado con arch=aarch64
pre-enrolled-keys0 | 10Precarga claves de distribuciones y de Microsoft Standard Secure Boot, y deja Secure Boot activo por defecto
formatcloop|qcow|qcow2|qed|raw|vmdksegún el storage
ms-cert2011 | 2023 | 2023k | 2023w2011Marcador informativo del set de certificados enrolados
sizeDiskSizePuramente informativo, sin efecto

Advertencia: si quieres Secure Boot en una VM que ya tiene un efidisk 2m, no se puede convertir. Hay que borrarlo y recrearlo, lo que resetea toda la configuración del menú OVMF, incluido el boot order guardado:

qm set 210 -delete efidisk0
qm set 210 -efidisk0 local-lvm:1,efitype=4m,pre-enrolled-keys=1

El set original de certificados de Microsoft de 2011, que usan Windows y las distribuciones Linux habituales para Secure Boot, expira en junio de 2026. Un disco EFI que solo tenga los de 2011 rechazará bootloaders firmados con los de 2023. El marcador ms-cert=2023k indica que están enrolados los tres nuevos: Microsoft UEFI CA 2023, Windows UEFI CA 2023 y Microsoft Corporation KEK 2K CA 2023. Con pve-edk2-firmware 4.2025.05-1 o superior, los discos EFI nuevos ya llevan 2011 y 2023 y aparecen con ms-cert=2023k. El comando de reenrolamiento, con la VM apagada, es:

qm enroll-efi-keys 210

El detalle de este procedimiento y su interacción con BitLocker está en el capítulo 4, porque afecta sobre todo a huéspedes Windows.

El TPM emulado

qm set 210 -tpmstate0 local-lvm:1,version=v2.0

version admite v1.2, que es el default del API, o v2.0, que es el que exige Windows 11. No se puede cambiar después de creado, solo eliminar y recrear. Se implementa con swtpm y, desde PVE 9.1, admite formato qcow2 con snapshots en storages dir, NFS y CIFS; desde 9.2, estado TPM sobre iSCSI y ZFS-over-iSCSI. La documentación es explícita sobre lo que no aporta: comparado con un TPM físico, uno emulado no proporciona ningún beneficio real de seguridad, porque el estado se guarda en un volumen normal que puede editar cualquiera con acceso a él.

CPU: sockets, cores y modelos x86-64

ClaveRangoDefaultSignificado
sockets1-N1Sockets virtuales
cores1-N1Cores por socket
vcpus1-N0vCPUs enchufadas al arranque
smp1Deprecado, usa sockets y cores

El total de vCPUs es sockets * cores. En rendimiento da igual 1 socket con 4 cores que 2 sockets con 2 cores; la topología importa para licencias de software que se cobra por socket. Es perfectamente seguro que la suma de cores de todas las VMs supere los cores físicos del servidor, pero Proxmox impedirá arrancar una VM con más cores virtuales de los que hay físicamente disponibles. Si no sabes qué carga vas a tener, la recomendación de la documentación es empezar con 2 cores en total.

La sintaxis completa de la clave cpu:

cpu: [[cputype=]<string>] [,flags=<+FLAG[;-FLAG...]>] [,guest-phys-bits=<integer>]
     [,hidden=<1|0>] [,hv-vendor-id=<vendor-id>] [,level=<integer>]
     [,phys-bits=<8-64|host>] [,reported-model=<enum>]

Los niveles x86-64 que hay que conocer, definidos por AMD, Intel, Red Hat y SUSE en 2020:

ModeloCompatible desdeFlags añadidos sobre el nivel anterior
kvm64 (x86-64-v1)Intel Pentium 4, AMD Phenombaseline
x86-64-v2Intel Nehalem, AMD Opteron_G3+cx16 +lahf-lm +popcnt +pni +sse4.1 +sse4.2 +ssse3
x86-64-v2-AESIntel Westmere, AMD Opteron_G4+aes
x86-64-v3Intel Haswell, AMD EPYC+avx +avx2 +bmi1 +bmi2 +f16c +fma +movbe +xsave
x86-64-v4Intel Skylake, AMD EPYC v4 Genoa+avx512f +avx512bw +avx512cd +avx512dq +avx512vl
hostla CPU física del hosttodos los del host, máximo rendimiento y sin garantía de migración

Gotcha: CentOS 9 y varias distribuciones modernas ya se compilan exigiendo x86-64-v2 como mínimo, así que una VM creada por CLI sin --cpu (es decir, con kvm64) puede fallar directamente al arrancar. En arm64 estos modelos no existen: se usa host (recomendado) o max con machine type virt.

La regla de decisión para migrar

La documentación reduce la elección a tres casos:

Uno. Si no te importa la live migration, o tu cluster es homogéneo (misma CPU y mismo microcódigo), usa host. Dos. Si te importan la migración y la seguridad, y tienes solo Intel o solo AMD, usa el modelo de la generación más baja presente en el cluster. Tres. Si te importa la migración pero no la seguridad, o el cluster es mixto Intel/AMD, usa el tipo virtual QEMU compatible más bajo.

La nota oficial es tajante: las live migrations entre CPUs host Intel y AMD no tienen garantía de funcionar. Todo lo relativo a migración y cluster se desarrolla en el capítulo 11.

Flags de CPU, mitigaciones y modelos personalizados

Por seguridad, la lista de flags que se pueden añadir por VM es cerrada:

aes, amd-no-ssb, amd-ssbd, hv-evmcs, hv-tlbflush, ibpb, md-clear,
nested-virt, pcid, pdpe1gb, spec-ctrl, ssbd, virt-ssbd

nested-virt es un atajo especial que activa la virtualización anidada según el fabricante (svm en AMD, vmx en Intel). Se introdujo en PVE 9.1 como alternativa a tener que poner cputype=host solo para eso.

Para comprobar el estado de las mitigaciones del host:

for f in /sys/devices/system/cpu/vulnerabilities/*; do echo "${f##*/} -" $(cat "$f"); done
grep ' pcid ' /proc/cpuinfo

En Intel: pcid reduce el coste de KPTI (mitigación de Meltdown, CVE-2017-5754); spec-ctrl cubre Spectre v1 y v2 y viene incluido en los modelos con sufijo -IBRS, con intel-microcode 20180425 o superior; ssbd cubre Spectre v4 y no está incluido por defecto en ningún modelo Intel, requiere intel-microcode 20180703. En AMD: ibpb cubre Spectre v1 y v2 y viene en los modelos con sufijo -IBPB; virt-ssbd cubre Spectre v4 y debe activarse explícitamente incluso con cpu=host, porque es una feature virtual que no existe en la CPU física; amd-ssbd hace lo mismo con mejor rendimiento y conviene exponer ambos; amd-no-ssb indica que el host no es vulnerable y es mutuamente excluyente con los dos anteriores.

Otras sub-opciones de cpu que resuelven problemas concretos: level fija el máximo CPUID leaf visible y level=30 es el workaround conocido para fallos de arranque de Hyper-V en huéspedes Windows sobre hosts Intel recientes con cpu=host o max; hidden=1 evita identificarse como KVM ante el huésped; hv-vendor-id fija el Hyper-V vendor ID que algunos drivers de Windows exigen; y phys-bits=host reporta los bits de dirección física reales del host y rompe la live migration hacia CPUs con otros valores.

Los modelos personalizados viven en /etc/pve/virtual-guest/cpu-models.conf (hay man page: man cpu-models.conf) y se referencian como cputype=custom-<nombre>. Novedad de 9.2: se gestionan desde la GUI en Datacenter -> Custom CPU Models, con editor de flags, selector de acelerador kvm o tcg y un multi-select por nodo que resalta qué flags reporta cada miembro del cluster. Los permisos van por la ruta ACL /mapping/cpu/<nombre>: Mapping.Audit para verlo en listados, Mapping.Modify para crear o borrar y Mapping.Use para asignarlo a una VM, privilegio que también se exige al clonar una VM que lo use.

Límites de CPU: cpulimit, cpuunits, affinity y NUMA

cpulimit (0-128, default 0 = sin límite) expresa tiempo total de CPU del host como número flotante: 1.0 es el 100% de un core y 4.0 el 400%. En el ejemplo de la documentación, una VM con 8 vCPUs y cpulimit 4.0 que use las ocho al máximo le da un 50% a cada una; si solo usa cuatro, cada una puede llegar al 100%. Ten en cuenta que una VM consume más CPU que la de sus vCPUs por los hilos de red, IO y migración: para acotar de verdad, pon cpulimit igual al número total de cores. Equivale a CPUQuota de systemd.

cpuunits (1-262144) es el peso relativo del scheduler: una VM con 200 recibe el doble de ancho de banda que una con 100. Su default es 100 con cgroup v2, que es lo que usa Proxmox VE 9, y era 1024 en el cgroup v1 legacy. Equivale a CPUWeight de systemd.

affinity usa el formato taskset de man cpuset:

affinity: 0-1,8-11

Se expande a los cores 0, 1, 8, 9, 10 y 11 del host según la numeración de lscpu. Solo afecta a los hilos de vCPU, no a los procesos periféricos de IO y red, y no es una medida de seguridad: no aísla nada, solo reparte.

NUMA. Para saber si el host lo es:

numactl --hardware | grep available

Si devuelve más de un nodo, conviene activar numa: 1 y hacer coincidir el número de sockets virtuales con el número de nodos NUMA del host. Además, numa: 1 es requisito para el hot-plug de cores y de RAM.

Memoria, ballooning, shares y hugepages

Esta es la parte donde el mapeo entre la GUI y la configuración confunde más:

memory: [current=]<integer>    # 16-N, default 512 MiB — es el MAXIMO
balloon: <integer>             # 0-N, RAM objetivo en MiB — es el MINIMO garantizado
shares:  <integer>             # 0-50000, default 1000

El campo “Memory (MiB)” de la GUI es memory y actúa como máximo; el campo “Minimum memory (MiB)” es balloon y actúa como mínimo garantizado; desmarcar “Ballooning Device” equivale a balloon: 0. Con asignación fija (máximo y mínimo iguales) el dispositivo balloon se añade igual, porque aporta información útil sobre cuánta memoria usa realmente el huésped. Para quitarlo del todo hay que poner balloon: 0.

Con asignación automática, el que trabaja es pvestatd: garantiza el mínimo y añade memoria dinámicamente hasta el máximo mientras el uso de RAM del host esté por debajo de un porcentaje objetivo, que por defecto es el 80% de la RAM del host y se ajusta por nodo:

pvenode config set --ballooning-target 90

shares reparte la memoria sobrante entre las VMs que la piden. El ejemplo literal de la documentación: cuatro VMs (tres HTTP y una base de datos), host de 32 GB usando 16 GB, objetivo 80%. La RAM repartible es 32 * 80/100 - 16 = 9 GB. Con la base de datos en shares=3000 y las otras tres en el default 1000, la base de datos recibe 9 * 3000 / 6000 = 4.5 GB extra y cada HTTP recibe 1.5 GB. shares: 0 desactiva el auto-ballooning para esa VM.

flowchart LR
    MAX["memory<br/>maximo asignable"] --> PVS["pvestatd evalua el uso<br/>de RAM del host"]
    MIN["balloon<br/>minimo garantizado"] --> PVS
    SH["shares<br/>peso relativo por defecto 1000"] --> PVS
    PVS --> T{"Uso del host<br/>por debajo del 80 por ciento"}
    T -->|"Si"| INF["Infla hacia memory<br/>repartiendo por shares"]
    T -->|"No"| DEF["Desinfla hasta balloon<br/>nunca por debajo"]
    INF --> LIM["shares 0 desactiva el reparto"]
    DEF --> LIM

Notas prácticas que evitan sorpresas:

  • Todas las distribuciones Linux posteriores a 2010 traen el driver balloon en el kernel. En Windows hay que instalarlo desde el ISO virtio-win y registrar el servicio con BLNSVR.exe -i; desde Windows Server 2012 y 8.1 el instalador virtio-win-gt-x64.msi lo hace solo.
  • La documentación no recomienda ballooning en sistemas Windows críticos.
  • Deja siempre 1 GB de RAM libre al host.
  • El ballooning no funciona si la VM tiene passthrough PCI(e) o un mediated device. No es un fallo, es una consecuencia de que la memoria del huésped tiene que estar fijada para el DMA del dispositivo.

Para cargas que se benefician de páginas grandes existen hugepages: <1024|2|any> (tamaño en MiB, donde any intenta 1 GiB y cae a 2 MiB) y keephugepages: <boolean> con default 0, que las conserva tras el apagado para arranques posteriores.

Discos: buses, controlador SCSI, formatos y caché

BusMáximo de dispositivosPrefijoNotas
IDE4 (ide0-ide3)ide[n]Sistemas anteriores a 2003
SATA6 (sata0-sata5)sata[n]
SCSIscsi0-scsi30 en el APIscsi[n]Emula por defecto un LSI 53C895A. La prosa de la documentación dice “up to 14 storage devices”; el esquema del API acepta 31 slots
VirtIO Block16 (virtio0-virtio15)virtio[n]Paravirtualizado antiguo, superado por VirtIO SCSI

La recomendación textual es usar VirtIO SCSI o VirtIO Block por rendimiento y porque están mejor mantenidos. El controlador se elige con scsihw, cuyo default de backend es lsi:

ValorCuándo se usa
lsiLSI 53C895A, default del backend, máxima compatibilidad
lsi53c810Variante muy antigua
megasasLSI MegaRAID SAS
pvscsiVMware Paravirtual, útil en VMs importadas de ESXi
virtio-scsi-pciUn único controlador virtio-scsi para todos los discos. Requerido por las imágenes cloud de Ubuntu
virtio-scsi-singleUn controlador VirtIO SCSI por disco. Default de la GUI en VMs Linux desde PVE 7.3 y requisito para iothread en discos SCSI

La cita completa: se recomienda un controlador de tipo VirtIO SCSI single con IO Thread activado en los discos si buscas rendimiento; cada disco tendrá su propio controlador VirtIO SCSI y QEMU manejará su IO en un hilo dedicado.

Formatos

FormatoSnapshots propiosThin provisioningRendimiento
qcow2Sí, copy-on-writebase
rawNo, depende del storageNo, depende del storagehasta 10% más rápido que qcow2
vmdksolo para importar y exportar

Regla dura: los storages que presentan dispositivos de bloque (LVM, ZFS, Ceph) exigen raw. Los basados en fichero (ext4, XFS, NFS, CIFS) permiten elegir. La matriz completa por backend es el capítulo 7.

Modos de caché

El default de Proxmox VE es none, que en la GUI aparece como “No cache”.

ModoPage cache del hostCaché del disco del huéspedCuándo usarlo
none (default)Desactivada, O_DIRECTwritebackDefault general. “Good balance between safety and speed”
writethroughSolo lecturas, O_DSYNCDeshabilitadaMás seguro que writeback y más lento. Aceptable con SAN o RAID con batería
writebackLecturas y escriturasHabilitadaEl más rápido. Riesgo de pérdida de datos ante corte de corriente. Es el que recomienda la wiki para Windows Server 2022 y 2025
directsyncDesactivada, O_DSYNC más O_DIRECTwritethroughHuéspedes que no envían comandos flush correctamente. Peor rendimiento
unsafeHabilitadaHabilitadaComo writeback pero ignora los flush del huésped. Instalaciones desechables. No apto para producción

Gotcha: qcow2 combinado con directsync o writethrough rinde muy mal. Y añadir RAM al huésped sirve más como caché de lectura que cualquier ajuste de caché a nivel de host.

flowchart LR
    P["Proceso en el huesped"] --> FS["Sistema de ficheros del huesped"]
    FS --> CTL["Controlador virtual<br/>virtio-scsi-single"]
    CTL --> IOT["iothread dedicado<br/>uno por controlador"]
    IOT --> CACHE{"Modo de cache"}
    CACHE -->|"none"| DIR["O_DIRECT<br/>sin page cache del host"]
    CACHE -->|"writeback"| PC["Page cache del host<br/>confirma antes de bajar a disco"]
    DIR --> AIO["Capa aio<br/>io_uring native o threads"]
    PC --> AIO
    AIO --> ST["Storage: LVM-thin ZFS RBD o fichero"]

Discard, SSD emulation, IO Thread, aio y límites de IOPS

Con discard=on y un huésped con TRIM habilitado, cuando el sistema de ficheros del huésped marca bloques como no usados el controlador propaga la información al storage, que encoge la imagen. Requiere que el storage soporte thin provisioning, y algunos sistemas operativos huésped necesitan además ssd=1 para emitir TRIM (no hace falta que el medio físico sea realmente un SSD).

Dos restricciones que hay que memorizar: discard en VirtIO Block solo funciona con kernel Linux 5.0 o superior en el huésped, y la opción ssd no está soportada en virtio[n], solo en IDE, SATA y SCSI.

Para verificarlo dentro de un huésped Linux, lsblk --discard debe mostrar DISC-GRAN y DISC-MAX distintos de cero; después, fstrim -av y systemctl enable --now fstrim.timer.

IO Thread. La restricción es textual: la opción solo se puede usar con un disco con controlador VirtIO, o con el controlador SCSI cuando el tipo emulado es VirtIO SCSI single. Es decir, virtio[n] siempre, o scsi[n] solo si scsihw=virtio-scsi-single. Lo que gana: QEMU crea un hilo de IO por controlador de almacenamiento en lugar de manejar todo el IO en el event loop principal o en los hilos de vCPU, lo que reparte mejor el trabajo y reduce los bloqueos del huésped bajo IO intensivo, porque ni el hilo principal ni un hilo de vCPU pueden quedarse esperando al disco.

Async IO. aio acepta io_uring, native y threads. native (libaio) requiere cache=none o cache=directsync para ser realmente asíncrono; con caché de host se vuelve bloqueante. threads es un pool POSIX, el más compatible y la opción de fallback cuando io_uring da problemas con algunos storages de red o kernels antiguos. La documentación oficial de PVE 9.2 no publica un valor por defecto explícito para aio, así que si necesitas saber cuál está usando una VM concreta, míralo en la línea de comandos real:

qm showcmd 101 --pretty | grep aio

Límites de ancho de banda e IOPS. Todos los buses admiten el mismo conjunto: bps, bps_rd, bps_wr y sus *_max_length en segundos; mbps, mbps_max, mbps_rd, mbps_rd_max, mbps_wr, mbps_wr_max; iops, iops_max, iops_max_length y sus variantes de lectura y escritura. Un ejemplo real que limita un disco a 100 MB/s sostenidos con ráfagas de 200 MB/s durante 10 segundos y 5000 IOPS:

qm set 120 --scsi0 local-lvm:vm-120-disk-0,mbps=100,mbps_max=200,bps_max_length=10,iops=5000

Otras sub-opciones útiles de cualquier disco: backup=0 lo excluye de los backups, replicate=0 de los jobs de replicación, ro=1 lo hace de solo lectura, serial reporta un número de serie de hasta 20 bytes url-encoded, y size es puramente informativo y no tiene efecto. shared=1 marca un volumen gestionado localmente como disponible en todos los nodos, pero la propia documentación avisa de que esta opción no comparte el volumen: asume que ya lo está.

Operaciones de disco del día a día:

qm disk resize 120 scsi0 +20G                 # ampliar 20 GiB, reducir NO esta soportado
qm disk move 300 scsi0 other-storage --delete 1 --format qcow2 --bwlimit 100000
qm move-disk 300 scsi1 --target-vmid 400 --target-disk scsi3   # reasignar a otra VM
qm disk unlink 300 --idlist scsi1 --force 1   # sin --force deja el volumen como unused[n]
qm disk rescan --vmid 300 --dryrun 1          # descubrir discos huerfanos

Después de ampliar hay que crecer el sistema de ficheros dentro del huésped, con growpart más resize2fs en ext4, growpart más xfs_growfs en xfs, o pvresize más lvextend -r sobre LVM.

Red de la VM, display, puerto serie y boot order

net[n]: [model=]<enum> [,bridge=<bridge>] [,firewall=<1|0>] [,link_down=<1|0>]
        [,macaddr=<XX:XX:XX:XX:XX:XX>] [,mtu=<integer>] [,queues=<integer>]
        [,rate=<number>] [,tag=<integer>] [,trunks=<vlanid[;vlanid...]>]

Los modelos disponibles van desde e1000 y sus variantes hasta rtl8139, pcnet, vmxnet3 y virtio. La recomendación textual: el modelo virtio da el mejor rendimiento con muy poco overhead de CPU; si el huésped no soporta ese driver, lo normal es usar e1000.

Detalles con consecuencias:

  • Sin bridge se crea una red user-mode NAT de QEMU con gateway 10.0.2.2, DNS 10.0.2.3, SMB 10.0.2.4 y DHCP desde 10.0.2.15. Casi nunca es lo que quieres.
  • tag (1-4094) fija la VLAN de acceso y trunks la lista de VLANs a pasar. Los bridges, VLANs y bonding del host son el capítulo 9.
  • rate limita el tráfico en megabytes por segundo como número flotante.
  • mtu (1-65520) es solo para VirtIO; el valor 1 o vacío significa usar la MTU del bridge.
  • host-tunnel habilita GSO over UDP tunnel offload, solo con VirtIO y QEMU superior a 10.2. Está deshabilitado por defecto desde la machine version 11.0+pve1 por un problema con el driver virtio-net en kernels de huésped; en las machine versions 10.2 y 11.0 estaba habilitado.

Gotcha: pasar un dispositivo serie físico del host impide la migración. Para el display, vga acepta std (default desde QEMU 2.9 para todos los ostype salvo Windows XP y anteriores, que usan cirrus), none, la familia qxl* que habilita SPICE, virtio, virtio-gl, vmware y serial0 a serial3. memory (4-512 MiB) sube la memoria de vídeo para resoluciones de 1280x1024x16 en adelante y no tiene efecto con display serie. Y clipboard=vnc impide la live migration con machine versions anteriores a 10.1.

Los puertos serie se declaran como serial[n] con n de 0 a 3 y valor socket o una ruta /dev/.... Con socket se crea un socket unix en el host y se accede así:

qm set 100 --serial0 socket --vga serial0
qm terminal 100
qm terminal 100 --iface serial1 --escape '^O'

Boot order

boot: order=scsi0;net0;hostpci0

La clave legacy (a floppy, c disco, d CD-ROM, n red, default cdn) está deprecada. Lo que importa: solo los dispositivos que aparecen en order se marcan como bootables, y las versiones recientes de SeaBIOS y OVMF solo inicializan los discos marcados como tal. Los dispositivos no listados siguen disponibles para el sistema operativo una vez arrancado, porque el flag solo afecta al firmware y al bootloader.

Gotcha: si el huésped arranca desde varios discos (software RAID, LVM sobre varios PV), todos tienen que estar en la lista o la VM no arrancará. Es el fallo clásico tras añadir un segundo disco de arranque y olvidar tocar boot.

Arranque automático, hotplug y hookscripts

qm set 101 -onboot 1
qm set 101 -startup order=1,up=240,down=60
ParámetroSignificado
orderPrioridad de arranque. El apagado usa el orden inverso: order=1 es la última en apagarse. Con order empatado se ordena por VMID ascendente
upSegundos de espera antes de arrancar la siguiente VM
downShutdown timeout. Default 180 s; pasado ese tiempo la VM se detiene por la fuerza

Las VMs sin parámetro startup arrancan después de las que sí lo tienen, y el orden solo se aplica dentro del mismo host, no a nivel de cluster. Las VMs gestionadas por HA ignoran onboot y el boot order: quien decide es el HA manager, como verás en el capítulo 11.

El hotplug se controla con una lista:

hotplug: <string>    # default network,disk,usb

Acepta network, disk, cpu, memory, usb y cloudinit. El valor 0 lo desactiva por completo y 1 es alias de network,disk,usb. Para habilitarlo todo:

qm set 100 --hotplug network,disk,cpu,memory,usb,cloudinit --numa 1

Sobre el hot-plug de vCPU: el máximo enchufable es cores * sockets, vcpus define cuántas se enchufan al arranque, requiere numa: 1 y funciona solo en Linux con kernel superior a 3.10 (recomendado por encima de 4.7). No está soportado en Windows. Además, en Linux hay que poner las CPUs nuevas online con una regla udev en un fichero .rules bajo /etc/udev/rules.d/:

SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1"

El hot-remove depende de la cooperación del huésped: en x86 es una petición vía ACPI y el comando de borrado no garantiza la extracción real. Los hookscripts permiten enganchar lógica propia al ciclo de vida del huésped (pre-start, post-start, pre-stop, post-stop):

qm set 100 --hookscript local:snippets/hookscript.pl

El ejemplo documentado está en /usr/share/pve-docs/examples/guest-example-hookscript.pl. El storage debe tener el content type snippets habilitado.

Passthrough PCI(e), GPU, SR-IOV, mediated devices y USB

El passthrough entrega hardware físico del host directamente a una VM. Requiere soporte de IOMMU e interrupt remapping tanto en la CPU como en la placa base (VT-d en Intel, AMD-Vi en AMD, SMMU en arm64), y la documentación avisa de que el hardware de servidor suele tener mejor soporte que el de consumo. Antes de empezar, dos consecuencias duras: si pasas un dispositivo a una VM ya no puedes usarlo en el host ni en otra VM, y esa VM pierde la live migration.

flowchart TD
    A["BIOS/UEFI: activar VT-d o AMD-Vi"] --> B["Parametros de kernel<br/>segun el bootloader"]
    B --> B1["systemd-boot: /etc/kernel/cmdline<br/>y proxmox-boot-tool refresh"]
    B --> B2["GRUB: /etc/default/grub<br/>y update-grub"]
    B1 --> C["Modulos en /etc/modules<br/>vfio vfio_iommu_type1 vfio_pci"]
    B2 --> C
    C --> D["update-initramfs -u -k all<br/>y reiniciar"]
    D --> E{"Grupo IOMMU aislado"}
    E -->|"No"| E1["Probar otra ranura PCIe fisica"]
    E -->|"Si"| F["Liberar el dispositivo del host"]
    F --> F1["ids en vfio-pci"]
    F --> F2["blacklist del driver"]
    F --> F3["softdep pre vfio-pci"]
    F1 --> G["lspci -nnk debe decir vfio-pci"]
    F2 --> G
    F3 --> G
    G --> H["VM q35 con OVMF<br/>hostpci0 con pcie 1"]

Habilitar IOMMU

En la BIOS o UEFI la opción se llama normalmente IOMMU o VT-d. En el host, los parámetros de kernel se editan según el bootloader: con GRUB, en /etc/default/grub, línea GRUB_CMDLINE_LINUX_DEFAULT, seguido de update-grub; con systemd-boot y proxmox-boot-tool, en /etc/kernel/cmdline, seguido de proxmox-boot-tool refresh. Los parámetros relevantes:

intel_iommu=on      # Intel, necesario solo en kernels anteriores a 6.8
amd_iommu=on        # AMD, activado por defecto en kernels recientes
iommu=pt            # modo passthrough, puede mejorar rendimiento

El estado verificado en la documentación de 9.2: con CPUs AMD el IOMMU está activo por defecto y, con kernels 6.8 o más nuevos, también con CPUs Intel. En arm64 el SMMU lo activa el firmware vía ACPI y no hay parámetro de kernel.

Módulos VFIO y verificación

Los tres módulos que lista la documentación de PVE 9.2 van en /etc/modules:

vfio
vfio_iommu_type1
vfio_pci
update-initramfs -u -k all
reboot
lsmod | grep vfio
dmesg | grep -e DMAR -e IOMMU -e AMD-Vi

Los grupos IOMMU se consultan por la propia API con pvesh get /nodes/pve1/hardware/pci --pci-class-blacklist "". El dispositivo que quieres pasar debe estar en un grupo IOMMU separado. Es aceptable que comparta grupo con sus propias funciones (una GPU con su dispositivo de audio HDMI) o con su root port o puente PCI(e). Si no está aislado, la salida habitual es probar otra ranura PCIe física. Existe la opción de último recurso options vfio_iommu_type1 allow_unsafe_interrupts=1 en un fichero de /etc/modprobe.d/, con el aviso oficial de que puede volver el sistema inestable.

Liberar el dispositivo del host

Proxmox lo intenta automáticamente. Si no basta, hay tres caminos, todos en ficheros .conf bajo /etc/modprobe.d/ y todos seguidos de update-initramfs -u -k all y reinicio:

lspci -nn                                                  # obtener vendor:device
echo "options vfio-pci ids=10de:1d01,10de:0fb8" > /etc/modprobe.d/vfio.conf
echo "blacklist nouveau" >> /etc/modprobe.d/blacklist.conf
echo "softdep nouveau pre: vfio-pci" >> /etc/modprobe.d/nouveau.conf

La verificación final es lspci -nnk: debe decir Kernel driver in use: vfio-pci o no tener línea “in use” en absoluto.

Configurar la VM

Con el dispositivo libre, se asigna con qm set 210 -hostpci0 02:00,pcie=1,x-vga=1. Estas son las sub-opciones de hostpci[n]:

Sub-opciónDefaultQué hace
hostbus:dev.func en hexadecimal. Con 00:02 sin función se pasan todas las funciones. O host o mapping debe estar presente
mappingID de un mapping cluster-wide
pcie0Usa el bus PCI-express. Necesita machine q35
x-vga0Marca el dispositivo como GPU primaria. Con esto activo, la opción vga se ignora
rombar1Hace visible la ROM del firmware en el mapa de memoria del huésped. Algunos dispositivos necesitan 0
romfileROM personalizada, ruta relativa bajo /usr/share/kvm/
mdevTipo de mediated device; la instancia se crea al arrancar y se limpia al parar
legacy-igd0Modo IGD legacy. Requiere machine pc-i440fx y vga=none
drivervfioCon keep el dispositivo ni se resetea ni se vincula a vfio-pci. Nuevo en PVE 9.1, solo API y CLI
vendor-id, device-id, sub-vendor-id, sub-device-idSobrescriben los IDs PCI visibles por el huésped

El aviso oficial merece leerse entero: esta opción da acceso directo a hardware del host, ya no es posible migrar esas máquinas, hay que usarla con especial cuidado, y está marcada como experimental con problemas reportados por usuarios.

Para GPU passthrough, la mejor compatibilidad se alcanza con machine q35, OVMF en lugar de SeaBIOS y PCIe en lugar de PCI; si quieres OVMF, la GPU necesita una ROM con soporte UEFI, y si no la tiene hay que usar SeaBIOS o pasar una con romfile=. Limitación conocida: no es posible mostrar el framebuffer de la GPU vía noVNC o SPICE en la interfaz web, así que con salida de vídeo deseada hay que conectar un monitor físico a la tarjeta o configurar escritorio remoto dentro del huésped. Si solo la usas como acelerador de cómputo, esto no aplica.

SR-IOV crea Virtual Functions de dos formas: con options <driver> max_vfs=4 en /etc/modprobe.d/ seguido de update-initramfs -u -k all, o en caliente escribiendo en sysfs con echo 4 > /sys/bus/pci/devices/0000:01:00.0/sriov_numvfs (persistente con el paquete sysfsutils vía /etc/sysfs.conf o /etc/sysfs.d/). Después, cada VF aparece como un dispositivo PCI(e) separado en lspci y se pasa como cualquier otro.

Los mediated devices (vGPU, Intel GVT-g) son un caso distinto: no aparecen como dispositivos PCI(e) en el host, el dispositivo lo posee el driver del host y no vfio-pci, así que no hay que cargar los módulos vfio ni hacer blacklist. Para listar los tipos soportados y asignar uno:

ls /sys/bus/pci/devices/0000:00:02.0/mdev_supported_types
qm set 210 -hostpci0 00:02.0,mdev=i915-GVTg_V5_4

Cada entrada de ese directorio expone available_instances, description y create. Proxmox crea la instancia al arrancar la VM y la limpia al pararla.

USB passthrough

usb[n]: [[host=]<HOSTUSBDEVICE|spice>] [,mapping=<mapping-id>] [,usb3=<1|0>]

n va de 0 a 4, y hasta 14 con machine version 7.1 o superior y ostype l26 o Windows posterior a 7. El campo host acepta dos formatos: vendor_id:product_id en hexadecimal, con lo que dos dispositivos idénticos comparten identificador, o bus-port(.port)* en decimal, que apunta a puertos físicos concretos del host. El valor spice habilita la redirección USB del cliente SPICE.

lsusb -t
qm set 100 -usb0 host=0781:5583
qm set 100 -usb0 host=1-2.3
qm set 100 -usb1 spice

Comportamiento útil: si el dispositivo está en la configuración cuando la VM arranca pero no está presente en el host, la VM arranca sin problemas y el dispositivo se pasa en cuanto aparece. Y el aviso de siempre: con USB passthrough no puedes mover la VM en caliente a otro host.

Resource mapping cluster-wide y virtiofs

El problema que resuelve el resource mapping es concreto: con HA, en el nodo destino puede existir un dispositivo distinto con el mismo identificador o ruta, y se usaría el equivocado; además, cambiar hardware cambia rutas e IDs.

pvesh create /cluster/mapping/pci --id device1 \
  --map node=node1,path=0000:01:00.0,id=0002:0001 \
  --map node=node2,path=0000:02:00.0,id=0002:0001

qm set 210 -hostpci0 device1

Los tipos son pci, usb y dir (este último para virtiofs), y hay que repetir --map por cada nodo. Solo se puede mapear un dispositivo USB por nodo por mapping; para PCI sí se pueden dar varios map por nodo, y al arrancar se usa el primero libre en el orden en que están escritas las rutas, lo que resulta muy práctico con SR-IOV.

Dos opciones adicionales del mapping PCI: mdev marca el dispositivo como capaz de dar mediated devices (con varios PCI en el mapping, el mdev se crea en el primero con instancias disponibles) y live-migration-capable lo marca como capaz de live migration, algo que requiere soporte de driver y hardware y que solo se sabe que soportan GPUs NVIDIA con kernel reciente, con el aviso de que migrar en vivo dispositivos pasados es experimental. Los permisos son Mapping.Modify para crear y Mapping.Use para asignar, sobre la ruta /mapping/<tipo>/<nombre>; en la GUI están en Datacenter -> Resource Mappings.

virtiofs comparte un directorio del host con la VM y en PVE 9 se apoya en el mismo mecanismo de mappings:

apt install virtiofsd
pvesh create /cluster/mapping/dir --id compartido \
  --map node=node1,path=/srv/compartido \
  --map node=node2,path=/srv/compartido
qm set 100 -virtiofs0 dirid=compartido,cache=always,direct-io=1

Dentro del huésped se monta con mount -t virtiofs compartido /mnt/compartido, o en /etc/fstab con la línea compartido /mnt/compartido virtiofs rw,relatime 0 0.

El fichero VMID.conf: claves, locks y vmgenid

Todo lo anterior acaba escrito en /etc/pve/qemu-server/<VMID>.conf, dentro de pmxcfs, replicado automáticamente a todos los nodos del cluster. El formato es clave/valor separado por dos puntos, las líneas en blanco se ignoran y las que empiezan por # son comentarios (la description se guarda precisamente así). Se puede editar con vi, pero hay que reiniciar la VM para aplicar la mayoría de los cambios: lo recomendable es usar qm o la GUI, que aplican en caliente lo que se pueda.

Un ejemplo realista de VM Linux de producción:

agent: enabled=1,fstrim_cloned_disks=1
balloon: 2048
bios: seabios
boot: order=scsi0;net0
cores: 4
cpu: x86-64-v2-AES
cpuunits: 100
description: Servidor web de produccion%0A- nginx%0A- php-fpm
ide2: local:iso/debian-13-netinst.iso,media=cdrom
machine: pc-i440fx-11.0
memory: 8192
meta: creation-qemu=11.0.0,ctime=1770000000
name: web-prod-01
net0: virtio=BC:24:11:AA:BB:CC,bridge=vmbr0,firewall=1,tag=20
numa: 0
onboot: 1
ostype: l26
scsi0: local-lvm:vm-101-disk-0,cache=none,discard=on,iothread=1,size=64G,ssd=1
scsi1: ceph-pool:vm-101-disk-0,backup=0,cache=none,discard=on,iothread=1,size=500G
scsihw: virtio-scsi-single
shares: 1000
smbios1: uuid=6f2b1e0a-4d3c-4b2a-9c1f-8e7d6a5b4c3d
sockets: 1
startup: order=2,up=30
tags: produccion;web
vmgenid: 3a7f1c22-9b8e-4d5a-8f6c-2e1d0b9a8c7f

Y el bloque equivalente de una Windows 11 con UEFI, TPM y GPU pasada:

bios: ovmf
cpu: host,flags=+aes;+pcid,level=30
efidisk0: local-lvm:vm-210-disk-0,efitype=4m,ms-cert=2023k,pre-enrolled-keys=1,size=528K
hostpci0: 0000:01:00,pcie=1,x-vga=1
machine: pc-q35-11.0+pve2
memory: 16384
balloon: 0
ostype: win11
scsi0: local-lvm:vm-210-disk-1,cache=writeback,discard=on,iothread=1,size=128G,ssd=1
scsihw: virtio-scsi-single
tpmstate0: local-lvm:vm-210-disk-2,size=4M,version=v2.0
usb0: host=046d:c52b
vga: none

Fíjate en dos detalles del segundo ejemplo: balloon: 0 porque hay passthrough PCIe y el ballooning no funcionaría, y vga: none porque x-vga=1 hace que la opción vga se ignore de todos modos.

Algunas claves de nivel superior que no han salido hasta ahora y conviene conocer:

ClaveDefaultPara qué sirve
allow-ksm1Permitir fusión de páginas vía KSM. Configurable por VM desde PVE 9.1
argsArgumentos KVM arbitrarios, por ejemplo args: -no-reboot
kvm1Virtualización asistida por hardware. Ponerlo a 0 fuerza emulación pura
protection0Impide borrar la VM y sus discos
tablet1USB tablet para ratón absoluto en VNC. Se apaga solo con --vga qxl
vmstatestorageStorage donde guardar el estado de memoria en snapshots e hibernación

Hay claves que aparecen solas y no se ponen a mano: parent, snaptime, runningmachine, runningcpu, vmstate, meta y lock. Y vmgenid implementa el Virtual Machine Generation Identifier de Microsoft, que permite al sistema operativo huésped detectar eventos que provocan un salto en el tiempo, como restaurar un backup o hacer rollback de un snapshot. Se genera automáticamente en VMs nuevas. Añadirlo a una VM existente puede tener los mismos efectos que un rollback desde el punto de vista del huésped, porque lo interpreta como un cambio de generación:

qm set 101 -vmgenid 1                    # autogenerar
qm set 101 -delete vmgenid               # desactivarlo

Los locks los ponen las migraciones online, los snapshots y vzdump para impedir acciones concurrentes incompatibles. Los valores posibles son backup, clone, create, migrate, rollback, snapshot, snapshot-delete, suspended y suspending. Tras un corte de luz puede quedar uno huérfano y se quita con qm unlock 101, pero la advertencia oficial es literal: hazlo solo si estás seguro de que la acción que puso el lock ya no está corriendo.

Errores comunes y diagnóstico con qm showcmd

La herramienta de diagnóstico número uno es qm showcmd <vmid> --pretty: imprime la línea de comandos real que recibe QEMU, una opción por línea, incluyendo caché, aio, iothread, machine version y flags de CPU. Cuando la configuración dice una cosa y la VM se comporta como si dijera otra, ahí está la respuesta.

qm showcmd 101 --pretty          # la linea de comandos QEMU real
qm config 101 --current 1        # config actual, sin los cambios pendientes
qm pending 101                   # que cambios esperan a un arranque en frio
journalctl -b | grep -i -e kvm -e vfio -e iommu
SíntomaCausa probableDiagnóstico o solución
La VM creada por CLI no permite activar iothread en un disco SCSIscsihw es lsi, el default del backendqm set <vmid> --scsihw virtio-scsi-single
La VM no arranca: “Host doesn’t support requested features”cpu=host o un modelo por encima de la CPU del hostBajar el cputype; contrastar con lscpu y los flags
Una distribución moderna no arranca con la VM creada por scriptcpu quedó en kvm64, nivel v1Poner al menos x86-64-v2-AES
La VM no arranca tras añadir un segundo disco de arranqueEl disco no está en boot: order=Listar todos los discos de arranque en order
PXE no funciona con OVMFFalta dispositivo RNGqm set <vmid> -rng0 source=/dev/urandom
Pantalla OVMF con resolución mínimaResolución no fijada en el firmwareESC en el arranque → menú OVMF → Device Manager, o usar display SPICE
Quieres Secure Boot pero el efidisk es 2mefitype=2m no lo soportaBorrar y recrear con efitype=4m,pre-enrolled-keys=1, perdiendo la config OVMF
Warning de machine version deprecadaPor debajo del baseline 6.0 de PVE 9Subir la machine version; revisar snapshots con runningmachine, que no se puede cambiar
Windows pierde la configuración de red tras subir la machine versionCambia la enumeración de NICsEs esperado; por eso Windows fija la machine version en la creación
VM Windows 11/2022/2025 con VBS se congela al 100% de CPU en IntelBugzilla #7825qemu-server 9.2.0 o superior y machine 11.0+pve2 o superior
Windows 11 con VBS no arrancaFlags cet-ibt o cet-ss reactivados a manoEstán deshabilitados por defecto en 9.2 para machine types Win11; quítalos
Hyper-V no arranca en Windows sobre Intel reciente con cpu=hostCPUID leaf demasiado altoqm set <vmid> --cpu host,level=30
discard no libera espacioStorage sin thin provisioning, huésped sin TRIM, o VirtIO Block con kernel anterior a 5.0lsblk --discard y fstrim -av en el huésped; añadir ssd=1; pasar el disco a SCSI
El ballooning no reduce memoriaHay passthrough PCI(e) o mediated deviceDocumentado: con passthrough el ballooning no funciona
Hot-plug de CPU o RAM no funcionaFalta numa: 1qm set <vmid> --numa 1 --hotplug network,disk,cpu,memory,usb y reiniciar
Hot-plug de CPU no funciona en WindowsNo está soportadoSolo Linux, kernel superior a 3.10
Las CPUs nuevas aparecen offline en LinuxFalta la regla udevAñadir la regla SUBSYSTEM=="cpu" en /etc/udev/rules.d/
El passthrough falla: dispositivo en grupo IOMMU compartidoAislamiento insuficientepvesh get /nodes/<nodo>/hardware/pci --pci-class-blacklist ""; probar otra ranura PCIe
El driver del host sigue tomando la GPUBlacklist no aplicada o carga tempranalspci -nnk debe decir vfio-pci; añadir softdep <mod> pre: vfio-pci y update-initramfs -u -k all
pcie=1 no tiene efectoEl machine type no es q35PCIe solo existe con q35
GPU passthrough falla con OVMFROM sin soporte UEFIUsar SeaBIOS, o romfile= con una ROM UEFI en /usr/share/kvm/
Mediated device no disponibleDriver sin soporte mdev o sin instancias libresls /sys/bus/pci/devices/<addr>/mdev_supported_types y revisar available_instances
VM bloqueada con lock: backup tras un corte de luzLock huérfanoqm unlock <vmid>, solo si la tarea realmente no corre
Live migration bloqueadaPassthrough PCI o USB, dispositivo serie del host, disco físico, o clipboard=vnc con machine anterior a 10.1Migrar offline y adaptar el passthrough, o usar Resource Mapping
Un cambio de configuración no surte efectoEs un cambio pendienteqm pending <vmid>; aplicar con stop más start o qm reboot

Lo que queda operativo

Ya puedes construir una VM completa desde la línea de comandos sabiendo exactamente qué hace cada opción: elegir machine type y firmware según el huésped, dimensionar CPU con un modelo que sobreviva a una migración, separar máximo y mínimo de memoria con conocimiento de causa, montar discos sobre virtio-scsi-single con iothread, discard y el modo de caché correcto, y entregar hardware físico a un huésped cuando de verdad hace falta. También sabes leer y editar VMID.conf y desatascar una VM con qm unlock.

Lo que falta es el huésped más exigente de todos. Windows no ve ni un solo disco durante la instalación porque no trae los drivers paravirtualizados, necesita OVMF con Secure Boot y un TPM 2.0 para instalarse siquiera, y su guest agent introduce un ciclo freeze/thaw que puede romper la cadena de backups de SQL Server. Todo eso, incluido el enrolamiento de los certificados de 2023 antes de que caduquen los de 2011, es el capítulo 4.