Windows en Proxmox VE: VirtIO, guest agent y Secure Boot
Windows en Proxmox VE: VirtIO, guest agent y Secure Boot
Arrancas la VM, montas el ISO de Windows, eliges “Custom (advanced)” y el instalador te dice que no hay ningún disco donde instalar. No hay un disco de 64 GiB, no hay nada. La VM está bien creada, el disco existe en local-lvm y qm config lo muestra. Windows sencillamente no lo ve.
Ese es el peaje de entrada de Windows en Proxmox VE, y no es un fallo: es la consecuencia directa del modelo que viste en el capítulo 3. El controlador que le estás dando a la VM es VirtIO SCSI, un dispositivo paravirtualizado que no existe como hardware físico. Linux lleva ese driver en el kernel desde 2012; Windows no lo lleva en ninguna versión, y hay que dárselo a mano, desde un segundo CD-ROM, antes de que el instalador pueda pintar la primera partición.
Este capítulo cubre el ciclo completo de un huésped Windows en Proxmox VE 9.2: qué ISO de drivers descargar y de qué canal, cómo se crea una VM de Windows 11 que cumpla los requisitos de Microsoft sin trampas, qué se instala después del primer arranque, cómo funciona el QEMU Guest Agent y por qué puede romperte los backups diferenciales de SQL Server, y qué tienes que hacer antes de junio de 2026 con los certificados de Secure Boot para que tus VMs sigan arrancando.
Al final tendrás una VM Windows con disco SCSI paravirtualizado, red VirtIO, ballooning funcionando, el guest agent reportando IPs en la pestaña Summary y los certificados UEFI de 2023 enrolados.
Por qué Windows no ve el disco
QEMU puede presentar a la VM dos familias de dispositivos, y la elección tiene un coste medible.
Emulados. Reproducen hardware real byte a byte: un controlador IDE de 1984, un chip SATA, un LSI 53C895A, una tarjeta Intel E1000. Cualquier sistema operativo los reconoce sin drivers extra porque los drivers llevan décadas en el árbol. El precio es que el host tiene que simular el comportamiento del silicio real, registro a registro, y eso cuesta CPU.
Paravirtualizados (virtio). El huésped sabe que está virtualizado y coopera con el hipervisor mediante colas compartidas en memoria. No hay emulación de registros ni interrupciones falsas. La documentación oficial lo cuantifica sin rodeos:
“Using the virtio generic disk controller versus an emulated IDE controller will double the sequential write throughput, as measured with
bonnie++(8). Using the virtio network interface can deliver up to three times the throughput of an emulated Intel E1000 network card, as measured withiperf(1).”
El doble de escritura secuencial y hasta el triple de throughput de red. Por eso nadie serio instala Windows sobre IDE emulado. Y por eso hay que resolver el problema del arranque en frío: para instalar sobre VirtIO SCSI necesitas el driver, y para tener el driver necesitas haber instalado. El ISO virtio-win rompe ese círculo.
La alternativa perezosa —instalar sobre SATA y migrar después a SCSI— existe, pero implica un cambio de controlador de arranque en un Windows ya instalado, que es exactamente el tipo de operación que deja la VM en pantalla azul con INACCESSIBLE_BOOT_DEVICE. Carga el driver durante la instalación y ahórrate el rodeo.
El ISO virtio-win: canales, URLs y versiones envenenadas
Los drivers los publica el proyecto virtio-win, mantenido por Red Hat, en fedorapeople.org. Hay dos URLs estáticas que siempre apuntan a la última compilación de su canal:
| Recurso | URL |
|---|---|
| ISO stable | https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso |
| ISO latest | https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/virtio-win.iso |
virtio-win-guest-tools.exe | https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/virtio-win-guest-tools.exe |
| Archivo histórico | https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/ |
| RPM stable | https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.noarch.rpm |
La diferencia entre canales está documentada por el propio proyecto:
“The
stablebuilds of virtio-win roughly correlate to what was shipped with the most recent Red Hat Enterprise Linux release. Thelatestbuilds of virtio-win are the latest available builds, which may be pre-release quality.”
Traducido: stable es lo que Red Hat se atrevió a meter en una RHEL con soporte comercial. latest es la punta del desarrollo. Para producción, stable. Para reproducir un bug que ya está arreglado upstream, latest.
La descarga va directa al storage de ISOs del nodo. En una instalación por defecto el storage local vive en /var/lib/vz y guarda las imágenes ópticas en template/iso/, tal como viste en el capítulo 2:
cd /var/lib/vz/template/iso/
wget https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso
La versión que no debes usar
Aquí viene el gotcha caro, y está documentado en la wiki oficial de Proxmox, no en un foro:
Advertencia: la versión 0.1.285 provoca errores de lectura y problemas de rendimiento con discos VirtIO SCSI y VirtIO Block en máquinas Windows Server 2025 bajo carga de IO intensiva. El caso reportado es Microsoft SQL Server. El workaround oficial es usar 0.1.271-1 (7 de abril de 2025), que no está afectada.
La última versión documentada de forma verificable es 0.1.285-1, publicada el 12 de septiembre de 2025. El listado de directorios de fedorapeople.org está detrás de un anti-bot y no devuelve el índice de archivos, así que si necesitas saber qué versión tienes exactamente, monta el ISO y mira el nombre de las subcarpetas de driver, o comprueba la versión del paquete en el Device Manager del huésped.
Histórico de versiones con avisos conocidos:
| Rango | Problema | Estado |
|---|---|---|
| 0.1.215 – 0.1.262 | Avisos de reset de dispositivo y bloqueos de IO | Resuelto en 0.1.266+ |
| 0.1.271-1 | (7-abr-2025) sin avisos conocidos | Versión de refugio |
| 0.1.285-1 | (12-sep-2025) errores de lectura con IO intensivo en Server 2025 | Usar 0.1.271 |
| 0.1.173-9 | Última que soporta Windows XP | Histórica |
Si administras un Windows Server 2025 con una base de datos encima, esta tabla vale más que todo lo demás del capítulo.
Estructura del ISO y firma de los drivers
El ISO tiene una carpeta por driver en el nivel superior, y dentro de cada una, subcarpetas por versión de Windows (w7, w8.1, w10, w11, 2k12R2, 2k16, 2k19, 2k22, 2k25) y por arquitectura (amd64, x86, ARM64).
virtio-win.iso
vioscsi/
w11/amd64/
2k25/amd64/
viostor/
NetKVM/
Balloon/
vioserial/
viorng/
vioinput/
qxldod/
viogpudo/
pvpanic/
smbus/
guest-agent/
qemu-ga-x86_64.msi
virtio-win-gt-x64.msi
virtio-win-guest-tools.exe
Qué hace cada uno:
| Carpeta | Driver | Función |
|---|---|---|
vioscsi | Red Hat VirtIO SCSI pass-through controller | Discos SCSI con virtio-scsi-pci o virtio-scsi-single |
viostor | Red Hat VirtIO SCSI controller | Discos VirtIO Block (virtio[n]) |
NetKVM | Redhat VirtIO Ethernet Adapter | Red virtio |
Balloon | VirtIO Balloon Driver | Ballooning y el servicio BLNSVR.exe |
vioserial | VirtIO Serial Driver | Canal de comunicación del guest agent |
viorng | VirtIO RNG Device | Entropía |
vioinput | VirtIO Input Driver | Teclado y ratón virtio |
qxldod | QXL display | SPICE en Windows 10 y posteriores |
viogpudo | VirtIO GPU DOD | Display virtio |
pvpanic | pvpanic | Notificación de panic al host |
smbus | SMBus | Chipset |
guest-agent | qemu-ga-x86_64.msi | QEMU Guest Agent |
La confusión más frecuente es vioscsi frente a viostor: el primero es para el bus SCSI (scsi0, con scsihw=virtio-scsi-single) y el segundo para VirtIO Block (virtio0). Si creaste el disco como scsi0, el driver que buscas es vioscsi, aunque viostor se llame literalmente “VirtIO SCSI controller” en la descripción.
flowchart LR
ISO["ISO virtio-win"] --> VS["vioscsi"]
ISO --> VB["viostor"]
ISO --> NK["NetKVM"]
ISO --> BL["Balloon"]
ISO --> VSER["vioserial"]
ISO --> QXL["qxldod"]
VS --> D1["scsi0 con scsihw virtio-scsi-single"]
VB --> D2["virtio0 - VirtIO Block"]
NK --> D3["net0 model virtio"]
BL --> D4["Ballooning y servicio BLNSVR"]
VSER --> D5["Canal del QEMU Guest Agent"]
QXL --> D6["Display SPICE"]
Firmas y Secure Boot
Este punto decide si la instalación te va a salir a la primera o no:
- Los drivers para Windows 8 y posteriores llevan la test signature de Red Hat.
- Los drivers para Windows 10 y posteriores llevan Microsoft attestation signature.
- Ninguno está firmado con WHQL. La certificación WHQL solo llega con una suscripción RHEL de pago.
Con Secure Boot activo, algunas versiones de Windows se niegan a cargar drivers que no estén firmados por Microsoft. El certificado de prueba de Red Hat está disponible en el host, dentro del paquete de drivers, en /usr/share/virtio-win/drivers/by-driver/cert/Virtio_Win_Red_Hat_CA.cer, por si necesitas enrolarlo manualmente en el firmware de la VM.
En la práctica, con una VM Windows 11 creada con pre-enrolled-keys=1 y drivers de un canal stable reciente, la attestation signature basta y no vas a tocar el certificado. Si te topas con un “el sistema no puede verificar la firma digital de este driver”, la primera hipótesis es una versión antigua del ISO, no un problema de configuración de la VM.
Receta completa de una VM Windows 11 válida
Windows 11 impone tres requisitos que en un hipervisor hay que fabricar explícitamente: firmware UEFI, Secure Boot y TPM 2.0. Ninguno de los tres aparece por defecto. Esta es la creación completa por CLI, con cada opción justificada:
qm create 210 --name win11 \
--ostype win11 \
--machine q35 \
--bios ovmf \
--efidisk0 local-lvm:1,efitype=4m,pre-enrolled-keys=1 \
--tpmstate0 local-lvm:1,version=v2.0 \
--scsihw virtio-scsi-single \
--scsi0 local-lvm:64,cache=writeback,discard=on,ssd=1,iothread=1 \
--ide0 local:iso/Win11.iso,media=cdrom \
--ide2 local:iso/virtio-win.iso,media=cdrom \
--boot 'order=ide0;scsi0' \
--cores 4 --sockets 1 --cpu x86-64-v2-AES \
--memory 8192 --balloon 4096 \
--net0 virtio,bridge=vmbr0 \
--agent enabled=1
Desglose de las decisiones que no son negociables:
Uno. --ostype win11. No es cosmético. El ostype activa localtime automáticamente (el RTC de Windows espera hora local, Unix espera UTC), determina el citype por defecto de cloud-init, habilita los flags de hotplug USB y —esto es lo importante— fija la machine version en la creación. Windows es sensible a cambios de hardware virtual incluso entre arranques en frío: si la machine version bailara, cambiaría la enumeración de NICs y perderías la configuración de red.
Dos. --machine q35 y --bios ovmf. Q35 es el chipset moderno con bus PCIe virtual; OVMF es la implementación UEFI. Windows 11 exige UEFI. En arm64 el machine type es virt y SeaBIOS ni siquiera existe: OVMF es la única opción.
Tres. --efidisk0 ...,efitype=4m,pre-enrolled-keys=1. El disco EFI persiste el boot order y las variables UEFI. El default del API es efitype=2m, y 2m no soporta Secure Boot. La GUI pone 4m; la CLI no. Este es el error número uno al crear VMs Windows por script. pre-enrolled-keys=1 precarga las claves de las distribuciones y las de Microsoft Standard Secure Boot, y deja Secure Boot habilitado por defecto.
Gotcha: si ya tienes una VM con un efidisk 2m y quieres Secure Boot, no se puede convertir. Hay que borrarlo y recrearlo, lo que resetea toda la configuración del menú OVMF, incluido el boot order guardado en las variables EFI:
qm set 210 -delete efidisk0
qm set 210 -efidisk0 local-lvm:1,efitype=4m,pre-enrolled-keys=1
Cuatro. --tpmstate0 local-lvm:1,version=v2.0. El default del API es v1.2, y Windows 11 exige v2.0. La versión no se puede cambiar después de creado: solo eliminar y recrear el estado, con lo que pierdes cualquier clave sellada dentro (BitLocker incluido). Se implementa con swtpm, emulación por software, y la documentación es honesta sobre lo que eso significa:
“Compared to a physical TPM, an emulated one does not provide any real security benefits. […] Since with an emulated device the data storage happens on a regular volume, it can potentially be edited by anyone with access to it.”
Es decir: el TPM emulado existe para satisfacer el requisito de instalación de Windows 11 y para habilitar BitLocker, no para protegerte de alguien con acceso al storage del hipervisor.
Cinco. --scsihw virtio-scsi-single con --scsi0 ...,iothread=1. La restricción es textual: iothread solo funciona con el controlador VirtIO Block, o con SCSI cuando el controlador emulado es VirtIO SCSI single. Con virtio-scsi-single QEMU crea un controlador por disco y un hilo de IO dedicado, en lugar de manejar todo el IO en el event loop principal o en los hilos de vCPU. El resultado práctico es menos “hangs” del huésped bajo IO intensivo.
Seis. cache=writeback. Es la única desviación respecto al default de Proxmox (none) que la wiki oficial recomienda explícitamente para Windows Server 2022 y 2025. Cachea lecturas y escrituras en la page cache del host y confirma al huésped en cuanto el dato llega ahí. Es más rápido y tiene riesgo real de pérdida de datos ante un corte de corriente. Si el host no tiene SAI, quédate en cache=none.
Siete. --ide0 y --ide2 como dos CD-ROM. Uno lleva el ISO de Windows y el otro el de virtio-win. --boot 'order=ide0;scsi0' arranca primero desde el ISO de instalación. El valor va entrecomillado porque el punto y coma separa dispositivos en la sintaxis de boot y, sin comillas, tu shell lo interpretaría como separador de comandos. Solo los dispositivos listados en order se marcan como bootables y son inicializados por el firmware.
Ocho. --cpu x86-64-v2-AES. El default del backend es kvm64, que es el baseline x86-64-v1 y que varias distribuciones modernas ya ni siquiera soportan. La GUI pone x86-64-v2-AES, que requiere Intel Westmere o AMD Opteron de cuarta generación en adelante. Si el cluster es homogéneo y no te importa la live migration, host te da todo lo que la CPU física ofrece.
La tabla de la wiki Windows_2022_guest_best_practices y su equivalente para 2025 recogen exactamente estos valores:
| Tab del wizard | Ajuste recomendado |
|---|---|
| OS | ISO de Windows; Guest OS = “Microsoft Windows 11/2022/2025” |
| System | Machine q35, BIOS OVMF (UEFI), Add EFI Disk (4m, pre-enrolled-keys), Add TPM v2.0, SCSI Controller VirtIO SCSI single, marcar Qemu Agent |
| Disks | Bus SCSI, Cache Write back, Discard sí, IO Thread sí |
| CPU | Cores según necesidad; host si vas a usar WSL |
| Memory | Según necesidad; el ballooning se ajusta después |
| Network | Model VirtIO (paravirtualized) |
Si prefieres añadir el segundo CD-ROM a una VM ya creada desde la GUI: Hardware -> Add -> CD/DVD drive, Bus IDE, número 0, y seleccionas virtio-win.iso. El equivalente CLI:
qm set 210 --ide0 local:iso/virtio-win.iso,media=cdrom
Instalación paso a paso: cargar vioscsi, NetKVM y Balloon
Arrancas la VM, abres la consola noVNC y eliges “Custom (advanced)”. El instalador muestra una lista de discos vacía. Ahí es donde entra el segundo CD-ROM.
sequenceDiagram
participant OP as Operador
participant WIN as Instalador de Windows
participant CD as CD virtio-win
participant VM as VM en Proxmox
OP->>WIN: Elegir Custom advanced
WIN-->>OP: No se encuentra ningun disco
OP->>WIN: Pulsar Load driver
WIN->>CD: Buscar en vioscsi w11 amd64
CD-->>WIN: Red Hat VirtIO SCSI pass-through controller
WIN-->>OP: Aparece el disco de 64 GiB
OP->>WIN: Load driver NetKVM w11 amd64
OP->>WIN: Load driver Balloon w11 amd64
OP->>WIN: Continuar la instalacion
WIN->>VM: Primer arranque de Windows
OP->>VM: Ejecutar guest-agent qemu-ga-x86_64.msi
OP->>VM: Ejecutar virtio-win-gt-x64.msi
OP->>VM: Reiniciar
VM-->>OP: Summary muestra uso de RAM e IPs
Los tres drivers a cargar, en este orden, con las rutas exactas de la wiki oficial:
| Orden | Botón | Carpeta (Win 11 / Server 2022 / Server 2025) | Driver a seleccionar |
|---|---|---|---|
| 1 | Load driver | vioscsi\w11\amd64 / vioscsi\2k22\amd64 / vioscsi\2k25\amd64 | Red Hat VirtIO SCSI pass-through controller |
| 2 | Load driver | NetKVM\w11\amd64 / NetKVM\2k22\amd64 / NetKVM\2k25\amd64 | Redhat VirtIO Ethernet Adapter |
| 3 | Load driver | Balloon\w11\amd64 / Balloon\2k22\amd64 / Balloon\2k25\amd64 | VirtIO Balloon Driver |
Para Windows 10 la subcarpeta es w10. Tras cargar el primero, el disco aparece y la instalación continúa con normalidad; los otros dos se cargan en la misma pantalla para ahorrarte el paso posterior.
Gotcha: en el diálogo “Load driver” hay que dejar marcado “Include subfolders”. Si lo desmarcas y apuntas a la raíz del CD, el instalador no encuentra ningún .inf y te dice que no hay drivers compatibles. Es el error más reportado del proceso y no tiene nada que ver con la versión del ISO.
Post-instalación: guest agent, virtio-win-gt-x64.msi y Device Manager
Windows arranca. Todavía le falta la mitad del equipamiento. El orden importa:
Uno. QEMU Guest Agent. Ejecuta <CD>:\guest-agent\qemu-ga-x86_64.msi (o qemu-ga-i386.msi en un huésped de 32 bits). Si activaste “Qemu Agent” en la configuración de la VM y aún no has instalado el agente, notarás que el puntero del ratón está descolocado en la consola: es el síntoma clásico.
Dos. El resto de drivers y servicios. Ejecuta <CD>:\virtio-win-gt-x64.msi. Instala NetKVM, Balloon con su servicio, vioserial, viorng, vioinput y el resto. Puedes deseleccionar “Qxl” y “Spice” si no vas a usar el cliente SPICE, con lo que te ahorras un driver de display que no aporta nada en un huésped al que accedes por RDP.
Tres. Reinicia la VM. No un reinicio desde dentro: los cambios de configuración de la VM se aplican en un arranque limpio.
Cuatro. Verifica en el Device Manager que no queda ningún “Unknown device” ni ningún dispositivo con el triángulo amarillo. Si queda alguno, la causa casi siempre es un driver individual que el instalador global no cubrió; se resuelve apuntando manualmente al ISO desde “Update driver”.
Cinco. La página Summary de la VM en la interfaz web debe mostrar ahora el uso real de RAM y las direcciones IP del huésped. Si ese panel sigue vacío, el agente no está corriendo.
Si vas a ejecutar WSL dentro del huésped, necesitas virtualización anidada: pon el CPU type a host o añade el flag nested-virt, que se introdujo en PVE 9.1 precisamente como alternativa a tener que usar cputype=host solo por esto.
Ballooning en Windows: driver, BLNSVR y cuándo no usarlo
El ballooning permite que el hipervisor recupere memoria de una VM que no la está usando. En la configuración, la relación es contraintuitiva y conviene fijarla:
memoryes el máximo. En la GUI aparece como “Memory (MiB)”.balloones el mínimo garantizado. En la GUI, “Minimum memory (MiB)”.shares(default1000, rango 0-50000) es el peso relativo al repartir la memoria sobrante entre VMs.balloon: 0desactiva el dispositivo por completo.
El auto-ballooning lo ejecuta pvestatd mientras el uso de RAM del host esté por debajo de un objetivo, que por defecto es el 80% de la RAM del host y se ajusta por nodo:
pvenode config set --ballooning-target 90
En Linux el driver del balloon está en el kernel desde 2010. En Windows no. Hay que instalar el driver desde Balloon\<version>\amd64 y además registrar el servicio:
BLNSVR.exe -i
Desde Windows Server 2012 y Windows 8.1, el instalador virtio-win-gt-x64.msi hace las dos cosas por ti. Si instalaste solo el driver a mano y el ballooning no reduce memoria, lo que falta es el servicio.
Tres avisos que ahorran diagnósticos largos:
Uno. La documentación no recomienda ballooning en sistemas Windows críticos: puede degradar el rendimiento de forma difícil de correlacionar.
Dos. El ballooning no funciona en absoluto si la VM tiene passthrough PCI(e) o un mediated device asignado. La memoria del huésped queda pinneada. No es un bug, es una consecuencia de cómo funciona el DMA.
Tres. Deja siempre alrededor de 1 GB de RAM libre para el host. Un nodo que se queda sin memoria empieza a matar procesos QEMU.
QEMU Guest Agent: qué habilita exactamente
El guest agent es un demonio dentro del huésped que habla con QEMU por un canal virtio-serial. No es opcional en un entorno serio: cinco funciones dependen de él.
- Apagado limpio. Con el agente activo, Proxmox envía los comandos de energía por el agente en lugar de emitir eventos ACPI.
guest-fsfreeze-freeze/guest-fsfreeze-thawpara consistencia de datos en backups y snapshots.- IPs en la interfaz web. El panel Summary obtiene las direcciones del huésped vía el agente.
- TRIM automático tras operaciones que escriben ceros o mueven datos.
- Ejecución remota de comandos (
qm guest exec) y cambio de contraseñas (qm guest passwd).
La configuración en la VM es una sola clave con cuatro sub-opciones:
agent: [enabled=]<1|0> [,freeze-fs=<1|0>] [,fstrim_cloned_disks=<1|0>] [,type=<virtio|isa>]
| Sub-opción | Default | Qué hace |
|---|---|---|
enabled | 0 | Habilita la comunicación con el agente |
freeze-fs | 1 | Emitir guest-fsfreeze-freeze y thaw. El antiguo freeze-fs-on-backup se trata como alias |
fstrim_cloned_disks | 0 | Ejecutar fstrim tras mover un disco o migrar la VM |
type | virtio | Transporte: virtio o isa |
qm set 210 --agent enabled=1,fstrim_cloned_disks=1
qm set 210 --agent 1 # forma corta equivalente
Advertencia: la documentación es literal sobre esto: “A fresh start of the VM is necessary for the changes to take effect.” Un reinicio caliente desde dentro de Windows no basta. Hay que hacer stop + start, o un qm reboot, que sí aplica los cambios pendientes.
La instalación en el huésped Windows, cuando no usaste el instalador global:
- Monta el ISO virtio-win.
- Instala el driver virtio-serial desde
vioserial\<version>\amd64en el Device Manager, si no está. - Ejecuta
<CD>:\guest-agent\qemu-ga-x86_64.msi. - Verifica en PowerShell:
Get-Service QEMU-GA
Si el servicio no está corriendo, arráncalo desde services.msc y ponlo en autostart.
En Linux el equivalente es una línea, para que tengas la comparación a mano:
apt-get install qemu-guest-agent
systemctl enable --now qemu-guest-agent
El ciclo freeze/thaw, VSS y el problema con SQL Server
Cuando Proxmox necesita una copia consistente de los discos de una VM en ejecución, no puede simplemente leer los bloques: el huésped tiene escrituras en vuelo y caché sucia. La solución es pedirle al huésped que congele sus sistemas de archivos durante un instante.
El freeze se emite en cualquiera de estas cinco operaciones, siempre que agent enabled=1, freeze-fs=1 y el agente esté realmente corriendo:
- Backup en modo snapshot.
- Clonar una VM mientras está corriendo.
- Replicar una VM en ejecución.
- Tomar un snapshot sin RAM de una VM en ejecución.
- Importar una imagen de disco desde un huésped en ejecución.
En Windows, guest-fsfreeze-freeze no congela el filesystem directamente: llama a VSS (Volume Shadow Copy Service), que a su vez notifica a los VSS writers registrados en el sistema para que dejen sus datos en un estado consistente. Ahí está el problema documentado:
“it has been observed that calling
guest-fsfreeze-freezewith some SQL Servers triggers VSS to call the SQL Writer VSS module in a mode that breaks the SQL Server backup chain for differential backups.”
Es decir: el backup de Proxmox funciona, pero la cadena de backups diferenciales de SQL Server queda rota, y eso no se nota hasta que intentas restaurar. Hay dos salidas y no son equivalentes.
flowchart TD
OP["Backup snapshot - clone en caliente - replicacion - snapshot sin RAM"] --> Q1{"agent enabled=1 y freeze-fs=1"}
Q1 -->|No| DIRECT["Copia sin congelar - filesystem potencialmente inconsistente"]
Q1 -->|Si| FZ["guest-fsfreeze-freeze"]
FZ --> VSS{"Huesped Windows con SQL Server"}
VSS -->|No| COPY["Copia de los bloques"]
VSS -->|Si| BREAK["VSS llama al SQL Writer y rompe la cadena diferencial"]
BREAK --> S1["Solucion preferida - configurar otra variante de VSS en el QGA"]
BREAK --> S2["Alternativa - agent enabled=1 freeze-fs=0"]
S1 --> COPY
S2 --> DIRECT
COPY --> TH["guest-fsfreeze-thaw"]
TH --> END["Backup consistente"]
Solución preferida: configurar el QEMU Guest Agent dentro del huésped para que use otra variante de VSS. La wiki VM_Backup_Consistency de Proxmox documenta el procedimiento.
Alternativa: desactivar el ciclo freeze/thaw para esa VM.
qm set 210 --agent enabled=1,freeze-fs=0
En la GUI: Options -> QEMU Guest Agent, desmarcar “Freeze/thaw guest filesystems during certain operations for consistency”. La documentación lo acompaña de un aviso en mayúsculas:
“IMPORTANT: Disabling this option can potentially lead to backups with inconsistent filesystems.”
Estás cambiando “el backup del hipervisor rompe la cadena de SQL” por “el backup del hipervisor puede capturar un filesystem inconsistente”. Si eliges esta vía, la copia de seguridad real de la base de datos tiene que venir de un backup lógico dentro del huésped, no del snapshot del hipervisor. La estrategia completa de backups la desarrollas en el capítulo 13.
TRIM automático, fstrim_cloned_disks y el caveat de ext4
Con discard=on en el disco y TRIM habilitado en el huésped, cuando el sistema de archivos marca bloques como no usados el controlador propaga esa información al storage, que encoge la imagen. Requiere que el storage soporte thin provisioning: LVM-thin, ZFS, Ceph/RBD o qcow2 sobre un storage de fichero. Los detalles por backend están en el capítulo 7.
Dos restricciones que se olvidan:
discarden VirtIO Block solo funciona con kernel Linux >= 5.0 en el huésped. En Windows, usa SCSI.ssdno está soportado envirtio[n]. Solo en IDE, SATA y SCSI. Como la receta de Windows usascsi0, puedes ponerssd=1sin problema; algunos sistemas huésped solo emiten TRIM si creen que el medio es SSD.
Además del TRIM que emite el propio huésped, Proxmox puede forzar uno. Con fstrim_cloned_disks=1, el hipervisor emite un trim al huésped después de:
- mover un disco a otro storage;
- migrar en caliente una VM a otro nodo con storage local.
Gotcha con ext4 (aplica a los huéspedes Linux de tu parque, no a Windows, pero se configura en la misma opción): ext4 usa una optimización en memoria para evitar peticiones TRIM duplicadas. Como el huésped no sabe que el storage subyacente cambió, solo el primer guest-trim funcionará como se espera; los siguientes, hasta el próximo reinicio, solo considerarán las partes del sistema de archivos que cambiaron desde entonces.
Comandos qm guest cmd, exec y passwd
Con el agente corriendo tienes una vía de gestión que no pasa por la red del huésped. Es la herramienta que salva el día cuando una VM perdió su IP.
qm agent 210 ping # alias de 'qm guest cmd'
qm guest cmd 210 ping
qm guest cmd 210 get-osinfo
qm guest cmd 210 network-get-interfaces
qm guest cmd 210 get-fsinfo
qm guest cmd 210 fstrim
qm guest cmd 210 fsfreeze-status
qm guest cmd 210 shutdown
Comandos válidos completos para qm guest cmd:
fsfreeze-freeze | fsfreeze-status | fsfreeze-thaw | fstrim | get-fsinfo | get-host-name | get-memory-block-info | get-memory-blocks | get-osinfo | get-time | get-timezone | get-users | get-vcpus | info | network-get-interfaces | ping | shutdown | suspend-disk | suspend-hybrid | suspend-ram
Ejecución de comandos dentro del huésped:
qm guest exec 210 -- powershell.exe -Command "Get-Service QEMU-GA"
qm guest exec 210 --timeout 60 --synchronous 1 -- ipconfig /all
qm guest exec 210 --pass-stdin 1 -- tee C:\\temp\\file.txt < local.txt
qm guest exec-status 210 <pid>
Opción de qm guest exec | Default | Notas |
|---|---|---|
--pass-stdin <boolean> | 0 | Lee STDIN hasta EOF y lo reenvía vía input-data. Máximo 1 MiB |
--synchronous <boolean> | 1 | Con 0 devuelve el pid inmediatamente y consultas con exec-status |
--timeout <integer> | 30 | Segundos. 0 lo desactiva |
Y el cambio de contraseña, útil cuando alguien se dejó fuera:
qm guest passwd 210 Administrator
qm guest passwd 210 Administrator --crypted 1
La referencia del protocolo, si necesitas un comando que no está en la lista de qm, está en la documentación de QEMU: https://www.qemu.org/docs/master/interop/qemu-ga-ref.html.
Certificados Secure Boot: la expiración de 2011 y ms-cert=2023k
Este es el tema con fecha límite del capítulo. La documentación de Proxmox lo dice sin adornos:
“The original set of Microsoft certificates from 2011, which Windows and common Linux distributions use for secure boot, expires in June 2026.”
El mecanismo es simple y por eso duele. El firmware UEFI solo permite arrancar bootloaders firmados con certificados presentes en el disco EFI de la VM. Un efidisk0 creado hace años contiene únicamente los certificados de 2011. Cuando el bootloader de tu Windows —o de tu Debian— se actualice y venga firmado con los certificados de 2023, ese firmware lo rechazará y la VM no arrancará.
El marcador que indica el estado del disco EFI es la sub-opción ms-cert de efidisk0:
| Valor | Significado |
|---|---|
2011 | Solo los certificados originales. Hay que reenrolar |
2023 | Enrolamiento parcial. Hay que reenrolar igualmente |
2023w | Enrolamiento parcial. Hay que reenrolar igualmente |
2023k | Los tres certificados nuevos enrolados: Microsoft UEFI CA 2023, Windows UEFI CA 2023 y Microsoft Corporation KEK 2K CA 2023 |
Desde pve-edk2-firmware >= 4.2025.05-1, los discos EFI nuevos contienen tanto los de 2011 como los de 2023 y ya llevan ms-cert=2023k. El problema es el parque existente. Los valores 2023 y 2023w generan un aviso en el log de la tarea de arranque, y aun así hay que actuar sobre ellos.
flowchart TD
START["Revisar efidisk0 en la config de cada VM"] --> CHECK{"ms-cert es 2023k"}
CHECK -->|Si| OK["Nada que hacer"]
CHECK -->|No| BL{"El huesped Windows usa BitLocker"}
BL -->|Si| MB["Dentro de Windows por cada unidad - manage-bde -protectors -disable C:"]
BL -->|No| OFF["Apagar la VM"]
MB --> OFF
OFF --> ENROLL["qm enroll-efi-keys VMID o GUI Disk Action Enroll Updated Certificates"]
ENROLL --> BOOT["Arrancar la VM - surte efecto en el siguiente arranque"]
BOOT --> VERIFY["Comprobar ms-cert=2023k en qm config VMID"]
El procedimiento, en orden estricto:
Uno. Si el huésped Windows usa BitLocker, dentro del huésped y por cada unidad cifrada:
manage-bde -protectors -disable C:
Advertencia: si te saltas este paso, en el siguiente arranque Windows detectará un cambio en la cadena de confianza del firmware y pedirá la clave de recuperación de BitLocker. Si no la tienes a mano, la VM se queda ahí.
Dos. Apaga la VM. El comando CLI lo exige.
Tres. Enrola los certificados:
qm enroll-efi-keys 210
O desde la interfaz web: Hardware -> seleccionar el EFI Disk -> Disk Action -> Enroll Updated Certificates. Surte efecto en el siguiente arranque de la VM.
Cuatro. Verifica:
qm config 210 | grep efidisk0
Salida esperada, con el marcador actualizado:
efidisk0: local-lvm:vm-210-disk-0,efitype=4m,ms-cert=2023k,pre-enrolled-keys=1,size=528K
Cinco. Vuelve a habilitar los protectores de BitLocker dentro del huésped.
Un barrido rápido de todas las VMs del nodo para saber a cuántas les toca:
for id in $(qm list | awk 'NR>1 {print $1}'); do
line=$(qm config "$id" | grep '^efidisk0:') || continue
echo "$id -> $line"
done
Ajustes de CPU específicos de Windows: cet-ibt, cet-ss y level=30
Proxmox VE 9.2 trae dos cambios de CPU que solo afectan a huéspedes Windows y que conviene conocer antes de encontrártelos.
Uno. cet-ibt y cet-ss deshabilitados por defecto. Son los flags de Control-flow Enforcement Technology. PVE 9.2 los deshabilita por defecto en los machine types de Windows 11 porque rompían el arranque cuando el huésped tenía Virtualization-Based Security activo. Se pueden reactivar por VM desde el editor de flags del panel Processor, pero si tu Windows 11 con VBS no arranca y tú los activaste a mano, esa es la causa.
Dos. level=30. La propiedad level fija el máximo CPUID leaf visible para el huésped. Es el workaround conocido para fallos de arranque de Hyper-V en huéspedes Windows sobre hosts Intel recientes cuando el cputype es host o max:
qm set 210 --cpu host,level=30
Solo aplica a x86_64. Si tu Windows 11 usa Hyper-V, WSL2, Windows Sandbox o cualquier otra función que se apoye en el hipervisor de Microsoft, y no arranca sobre un host Intel de generación reciente, prueba esto antes que nada.
Bug conocido de 9.2: las VMs Windows 11, Server 2022 y Server 2025 con cpu host y VBS pueden congelarse en hosts Intel. El fix está en qemu-server 9.2.0 con machine version 11.0+pve2 o superior. Si tienes una VM con ese síntoma, comprueba la machine version:
qm config 210 | grep machine
Y recuerda: el hot-plug de vCPU no está soportado en Windows, solo en Linux con kernel > 3.10 (> 4.7 recomendado). Si necesitas más cores en una VM Windows, hay apagado de por medio.
Una configuración completa de referencia, como queda en /etc/pve/qemu-server/210.conf:
agent: enabled=1
bios: ovmf
boot: order=scsi0
cores: 8
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
machine: pc-q35-11.0+pve2
memory: 16384
balloon: 0
name: win11-workstation
net0: virtio=BC:24:11:11:22:33,bridge=vmbr0
numa: 1
ostype: win11
scsi0: local-lvm:vm-210-disk-1,cache=writeback,discard=on,iothread=1,size=128G,ssd=1
scsihw: virtio-scsi-single
sockets: 1
tpmstate0: local-lvm:vm-210-disk-2,size=4M,version=v2.0
vmgenid: 1b2c3d4e-5f6a-7b8c-9d0e-1f2a3b4c5d6e
Fíjate en balloon: 0: en esta VM el ballooning está desactivado a propósito, que es lo razonable en una workstation Windows crítica.
cloudbase-init: cloud-init para Windows y sus trampas
En el capítulo 5 construyes plantillas Linux con cloud-init en siete comandos. Para Windows existe el equivalente, cloudbase-init, pero el camino es bastante más áspero.
Tres hechos que definen el terreno:
Uno. No hay imágenes cloud gratuitas de Windows. Con Debian o Ubuntu descargas un .qcow2 preparado y en dos minutos tienes plantilla. Con Windows tienes que instalar y configurar el huésped a mano, y luego generalizarlo con Sysprep.
Dos. No todas las funciones de cloud-init están disponibles en cloudbase-init, y algunas se comportan de forma distinta.
Tres. Requiere ostype de cualquier versión Windows y citype=configdrive2, que ya es el default cuando el ostype es Windows. No hace falta ponerlo a mano, pero sí verificar que el ostype está bien.
El flujo, una vez tienes el huésped preparado y generalizado:
qm set 9100 --ide2 local-lvm:cloudinit
qm template 9100
qm clone 9100 123 --name windows123
qm set 123 --cipassword <la-password-en-claro-que-quieres-fijar>
qm set 123 --ipconfig0 ip=10.0.10.123/24,gw=10.0.10.1
qm set 123 --sshkeys ~/.ssh/id_rsa.pub
Advertencia crítica: la documentación es explícita:
“Make sure that the
ostypeis set to any Windows version before setting the password. Otherwise the password will be encrypted and Cloudbase-Init will use the encrypted password as plaintext password.”
Si fijas cipassword cuando el ostype todavía era l26 u other, Proxmox cifra la contraseña y cloudbase-init la usará tal cual, como texto plano. El resultado es una VM cuya contraseña de administrador es un hash. Fija el ostype primero, siempre.
En el primer arranque el login no funcionará y la VM se reiniciará automáticamente por el cambio de hostname. Tras ese reinicio, la contraseña nueva ya está activa. No es un fallo, es el comportamiento esperado.
Opciones típicas de la configuración de cloudbase-init antes del Sysprep:
| Opción | Valor recomendado |
|---|---|
username | Nombre del administrador |
groups | Administrators |
inject_user_password | true (permite fijar la password desde la config de la VM) |
first_logon_behaviour | no (no exigir contraseña nueva al entrar) |
rename_admin_user | true |
metadata_services | cloudbaseinit.metadata.services.configdrive.ConfigDriveService |
allow_reboot | false para desactivar reinicios automáticos |
Si no restringes metadata_services al ConfigDriveService, cloudbase-init irá probando servicios de metadatos de otros proveedores cloud uno por uno y la configuración puede tardar minutos en cada arranque.
Hay dos ficheros de configuración: el que termina en -unattend.conf se usa en el paso de Sysprep y el principal en el paso regular. Para Windows Server el Unattend.xml provisto funciona directamente. Para las ediciones “normales” de Windows hay que habilitar la cuenta Administrator:
net user Administrator /active:yes
Instalar Cloudbase-Init con esa cuenta, y añadir al Unattend.xml:
<RunSynchronousCommand wcm:action="add">
<Path>net user administrator /active:yes</Path>
<Order>1</Order>
<Description>Enable Administrator User</Description>
</RunSynchronousCommand>
subiendo el <Order> del comando de Cloudbase-Init a 2. Solo en Windows 11 hay un paso extra antes del Sysprep:
Get-AppxPackage -AllUsers Microsoft.OneDriveSync | Remove-AppxPackage -AllUsers
Y finalmente, desde C:\Program Files\Cloudbase Solutions\Cloudbase-Init\conf:
C:\Windows\System32\Sysprep\sysprep.exe /generalize /oobe /unattend:Unattend.xml
La documentación de referencia de todas las opciones está en https://cloudbase-init.readthedocs.io/en/latest/config.html.
Errores comunes en huéspedes Windows y cómo se diagnostican
| Síntoma | Causa probable | Diagnóstico y solución |
|---|---|---|
| Windows no ve ningún disco durante la instalación | Falta el driver vioscsi (o viostor si usas VirtIO Block) | Load driver → vioscsi\w11\amd64; marcar “Include subfolders" |
| "No se encontraron drivers compatibles” al cargar desde el CD | ”Include subfolders” desmarcado | Volver a intentarlo con la casilla marcada |
qm shutdown se queda colgado hasta el timeout | agent: 1 en la config pero el QGA no está instalado o no corre | qm agent <vmid> ping; en Windows Get-Service QEMU-GA |
| Las IPs no aparecen en el panel Summary | Igual que arriba, o el agente no arrancó | qm guest cmd <vmid> network-get-interfaces |
El cambio de agent no surte efecto | Cambio pendiente de aplicar | ”A fresh start of the VM is necessary”: stop + start, o qm reboot |
| Puntero del ratón descolocado en la consola | agent activo sin el QGA instalado | Instalar guest-agent\qemu-ga-x86_64.msi |
| Ballooning no reduce memoria en Windows | Falta el driver Balloon, falta el servicio, o hay passthrough PCI(e) | BLNSVR.exe -i o virtio-win-gt-x64.msi. Con passthrough el ballooning no funciona |
| Errores de lectura en Windows Server 2025 con IO intensivo | virtio-win 0.1.285 | Downgrade a 0.1.271 |
| Backup en modo snapshot rompe los diferenciales de SQL Server | El freeze dispara el SQL Writer de VSS | Configurar otra variante de VSS en el QGA (preferido) o --agent enabled=1,freeze-fs=0 |
| Windows pide la clave de recuperación de BitLocker tras enrolar certificados | No se desactivaron los protectores | manage-bde -protectors -disable C: antes de enrolar |
| Secure Boot rechaza el bootloader después de junio de 2026 | El efidisk solo tiene los certificados de 2011 | qm enroll-efi-keys <vmid> con la VM apagada; comprobar ms-cert=2023k |
Quiero Secure Boot pero el efidisk es 2m | efitype=2m no lo soporta | Borrar y recrear con efitype=4m,pre-enrolled-keys=1; se pierde la config del menú OVMF |
| Windows 11 con VBS no arranca | Flags cet-ibt o cet-ss activados a mano | Están deshabilitados por defecto desde PVE 9.2; quítalos |
Windows 11/2022/2025 con cpu host y VBS se congela en host Intel | Bug conocido de 9.2 (Bugzilla #7825) | Fix en qemu-server 9.2.0 con machine version 11.0+pve2 o superior |
Hyper-V no arranca en Windows sobre Intel reciente con cpu=host | CPUID leaf demasiado alto | qm set <vmid> --cpu host,level=30 |
No se puede activar iothread en un disco SCSI | scsihw no es virtio-scsi-single | qm set <vmid> --scsihw virtio-scsi-single |
| Windows pierde la configuración de red tras cambiar la machine version | Cambia la enumeración de NICs | Es esperado; por eso Windows fija la machine version en la creación |
| Hot-plug de CPU no funciona | No está soportado en Windows | Solo Linux, kernel > 3.10 (> 4.7 recomendado) |
discard no libera espacio | Storage sin thin provisioning, o VirtIO Block en lugar de SCSI | Verificar el backend; usar scsi[n] con ssd=1 |
| Pantalla OVMF con resolución minúscula | Resolución no fijada en el firmware | Pulsar ESC en el arranque → menú OVMF → Device Manager; o usar display SPICE |
| PXE no funciona con OVMF | Falta dispositivo RNG | qm set <vmid> -rng0 source=/dev/urandom |
| Cloudbase-init usa la contraseña cifrada como texto plano | ostype no era Windows al fijar cipassword | Fijar ostype antes de cipassword |
| Queda un “Unknown device” en el Device Manager | Un driver individual sin instalar | Update driver apuntando al ISO virtio-win con subcarpetas incluidas |
Los comandos transversales de diagnóstico, los mismos que usas para cualquier VM:
qm showcmd 210 --pretty # la linea de comandos QEMU real que se ejecuta
qm config 210 --current 1 # la config aplicada, sin cambios pendientes
qm pending 210 # que cambios esperan un arranque en frio
qm agent 210 ping # el agente responde o no
journalctl -u pvedaemon -u pveproxy -u pvestatd -f
dmesg -T | tail -50
qm showcmd --pretty sigue siendo la herramienta número uno: muestra literalmente los argumentos con los que se lanza QEMU, incluidos el modo de caché, el aio, los iothread, la machine version y los flags de CPU efectivos. Si la GUI dice una cosa y la VM se comporta como otra, ahí está la verdad.
Checklist operativo de un huésped Windows
Antes de dar por buena una VM Windows en producción:
-
ostypecorrecto (win11,win10, etc.) y fijado antes de cualquiercipassword. -
machine q35ybios ovmf. -
efidisk0conefitype=4m,pre-enrolled-keys=1yms-cert=2023k. -
tpmstate0conversion=v2.0si es Windows 11. -
scsihw virtio-scsi-singley el disco enscsi0condiscard=on,ssd=1,iothread=1. -
net0con modelovirtio. -
agent enabled=1y el QGA instalado y corriendo dentro del huésped. - Sin “Unknown device” en el Device Manager.
- El panel Summary muestra RAM real e IPs.
- Decisión consciente sobre el ballooning: activado con
BLNSVRregistrado, oballoon: 0. - Si hay SQL Server: estrategia de backup decidida (VSS alternativo o
freeze-fs=0con backup lógico). - Versión de virtio-win comprobada, y no es 0.1.285 en un Server 2025 con IO intensivo.
Lo que queda funcionando
Con este capítulo tienes una VM Windows que arranca sobre hardware paravirtualizado de punta a punta: disco VirtIO SCSI con hilo de IO dedicado, red VirtIO, ballooning con su servicio registrado, guest agent respondiendo ping y reportando IPs, y un disco EFI con los certificados de 2023 enrolados que va a seguir arrancando después de junio de 2026. También sabes qué versión del ISO de drivers evitar y por qué un backup en modo snapshot puede romperte la cadena diferencial de SQL Server sin avisar.
Lo que no tienes todavía es una forma de repetir todo esto sin volver a hacer clic. Instalar Windows a mano una vez es aceptable; hacerlo veinte veces, no. En el capítulo 5 conviertes una VM en plantilla, la clonas en segundos con full clone o linked clone, la personalizas con cloud-init y aprendes qué storages soportan snapshots de verdad y cuáles te van a bloquear la VM durante horas mientras los crean.