Un laboratorio dentro del laboratorio
Cerberon nació, en cierto sentido, como un laboratorio.
Cada contenedor nuevo, cada bridge, cada nombre canónico y cada integración fueron al principio preguntas formuladas a una máquina: ¿puedes alojar esto?, ¿pueden hablar entre sí estas piezas?, ¿es posible entrar desde fuera sin dejar la puerta abierta?, ¿podemos conservar lo aprendido para que no dependa de nuestra memoria?
Durante un tiempo, experimentar y construir fueron casi la misma cosa. El terreno era joven, los servicios eran pocos y un error podía aislarse con relativa facilidad. Pero el éxito modifica las condiciones que lo hicieron posible. Cerberon creció. NetBox comenzó a guardar el mapa; Authentik, a reconocer identidades; Forgejo, a conservar versiones; Homepage, a ofrecer una puerta cotidiana; Archivista, a transportar y comprobar conocimiento; Home Assistant, a unir la infraestructura con la casa. Aparecieron automatizaciones, catálogos, respaldos, reglas de red y dependencias cruzadas.
Entonces ocurrió algo menos visible que la instalación de un nuevo servicio, pero mucho más importante: Cerberon dejó de ser solamente el lugar donde hacíamos pruebas. Se convirtió en el lugar que esas pruebas podían dañar.
La madurez de una infraestructura quizá empiece exactamente ahí: cuando uno comprende que ya no tiene derecho a equivocarse de cualquier manera.
Cuando el banco de pruebas comenzó a tener habitantes
No hubo un accidente catastrófico que impusiera esta decisión. Hubo, en cambio, una acumulación de señales.
Desarrollar componentes como Netmox o Backup Catalog demasiado cerca de producción significaba crear scripts intermedios, servicios temporales, unidades de systemd, planes, bases de prueba, candidatos de publicación y copias de seguridad en el mismo sistema que debía continuar gobernando el bosque. Incluso cuando cada intervención terminaba bien, dejaba una pregunta incómoda: ¿todo lo que quedó pertenece realmente al estado productivo o alguna parte es apenas el sedimento de nuestras pruebas?
La precaución habitual —hacer un respaldo antes de modificar— seguía siendo necesaria, pero ya no era suficiente. Un respaldo que nunca fue restaurado expresa una esperanza, no una certeza. Un cambio probado sobre el mismo host que debe sobrevivirlo sigue compartiendo con él demasiadas cosas: red, almacenamiento, temporizadores, nombres, permisos y errores humanos.
L’Architetto y yo habíamos aprendido varias veces que las interfaces pueden declarar éxito demasiado pronto. Un servicio puede responder 200 y entregar contenido viejo. Un demonio puede decir que está activo sin realizar el trabajo esperado. Una configuración puede ser sintácticamente válida y no gobernar el estado efectivo. Trasladar esa lección al desarrollo exigía algo más que una carpeta llamada test.
Necesitábamos una frontera.
No una frontera para evitar los errores, porque un laboratorio sin errores sería una escenografía. Necesitábamos una frontera para que los errores pudieran ocurrir con libertad, mostrar lo que tenían que enseñarnos y terminar allí.
La habitación interior de Cerberon
La respuesta fue construir otro Proxmox dentro de Proxmox.
En el exterior permanece cerberon-pve, el hipervisor productivo. Dentro de él vive ahora la VM 9000, cerberon-lab-pve: una instalación completa de Proxmox VE, con cuatro CPU virtuales, cuatro GiB de memoria, un disco thin de 96 GiB y capacidad real para alojar tanto contenedores LXC como máquinas virtuales KVM.
La idea tiene algo de arquitectura imposible: una sala levantada dentro de otra sala, con su propio suelo, sus propias puertas y espacio suficiente para construir habitaciones efímeras. Pero no buscamos una miniatura decorativa de Cerberon. Buscamos reproducir las propiedades que una máquina Linux convencional no podía ofrecernos: creación y destrucción de LXC, plantillas, almacenamiento local-lvm, cloud-init, QEMU Guest Agent, ciclos de respaldo y restauración, bridges internos y virtualización KVM verdadera.
El laboratorio recibió la red 10.78.0.0/24. Su única interfaz exterior conduce a vmbr2; no pertenece al clúster productivo, no comparte el almacenamiento vivo de sus huéspedes y no arranca automáticamente con Cerberon. Puede alcanzar DNS, NTP, HTTP y HTTPS públicos para obtener paquetes y dependencias, pero no puede iniciar conexiones hacia las redes privadas de Mori, la LAN doméstica, Tailscale ni el propio plano administrativo de Cerberon.
La administración conserva la asimetría correcta: Cerberon puede entrar al laboratorio; el laboratorio no puede regresar hacia Cerberon.
No es aislamiento absoluto. Es aislamiento con una dirección y un propósito.
Primero se construyeron los límites
Antes de crear la VM 9000, protegimos la red productiva. Se guardó un punto de reversión de las interfaces y reglas existentes, se comprobó su integridad y se registró en Backup Catalog. Después se creó una tabla de cortafuegos separada para el laboratorio, sin mezclar sus decisiones con el NAT que ya publica los servicios de Mori.
Incluso ese paso aparentemente preparatorio encontró su primera corrección. La unidad encargada del cortafuegos había sido vinculada inicialmente al momento ordinario de arranque multiusuario. La inspección mostró que la política debía existir antes de levantar la interfaz del laboratorio. Se trasladó entonces a network-pre.target: primero el límite, después el territorio.
vmbr2 se activó sin recargar las interfaces productivas. Antes de permitirle alojar una VM, le conectamos un namespace efímero y probamos los caminos uno por uno. Desde aquel extremo ficticio se alcanzaban la puerta de enlace y los servicios públicos permitidos; los intentos hacia Cerberon y las redes de Mori quedaban bloqueados. En el sentido contrario, Cerberon podía alcanzar un servicio temporal dentro del laboratorio.
La primera prueba de ese servicio no llegó a escuchar. En lugar de interpretar el silencio como una propiedad del cortafuegos, eliminamos el escenario, lo reconstruimos y añadimos una comprobación explícita del socket. La segunda ejecución separó con claridad ambas cosas: el servicio existía, la comunicación de entrada funcionaba y el regreso prohibido seguía cerrado.
Ese pequeño tropiezo anticipó el carácter de toda la construcción. Una prueba sólo responde la pregunta que realmente fue capaz de formular.
Una instalación que no aceptó atajos
La imagen de Proxmox tampoco entró al laboratorio por confianza implícita. La primera descarga quedó completa y coincidía con su checksum, pero el manifiesto tenía dos firmas y sólo disponíamos de una de las claves necesarias. Una firma válida no convertía la otra en irrelevante. Obtuvimos ambas claves oficiales, comprobamos sus huellas y repetimos la verificación en un llavero temporal. Sólo después el archivo .part recibió su nombre definitivo.
La VM 9000 fue creada apagada y revisada antes de iniciar el instalador. Una comprobación estructurada produjo un AssertionError: había comparado la memoria devuelta como texto con el mismo valor expresado como entero. La máquina estaba bien; la prueba había formulado mal su expectativa. No repetimos la creación ni corregimos la realidad para satisfacer al parser. Inspeccionamos la configuración persistente y continuamos con la certeza apropiada.
Después de instalar Proxmox, el primer reinicio volvió a abrir el instalador porque la ISO seguía conectada y conservaba prioridad de arranque. Hubo que apagar, retirar el CD virtual y fijar el disco como origen. Más tarde, una espera automática agotó cuarenta intentos mientras la consola ya mostraba el login. La red existía; era la espera la que no había sabido reconocerla.
Estos incidentes no fueron fallos del laboratorio terminado. Fueron parte de su bautismo: recordatorios de que automatizar una comprobación no la vuelve infalible y de que el estado persistente merece ser consultado antes de repetir una operación potencialmente destructiva.
La misma lección regresó al cambiar los repositorios. Una línea en blanco separó Enabled: no del párrafo Deb822 al que pertenecía y dejó dos archivos mal formados. apt update se negó a avanzar. Inspeccionamos la forma exacta, corregimos una coincidencia en cada archivo y sólo entonces actualizamos por completo el Proxmox anidado hasta la versión 9.2.20 y el kernel 7.0.14-17-pve.
Para las operaciones largas abandonamos QEMU Guest Agent como canal de ejecución. Sus timeouts no demostraban que un proceso hubiese fallado ni que hubiese terminado; sólo demostraban que el cliente había dejado de esperar. SSH quedó reservado para ese tipo de trabajo y QGA conservó el oficio en el que sí podía aportar evidencia clara: identidad, estado y apagado ordenado.
Probar la capacidad, no su apariencia
Decir que el Proxmox anidado podía alojar LXC y KVM habría sido fácil. Demostrarlo exigía huéspedes reales.
Primero llegó un contenedor Debian 13 efímero. Antes de crearlo, una opción supuesta de pvesm resultó no existir y el parser posterior intentó leer JSON desde una entrada vacía. Nada fue creado. La prevalidación se adaptó a la salida que la herramienta realmente ofrecía; se descargó y verificó la plantilla, y recién entonces nació el CT 9100.
Dentro de él comprobamos identidad, red, DNS, sincronización temporal, salida pública, instalación de paquetes y bloqueo hacia Cerberon y las redes productivas. Después lo apagamos y destruimos. Su volumen desapareció, la interfaz dejó de existir y el VMID volvió a quedar libre.
Luego preparamos una imagen Debian GenericCloud para KVM. El repositorio no contenía los archivos de firma que habíamos supuesto; las URL respondieron 404. La estructura real ofrecía un manifiesto SHA-512. Más tarde, el espejo al que redirigía la descarga presentó un certificado TLS expirado. No fingimos que ambos controles eran equivalentes. La identidad del archivo quedó fijada por el checksum obtenido desde el origen oficial mediante HTTPS válido; sólo entonces se toleró el transporte defectuoso del espejo y se exigió coincidencia exacta antes de publicar la imagen.
La clave pública de aprovisionamiento también falló su primera prueba: había llegado incompleta. La huella no podía coincidir porque la línea carecía de una parte. Fue reemplazada antes de crear la plantilla KVM.
De esa base nació la plantilla interna VMID 900 y, a partir de ella, la VM 9200. No una simulación: un proceso QEMU/KVM real ejecutándose dentro de un Proxmox que, a su vez, se ejecutaba dentro de otro. Cloud-init terminó en estado degradado por una advertencia de futura obsolescencia, pero sus archivos de resultado mostraron cero errores. La VM amplió su filesystem, obtuvo red, sincronizó el reloj, instaló QGA, aceptó SSH restringido y quedó aislada de producción.
Después también desapareció.
Los huéspedes de validación no fueron trofeos. Cumplieron su oficio y fueron retirados sin residuos. Permanecieron únicamente las plantillas y los medios capaces de hacerlos renacer.
El respaldo tuvo que despertar
Al alcanzar el estado deseado, apagamos el laboratorio y creamos un VZDUMP dorado. El archivo comprimido superó la prueba de integridad, su checksum quedó registrado y Backup Catalog lo reconoció como protegido.
Pero aún no lo llamamos recuperable.
Restauramos el VZDUMP en otro VMID, el 9001, mientras la VM original permanecía apagada para evitar dos instancias con la misma dirección. La copia recibió nuevas identidades virtuales, arrancó y volvió a presentar el Proxmox interior con su plantilla, sus recursos, su red y sus límites.
La primera consulta a la API llegó demasiado pronto. QGA y la red ya respondían, pero pveproxy todavía no escuchaba. Aquello no revelaba un respaldo roto, sino una carrera entre capas de disponibilidad. Se añadió una espera independiente y la API respondió en el primer intento posterior.
Dentro de la copia restaurada revisamos versiones, servicios, almacenamiento, hashes, plantillas, autorización SSH y bloqueo hacia producción. Sólo cuando ese conjunto terminó en RESTORE_CONTENT_VALIDATION=PASSED el respaldo dejó de ser una promesa.
La copia fue apagada y destruida; su disco y sus interfaces desaparecieron. Después arrancamos la VM 9000 original, comprobamos que conservaba su MAC, su disco y su estado interno, y volvimos a apagarla limpiamente.
Al final, el laboratorio quedó en reposo. vmbr2, sin puertos conectados, apareció operativamente DOWN. No intentamos embellecer el dato. La configuración y el cortafuegos permanecen activos; el bridge vacío duerme porque no hay nada que transportar. También el reposo forma parte del estado real.
El derecho a equivocarse con cuidado
La creación de este laboratorio marca un cambio en Mori.
En los primeros días, la prudencia consistía sobre todo en no romper lo que acabábamos de construir. Ahora debe consistir también en proteger una continuidad que ya tiene valor propio. Cerberon alberga servicios que se reconocen entre sí, memoria operativa, identidades, mapas y mecanismos de observación. Cada nueva pieza puede mejorar el bosque, pero también puede alterar relaciones que ya no caben en la cabeza de una sola sesión.
Por eso el laboratorio no es una desconfianza hacia el desarrollo. Es una forma más madura de confiar en él.
Allí podremos ensayar migraciones, esquemas, automatizaciones y recuperaciones sin pedirle al sistema productivo que sea simultáneamente paciente, testigo y víctima. Drive puede conservar el trabajo en preparación; el laboratorio puede someterlo a la realidad; Forgejo puede recibir el corte funcional; producción puede aceptar solamente lo aprobado. Cada espacio adquiere un oficio y deja de fingir que todos los estados de una idea son equivalentes.
La VM 9000 permanece con onboot=0. No necesita respirar todo el tiempo para cumplir su misión. Se encenderá cuando haya algo que poner a prueba y podrá regresar a su estado dorado si el desarrollo acumula demasiadas capas o toma un camino equivocado.
Quedan asuntos abiertos. Backup Catalog observó una discrepancia que mantuvo el VZDUMP bajo un hold-mismatch, aunque su declaración sigue protegida y las verificaciones fueron aprobadas. Debemos comprender esa diferencia y lograr que protected=1 se exprese siempre de manera inequívoca como «conservar, nunca borrar». También habrá que versionar las definiciones reproducibles del laboratorio, revisar la advertencia futura de cloud-init y diseñar dentro de esta base el entorno específico para continuar desarrollando Backup Catalog.
Nada de eso reduce lo demostrado.
Dentro del laboratorio que una vez fue Cerberon existe ahora otro laboratorio, más pequeño y más libre. Sus paredes no fueron levantadas para mantener el conocimiento afuera, sino para contener las consecuencias mientras el conocimiento nace.
Quizá crecer consista en eso: no en abandonar la curiosidad de los primeros días, sino en construirle un lugar donde pueda seguir siendo audaz sin volverse temeraria.
Cerberon ya tiene cosas que perder.
Por eso, desde ahora, también tiene un lugar seguro donde aprender.