Vagrant con libvirt: reproduce tu homelab antes de tocar produccion
Un homelab no se rompe el día que pruebas un cambio en producción; se rompe el día anterior, a las 2 de la mañana, cuando el DNS cacheado, el firewall heredado y la configuración de la base de datos ya están en producción y tú estás improvisando sobre el servidor real. La disciplina que evita esa madrugada es antigua y barata: reproducir el entorno completo en una máquina virtual descartable, hacer ahí el cambio, y cuando funcione, recién entonces tocar el servidor que importa.
Vagrant existe para eso, pero la mayoría de tutoriales te empujan a VirtualBox, que ya no es la ruta más limpia en Linux. vagrant-libvirt es el plugin que monta tus máquinas sobre KVM y libvirt, que es el mismo stack sobre el que corres tus servidores en casa. Este es el camino completo: instalar el stack, entender de verdad qué proveedor selecciona Vagrant y por qué, apuntar al catálogo de boxes correcto después del retiro de HCP Vagrant, y usar snapshots para volver atrás sin reconstruir nada.
TL;DR — Lo que vas a tener al final
- Tiempo de setup: Una sola vez, unos 40-55 minutos entre instalar el stack de virtualización, compilar las extensiones nativas de
ruby-libvirty el primervagrant upque descarga la caja; las máquinas siguientes levantan en segundos. - Requisitos: Debian 13, Fedora o Ubuntu con KVM habilitado (
/dev/kvmlegible), 8 GB de RAM libres yvagrant-libvirt0.12.2 - Resultado: un
Vagrantfileconconfig.vm.provider "libvirt"que crea máquinas con red privada y snapshots funcionales víavirsh - Troubleshooting: si
vagrant updice provider not found, no es VirtualBox: es que el plugin no quedó registrado en~/.vagrant.d
Instala el stack de virtualización antes de tocar Vagrant
Antes de instalar nada de Ruby conviene confirmar que el hipervisor funciona por sí solo. vagrant-libvirt no emula: habla con libvirtd mediante ruby-libvirt, y si el stack base está roto, el error que ves es un LoadError confuso que no tiene nada que ver con Vagrant.
En Debian y Ubuntu, estos son los paquetes que la documentación oficial del plugin indica: qemu, libvirt-daemon-system, libvirt-dev, ebtables y libguestfs-tools. El último no es opcional en la práctica: es el que permite que guestfs monte imágenes de disco para operaciones de sistema de archivos dentro de la máquina.
sudo apt-get update
sudo apt-get install -y qemu libvirt-daemon-system libvirt-dev ebtables libguestfs-tools
sudo systemctl enable --now libvirtd
sudo virsh list --all
El resultado esperado es una tabla vacía de dominios. Si virsh responde y no lista nada, el stack está arriba. Si responde con un error de conexión a qemu:///system, el problema es que libvirtd no está corriendo o tu usuario no tiene permisos sobre el socket.
Sobre esos permisos: libvirt usa grupos de Unix, no sudo por comando. Agrega tu usuario al grupo libvirt y abre una sesión nueva para que el cambio aplique.
sudo usermod -aG libvirt "$USER"
newgrp libvirt
id -nG | tr ' ' '\n' | grep -x libvirt
Y comprueba que la aceleración por hardware está disponible. En un servidor o una VM sin /dev/kvm, libvirt cae a emulación de software y una máquina que debería arrancar en 20 segundos tarda varios minutos.
ls -l /dev/kvm
grep -c -E 'vmx|svm' /proc/cpuinfo
Si el primer comando falla con No such file or directory, no hay KVM disponible y vas a medir el rendimiento de QEMU emulado, no de KVM. Configura la virtualización anidada en el BIOS o en las opciones de tu hipervisor antes de seguir.
Instala Vagrant y el plugin vagrant-libvirt
Aquí hay una decisión de distribución que conviene tomar con criterio, porque la versión de Vagrant que instales determina cómo se resuelven las URLs del catálogo de boxes.
Debian 13 (trixie) empaqueta vagrant en la versión 2.3.7+git20230731.5fc64cde+dfsg-3 y vagrant-libvirt en 0.12.2-4. Debian parchea el valor por defecto del servidor de boxes: en lugar de https://vagrantcloud.com, el paquete usa https://vagrantcloud.com/api/v2/vagrant. Ese detalle parece menor pero no lo es, y lo explico más abajo con el catálogo de AlmaLinux.
Hay dos caminos y cada uno tiene su razón. El camino Debian usa el paquete del sistema, que es más simple y evita problemas de linking entre el Ruby embebido de Vagrant y las extensiones nativas de ruby-libvirt:
sudo apt-get install -y vagrant ruby-fog-libvirt
vagrant --version
El camino upstream usa el repositorio oficial de HashiCorp y te da una versión bastante más nueva. La razón técnica es concreta: Vagrant embebido usa su propio Ruby, y las extensiones nativas de ruby-libvirt se compilan contra el Ruby del sistema, lo que produce errores de símbolos faltantes al cargar la biblioteca. Por eso la propia documentación de vagrant-libvirt recomienda el paquete de la distribución cuando existe.
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.asc
echo "deb [ signed-by=/usr/share/keyrings/hashicorp-archive-keyring.asc ] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt-get update
sudo apt-get install -y vagrant
vagrant --version
Si vas por el camino upstream, el plugin se compila contra tu Ruby, así que necesitas las dependencias de desarrollo que la documentación oficial lista para ese caso. Ten en cuenta que apt-get build-dep lee las fuentes de código, no los binarios: tienes que tener habilitado el repositorio deb-src correspondiente en tu sources.list.
sudo apt-get build-dep vagrant ruby-libvirt
sudo apt-get install -y qemu libvirt-daemon-system ebtables libguestfs-tools \
libxslt-dev libxml2-dev zlib1g-dev ruby-dev
vagrant plugin install vagrant-libvirt
El plugin se instala aparte en los dos caminos: vagrant-libvirt no viene incluido en Vagrant. Si ya tienes el paquete de Debian vagrant-libvirt instalado, la documentación oficial pide purgarlo primero para evitar el conflicto con el plugin compilado, y luego marcarlo para que apt no lo reinstale.
sudo apt-get purge vagrant-libvirt
sudo apt-mark hold vagrant-libvirt
sudo apt-get install -y vagrant ruby-fog-libvirt
vagrant plugin install vagrant-libvirt
vagrant plugin list
La salida de vagrant plugin list debe mostrar vagrant-libvirt. Si no aparece, el plugin no quedó registrado y todo lo que sigue fallará con errores poco descriptivos.
Un detalle que confunde mucho: la versión de vagrant-libvirt no cambia con la de Vagrant. La última release del plugin es 0.12.2, de junio de 2023, y sigue siendo esa en Debian 13 tres años después. Vagrant ya va por 2.4.9, publicada el 21 de agosto de 2025, y la 2.4.10 que circula en algunos artículos sigue en desarrollo, sin release estable. Lo vas a notar al fijar la combinación: vagrant-libvirt 0.12.2 declara compatibilidad con Vagrant 2.0, 2.1 y 2.2, y funciona con versiones anteriores desde 1.5 aunque sin pruebas activas. En la práctica funciona con 2.4.x, pero conviene probarlo en tu propio box antes de mentirle a tu equipo.
Entiende cuál proveedor selecciona Vagrant y por qué
Este es el punto donde la mayoría de los tutoriales se equivoca, y donde un sysadmin pierde una hora. Vagrant no tiene un proveedor predeterminado fijo. El mecanismo real funciona así: Vagrant recorre los proveedores registrados, descarta los que no son usable?, y entre los que quedan elige el de mayor prioridad.
Las prioridades están declaradas en el código fuente, no en la documentación. El proveedor VirtualBox declara priority: 6 y el plugin vagrant-libvirt deja el valor por defecto, que es 5.
vagrant plugin list
vagrant status
vagrant global-status
La consecuencia práctica es esta: VirtualBox gana por prioridad, pero solo si está instalado y es utilizable. Si VirtualBox no está en tu máquina, usable? devuelve falso, el proveedor se descarta del ciclo de selección y vagrant-libvirt queda como único candidato, aunque tenga prioridad menor.
Por eso la respuesta a la pregunta “¿Vagrant usa libvirt por defecto en Debian?” es matizada: no es que Debian configure libvirt como predeterminado. Es que Debian 13 no incluye VirtualBox en ninguna suite estable, ni en main ni en contrib, así que el único proveedor utilizable que queda es libvirt. En una máquina con VirtualBox instalado, seguirías-teniendo a VirtualBox por defecto aunque tengas el plugin de libvirt.
Esa es también la razón por la que el prefijo --provider=libvirt es buena práctica incluso en Debian. Deja la intención explícita y evita que el resultado cambie según qué instalaste en la máquina el mes pasado.
vagrant up --provider=libvirt
vagrant ssh -c 'uname -a; cat /etc/os-release | head -3'
También puedes fijar el proveedor por defecto para todo el proyecto, en el Vagrantfile, y eso es lo que yo hago en cualquier homelab que se vaya a replicar:
vagrant init almalinux/10
ls -la Vagrantfile
Y el bloque de configuración que le corresponde:
cat > Vagrantfile <<'EOF'
Vagrant.configure("2") do |config|
config.vm.box = "almalinux/10"
config.vm.hostname = "lab-app-01"
config.vm.provider "libvirt" do |libvirt|
libvirt.memory = 2048
libvirt.cpus = 2
end
config.vm.synced_folder ".", "/vagrant", disabled: true
end
EOF
vagrant validate
El parámetro libvirt.memory y libvirt.cpus existen en vagrant-libvirt 0.12.2, y vagrant validate revisa la sintaxis del Vagrantfile sin arrancar nada. Es el comando más barato del flujo: úsalo antes de cada up.
Apunta al catálogo de boxes correcto tras el retiro de HCP Vagrant
Si tu última vez que usaste Vagrant fue hace un año o dos, esto te va a tocar. HashiCorp está retirando HCP Vagrant, el servicio que hasta ahora alojaba los boxes públicos de Vagrant Cloud, con tres fechas en su aviso oficial de fin de vida:
| Hito | Fecha | Qué significa para ti |
|---|---|---|
| Fin de creación de boxes nuevos | 1 de octubre de 2026 | Ya no se pueden publicar versiones nuevas en HCP |
| Fin de soporte y mantenimiento | 2 de noviembre de 2026 | Los boxes publicados siguen ahí, pero sin backing de HashiCorp |
| Fin de operación del registro | 31 de diciembre de 2026 | El registro se apaga: vagrant box add deja de resolver nombres cortos |
La comunidad reaccionó con catálogos propios. AlmaLinux, que mantiene boxes almalinux/* en HCP desde 2021, publicó su catálogo propio el 2 de noviembre de 2026 en vagrant.almalinux.org, con las seis cajas que existían en HCP, el historial completo de versiones y las releases que se publicaron después del cierre, todo con verificación SHA-256 igual que antes.
El uso es el de siempre: defines la variable de entorno y usas los nombres cortos.
export VAGRANT_SERVER_URL=https://vagrant.almalinux.org
vagrant init almalinux/10
vagrant box add almalinux/9 --provider libvirt
Si prefieres que el proyecto sea autónomo, la variable de entorno se traduce a una línea en el Vagrantfile:
cat > Vagrantfile <<'EOF'
Vagrant.configure("2") do |config|
config.vm.box = "almalinux/9"
config.vm.box_server_url = "https://vagrant.almalinux.org"
end
EOF
Cuando están ambos definidos, la variable de entorno gana sobre el Vagrantfile, porque así está implementado Vagrant.server_url: primero lee VAGRANT_SERVER_URL y solo si está vacía recurre al valor de configuración. La segunda forma es la mejor para CI, porque sudo descarta las variables de entorno del usuario y un pipeline que corre sudo vagrant up perdería el puntero al catálogo.
Ahora la parte que casi nadie menciona y que te va a morder: un box que ya instalaste desde HCP sigue apuntando a HCP, aunque redefinas la variable de entorno. vagrant box outdated y vagrant box update van a reportarte que está al día cuando hay versiones nuevas en el catálogo, y van a fallar por completo cuando el registro se apague. La corrección es volver a agregar la caja con el catálogo activo y limpiar las versiones viejas:
export VAGRANT_SERVER_URL=https://vagrant.almalinux.org
vagrant box add almalinux/9 --provider libvirt
vagrant box prune --name almalinux/9
vagrant box list
Las máquinas que ya están corriendo no se ven afectadas: siguen usando la caja con la que se crearon.
Un detalle técnico que explica por qué el catálogo de AlmaLinux funciona con unas versiones de Vagrant y con otras no: en Vagrant 2.4.9, al agregar una caja con nombre corto, el código construye dos URLs candidatas, la ruta de API /api/v2/vagrant/ y la ruta directa, y se queda con la que responda metadata válido. En las versiones 2.3.x de Debian la construcción es de una sola URL, razón por la cual el parche 0013 de Debian ajusta el valor por defecto del servidor para incluir el prefijo /api/v2/vagrant. El catálogo de AlmaLinux expone la metadata en la ruta directa, y por eso funciona con ambas familias de Vagrant sin tocar una sola línea de código.
Usa snapshots para volver atrás sin reconstruir la máquina
Este es el retorno de inversión real de todo el montaje. Con vagrant-libvirt tienes snapshots de verdad, respaldados por las instantáneas de QEMU, y el comando vagrant snapshot forma parte del núcleo de Vagrant desde la serie 2.0. Eso significa que el mismo comando te sirve para snapshots de Vagrant y para los snapshots que ya hacías con virsh.
vagrant snapshot save antes-del-cambio
vagrant snapshot list
vagrant snapshot restore antes-del-cambio
El provider expone la capacidad de listado de snapshots, así que el comando de Vagrant delega en las instantáneas nativas de libvirt. Puedes verificarlo desde el stack de virtualización, y es buena idea porque te muestra el estado real:
virsh list --all
virsh snapshot-list NOMBRE_DE_LA_MAQUINA
virsh domiflist NOMBRE_DE_LA_MAQUINA
La convención que uso en el homelab es simple: snapshot antes de cada cambio de configuración, con el nombre del ticket o del cambio, no con un antes genérico. Cuando el cambio resulta bueno, el snapshot se borra; cuando sale mal, el rollback es un comando y no una tarde de rehacer todo.
vagrant snapshot delete antes-del-cambio
vagrant global-status
Para limpiar al final del ciclo, el comando de destrucción acepta -f para no pedir confirmación, y -g para un apagado ordenado en lugar de cortar la energía:
vagrant destroy -f
vagrant global-status
El ciclo completo de un cambio en tu homelab
Con todo lo anterior montado, el día a día se reduce a una secuencia que cabe en un rato. La reproduzco completa porque es la parte que te va a servir mañana.
export VAGRANT_SERVER_URL=https://vagrant.almalinux.org
vagrant init almalinux/9
vagrant up --provider=libvirt
vagrant ssh -c 'systemctl is-active firewalld; ss -tlnp | head -10'
Reproduces el stack real: las mismas reglas de firewall, el mismo DNS, el mismo esquema de base de datos. Aplicas el cambio, lo pruebas, y solo entonces lo llevas al servidor que importa.
vagrant snapshot save antes-del-cambio
vagrant ssh -c 'systemctl restart nginx; curl -sS -o /dev/null -w "%{http_code}" http://localhost/'
vagrant snapshot restore antes-del-cambio
vagrant ssh -c 'systemctl is-active nginx'
Y cuando la aplicación está estable en la máquina virtual, el artefacto que promoviste a producción se replica sin sorpresas. Ese es el ciclo completo, y funciona igual en un portátil, en un servidor con un hypervisor encima, o en un pipeline de CI que levante la misma imagen.
Errores que vas a ver y qué significan
La mayoría de los problemas de vagrant-libvirt se concentran en tres frentes. Vale la pena conocerlos antes de que aparezcan.
El provider no aparece. Si vagrant up se queja de que no encuentra el proveedor o de que libvirt no está instalado, el plugin no quedó registrado. Revisa vagrant plugin list antes de tocar nada más. En una máquina donde instalaste el paquete de Debian vagrant-libvirt y luego también el plugin desde Ruby, es el conflicto clásico: purga el paquete y deja solo uno de los dos.
Error de símbolos al cargar la biblioteca. LoadError con version 'OPENSSL_1_1_1b' not found o undefined symbol: EVP_KDF_ctrl significa que una biblioteca del sistema, libssh o libk5crypto, está enlazada contra una versión de OpenSSL distinta de la que usa el Ruby embebido de Vagrant. Es el problema característico de usar el Vagrant de upstream con su Ruby embebido. La solución no es pelear con variables de entorno: instala el Vagrant del sistema y deja que ruby-fog-libvirt se resuelva con las bibliotecas del sistema.
La caja no resuelve. Si vagrant box add falla con un error de catálogo, casi siempre es una de dos cosas: el nombre corto sin la variable VAGRANT_SERVER_URL apuntando al catálogo correcto, o una caja que instalaste antes desde HCP y que sigue apuntando ahí. La segunda se corrige con el ciclo box add más box prune --name que vimos arriba.
vagrant box list
vagrant box outdated
vagrant plugin list
vagrant --version
Y una nota sobre vagrant global-status: es el comando que te salva cuando tienes varios proyectos Vagrant abiertos en directorios distintos. Lista todas las máquinas que has creado, en qué estado están y dónde viven sus archivos, que es exactamente lo que necesitas saber antes de un destroy.
Preguntas frecuentes
¿Por qué Vagrant usa libvirt por defecto en Debian y no en otras distribuciones?
No es una configuración de Debian: es una consecuencia de que Debian 13 no incluye VirtualBox en ninguna suite estable. Vagrant descarta los proveedores no utilizables y entre los que quedan elige el de mayor prioridad, y VirtualBox tiene prioridad 6 contra el 5 de libvirt. Sin VirtualBox instalado, el único candidato queda y es libvirt. En una máquina con VirtualBox presente, ese sigue ganando.
¿Cuál es la diferencia real entre Vagrant 2.4.9 y vagrant-libvirt 0.12.2?
Son dos proyectos separados con ciclos de release distintos. Vagrant 2.4.9 salió el 21 de agosto de 2025 y es la última estable; la 2.4.10 aún no existe como release. El plugin vagrant-libvirt va en 0.12.2 desde junio de 2023 y no se actualiza al ritmo de Vagrant, algo normal porque un provider solo depende de la API de providers. Debian 13 empaqueta vagrant 2.3.7 y vagrant-libvirt 0.12.2-4.
¿Qué hago con las cajas que ya instalé antes de que HCP Vagrant cerrara?
Una caja agregada desde HCP conserva esa URL como origen de actualizaciones, sin importar que redefinas VAGRANT_SERVER_URL. Por eso vagrant box outdated la reporta al día y las operaciones de actualización fallarán cuando el registro se apague el 31 de diciembre de 2026. La corrección es agregar de nuevo la caja con el catálogo activo y limpiar las versiones antiguas con vagrant box prune --name.
¿Puedo usar snapshots de Vagrant con el provider libvirt?
Sí. vagrant-libvirt implementa la capacidad de snapshots y expone las acciones de guardado, restauración y borrado, así que el comando vagrant snapshot del núcleo de Vagrant delega en las instantáneas nativas de QEMU. El comando snapshot existe en el núcleo desde la serie 2.0 y funciona con los providers que implementan esa capacidad, como libvirt. Verificables con virsh snapshot-list.
¿Qué licencia tiene Vagrant y puedo usarlo en mi empresa?
Depende de la versión. El release 2.4.9 que se descarga hoy se distribuye bajo Business Source License 1.1, con HashiCorp Inc. como licenciador. Pero la rama main del repositorio revirtió ese cambio el 2 de noviembre de 2026 y volvió a MIT, así que la próxima release debería llegar bajo MIT. El paquete de Debian 13 es anterior al cambio a BSL. Verifica la licencia del artefacto que vas a desplegar.
