I am Lino
4 de agosto de 2026

Cómo me monté mi propia nube personal

Publicado el 4 de agosto de 2026  •  23 minutos  • 4747 palabras
Table of contents

Dicen que la nube es el futuro. Yo llevo años diciéndoselo a otros para ganarme la vida.

Dado que soy arquitecto de soluciones, diseño infraestructuras en la nube, las defiendo en comités de arquitectura, y las uso a diario en varios proyectos personales sin ningún conflicto existencial con ello. No he venido a declararle la guerra a AWS, Azure ni a nadie. Esto no es esa clase de artículo, por mucho que el titular invite a pensarlo.

Lo que sí he hecho es montar, durante mis cortas vacaciones de verano, y en un cajón de Ikea en el salón de mi casa, un clúster de seis nodos con IA local ejecutándose encima, con GPU propia, base de datos propia, DNS propio y hasta entidad certificadora propia.

Y la pregunta, para alguien que cobra por recomendar la nube a terceros, es: ¿para qué?

La respuesta corta es dinero: tener modelos de lenguaje ejecutándose en mi propia GPU me ahorra una parte nada desdeñable de lo que gasto en herramientas como Claude Code o GitHub Copilot. Eso lo justifica en una hoja de cálculo y podría ser una razón válida para un contable, pero no es el motivo real por el que existe este proyecto.

El motivo real es que se aprende de una manera completamente distinta cuando instalas, rompes y arreglas tú mismo un sistema, que cuando lo consumes ya resuelto detrás de un API Gateway. La nube, y esto lo digo desde dentro del oficio, no como reproche externo, está diseñada precisamente para que no tengas que entender lo que hay debajo. Eso es una ventaja de producto brutal para quien solo quiere resolver un problema de negocio. Y es, al mismo tiempo, el mayor freno al aprendizaje real que existe hoy en este sector.

Cuando montas tu propio servidor de inferencia, tienes que decidir tú cuánta VRAM reservar y por qué. Cuando tu propio DNS se cae, aprendes de redes lo que ningún curso online te va a enseñar, porque el proveedor cloud ya te ha simplificado esa capa hasta dejarla en un checkbox. Aprendo cómo se instala, se administra y se afina un sistema de IA real, no solo cómo se le manda un prompt. Aprendo, a bajo nivel, cómo funcionan de verdad los modelos que uso cada día.

Y puedo montar benchmarks y comparativas serias, en hardware controlado por mí de principio a fin, sin la variable oculta de “qué está haciendo por debajo el hipervisor de otro” contaminando cada resultado.

Y como el propio clúster ya trae de serie las piezas de apoyo que hacen falta para experimentar en condiciones (NAS, bases de datos, observabilidad, redes internas), cada nuevo laboratorio que monto encima no empieza de cero: reutiliza toda esa base y me deja centrarme de verdad en lo que quiero evaluar, no en volver a levantar el andamiaje cada vez.

Esto tampoco es solo para mi propio beneficio, aunque suene a excusa bonita. Cada vez que monto uno de estos laboratorios (explorando, explotando y comparando tecnologías que en muchos casos yo mismo conocía poco de antemano) termino casi siempre escribiendo uno o varios artículos contando qué encontré, con datos reales encima de la mesa, y una opinión formada, no prestada, sobre para qué sirve de verdad cada tecnología y para qué no.

Este artículo es la primera pieza de esa serie: la historia de por qué existe homelab-cluster, las decisiones que tomé para levantarlo sin que fuera un caos de cables y contenedores sueltos, y una selección con mucho cariño de los incidentes, la mayoría autoinfligidos, que tuve que resolver por el camino.

Seis nodos, un cerebro, y cero Kubernetes

Hace algo más de un año, cuando el precio de las Raspberry Pi era razonable todavía, se me ocurrió que podría hacerme con un par o dos de estos cacharros y montarme un clúster de Kubernetes “ligero” con k3s, para trastear con ello y de paso montarme algo útil.

Lo hice, lo arranqué, funcionó y recibí mi primera dosis de realidad: para un clúster que administra una sola persona en su tiempo libre, meter un orquestador pensado para equipos de plataforma enteros es como comprarse un tráiler para llevar la compra del supermercado; técnicamente puedes, pero vivirás peor.

Kubernetes no solo se quedaba para él solito uno de mis nodos del clúster, para dar servicio al Control Plane, sino que el resto de los nodos ejecutaban el agente de k8s y se quedaban bajo el control del maestro, en espera de que sucediesen cosas, que aumentase la carga para levantar pods y etcétera, etcétera. Eso está muy bien si tienes cientos de miles de usuarios, escala que da gusto.

Pero en mi clúster estoy solo yo, y a veces uno de mis gatos pisando el teclado. Entre la falta de usuarios y que perdía el contacto directo con mi “hierro”, algo que causa escalofríos a un maniático del control como yo, la cosa no cuajó.

En su lugar, decidí que cada nodo tuviera su propio docker-compose.yml independiente, y gestionado a mano (con un puñado de scripts propios) por SSH. Sin una capa mágica de orquestación intentando adivinar qué quería decir yo. Si algo se rompe, sé exactamente en qué máquina mirar.

El reparto final quedó así:

Cuatro Raspberry Pi 5, dos PC, y un NAS (“ketekasko”) que se sumó después para el almacenamiento serio.

Nada de nube ajena, todo en un rincón de mi casa, y todo hablando entre sí por una red que yo controlo de punta a punta (más o menos).

Radiografía del clúster: qué hace cada servicio y por qué importa

Los nodos ya están contados. Lo que todavía no he enseñado es el plano de servicio, el que explica de verdad cómo se habla el clúster consigo mismo, quién confía en quién y qué se rompe primero si algo falla:

Topología del clúster: seis nodos y un NAS, todo el tráfico pasando por pi-dns

Empiezo por la puerta de entrada, porque todo lo demás depende de ella. nginx es el único punto por el que entra tráfico HTTPS al clúster desde cualquier *.home.arpa (no hay atajos, ni siquiera para mí).

Antes de dejar pasar una petición hacia un servicio que no sabe autenticarse solo (Ollama, vLLM, ComfyUI, Whisper, markitdown, el scraper), nginx le pregunta primero a apikey-service, un microservicio propio que solo hace una cosa: decir sí o no a una clave. Sin esa clave válida, la petición ni siquiera llega a tocar el servicio real. Es la diferencia entre “cualquiera en mi LAN puede hablarle a mi GPU” y “solo quien yo autorice puede hacerlo”, para un puñado de herramientas que nacieron sin pensar lo más mínimo en seguridad multiusuario.

Justo al lado, en el mismo nodo, vive el DNS: Pi-hole resuelve todos los nombres *.home.arpa del clúster (y de paso bloquea publicidad en toda la casa), y cuando la consulta no es interna se la pasa a Unbound, que hace la resolución recursiva de verdad contra internet. Los dos juntos son el motivo por el que puedo escribir https://grafana.home.arpa en vez de memorizar media docena de IPs, y también, como te contaré después, el motivo del único ataque de denegación de servicio que me he hecho a mí mismo.

Para entrar desde fuera de casa sin abrir un solo puerto en el router, Tailscale hace de router de subred: cualquier dispositivo autenticado en mi tailnet llega a 192.168.1.0/24 como si estuviera en el salón, con DNS dividido para que solo las consultas de home.arpa viajen por el túnel.

Una vez dentro, el tráfico se reparte entre familias de servicios bastante distintas entre sí.

La capa de datos: postgres-main, un único PostgreSQL multiinquilino donde n8n, SonarQube y el propio apikey-service tienen cada uno su base aislada, y Qdrant, la base vectorial que indexa todo lo que el pipeline de contenido convierte a embeddings, para poder hacer RAG de verdad y no inventarse las respuestas.

La capa de inferencia: Ollama y vLLM sirven modelos de lenguaje (nunca a la vez, se turnan la misma GPU), mientras whisper-service transcribe audio y ComfyUI genera imágenes.

La capa de ingesta: RSSHub trae artículos, markitdown-service los convierte a Markdown limpio, crawl4ai-scraper-service hace lo mismo con páginas web completas cuando el RSS no basta, y n8n es el pegamento que conecta unos con otros sin que yo tenga que tocar código cada vez que quiero automatizar algo nuevo.

Y luego está la capa que no produce nada “de cara al público” pero sin la que estaría volando a ciegas: Prometheus recoge métricas de los seis nodos, Grafana las convierte en paneles que de verdad miro, Loki y Tempo guardan registros y trazas, y SonarQube audita la calidad del código de mis propios microservicios antes de que la audite yo mismo a gritos en producción.

Vaultwarden guarda cada contraseña y token que generan todos los servicios anteriores (es, sin exagerar, el servicio más importante de todo el clúster, porque si se pierde, se pierde con él el acceso a todo lo demás). Y Portainer me deja ver y operar el Docker de los seis nodos desde un único panel, sin tener que recordar en cuál de ellos vive cada contenedor.

Ninguno de estos servicios es imprescindible por sí solo. Lo que los hace importantes es la cadena: sin DNS no hay nombres, sin nginx no hay entrada, sin apikey-service no hay control de quién pasa, y sin todo lo demás, tampoco hay gran cosa que proteger.

Cuando algo puede ir mal …

Sobre el papel, todo lo anterior suena limpio, casi elegante: seis nodos, cada uno con su función clara, un diagrama bonito que hasta yo me creía mientras lo dibujaba en un cacho de papel, antes de tocar un solo cable de verdad.

La realidad tuvo otras ideas, como suele pasar.

Instalé el clúster por partes, con la confianza tranquila de quien lleva años diseñando sistemas para que los operen otros, y en cuestión de horas descubrí (por las malas, y más o menos en este orden) que mi propio robot doméstico era capaz de atacarme a mí mismo, que “instalar un certificado una sola vez” es una frase que ningún ingeniero debería pronunciar sin cruzar los dedos, que mi tarjeta gráfica tenía menos memoria de la que ponía en la caja, que la Unión Europea había escondido un interruptor dentro de mi propia placa base, que un cargador de móvil corriente casi me deja sin DNS para todo el clúster, y que, después de años recomendándole a otros que versionaran su código, se me había olvidado hacer git init en el mío.

Nada de esto fue culpa del diseño sobre el papel. Todo fue culpa del hardware real, de mí mismo, o de algún componente de software que decidió, por su cuenta, reinventar una rueda que ya funcionaba perfectamente bien sin él.

Pánico vs Tiempo

El orden de instalación que nadie te cuenta hasta que ya la has liado

Cuando diseñé el clúster sobre el papel, di por hecho que pi-dns, que es el nodo que hace de puerta de entrada para todo lo demás, debía instalarse el primero.

Tiene sentido: es la puerta, ¿no? Pues no.

Resulta que pi-dns aloja un servicio propio, apikey-service, que emite y valida las claves de acceso de todo lo que no tiene autenticación nativa. Y ese servicio necesita conectarse a una base de datos que vive en retaco. Y nginx, en el propio pi-dns, no arranca hasta que apikey-service está sano.

Así que si instalas pi-dns antes que retaco, tu flamante puerta de entrada se queda tocando el timbre de una casa vacía, reintentando la conexión en bucle hasta que el resto del clúster decide aparecer.

No es un fallo grave, se autocorrige solo en cuanto retaco arranca, pero es exactamente el tipo de sorpresa que quieres detectar en tu documentación y no en mitad de una reinstalación de madrugada. Así que reordené toda la documentación del proyecto para que el número de cada guía coincidiera con el orden real de dependencias, no con el orden en que a mí se me había ocurrido escribirlas.

Una tontería de nada que me ahorra, cada vez que tengo que reconstruir algo desde cero, la sensación de estar leyendo instrucciones de IKEA traducidas por alguien que nunca ha visto un mueble.

353 requests por segundo: cuando mi propio robot me hizo un ataque a mí mismo

Este es mi incidente favorito, porque tiene ese regusto especial de las meteduras de pata que uno mismo se ha buscado con sus propias acciones.

Monté un flujo de trabajo en n8n llamado, con toda la inocencia del mundo, “RSS Fetch & Store”. Su trabajo era ir recogiendo artículos de decenas de fuentes RSS, convertirlos a Markdown y guardarlos indexados.

Un día lo ejecuté y, minutos después, retaco, el nodo donde vive ese flujo, dejó de poder resolver postgresql.home.arpa, que es justo el nombre interno que usa para hablar con su propia base de datos.

El diagnóstico fue tan divertido de reconstruir como incómodo de aceptar: el flujo intentaba resolver decenas de dominios de golpe (raw.githubusercontent.com, huggingface.co, openai.com, medio internet técnico junto) prácticamente en el mismo instante.

El resultado, contado por los propios registros de Pi-hole, fue 353 consultas DNS desde un único nodo en un único segundo. Unbound, que es quien hace la resolución recursiva de verdad en una Raspberry Pi con recursos limitados, no dio abasto. Alguna consulta se retrasó lo suficiente como para que systemd-resolved la diera por fallida y decidiera, muy a su manera, quedarse pegado para siempre al DNS de reserva (que por supuesto no sabe nada de mi red interna).

Había montado un robot cuya única misión era leer noticias tranquilamente, y ese robot, sin mala intención, me hizo lo más parecido a un ataque de denegación de servicio contra mi propio DNS. Contra mí mismo. En mi propia casa.

La solución rápida fue subir el número de hilos de Unbound de 4 a 8, para que absorbiera mejor los picos de consultas simultáneas. La solución de fondo (limitar cuántas peticiones lanza el flujo a la vez) sigue pendiente, apuntada en mi lista de tareas con la etiqueta mental de “cosas que un robot bien educado no debería necesitar que le expliques dos veces”.

La confianza es una ilusión que hay que instalar como cinco veces

Como *.home.arpa no es un dominio público, monté mi propia entidad certificadora interna para que todos los servicios hablaran HTTPS sin que el navegador me recibiera cada día con la cara de susto de “esta conexión no es privada”. Instalas el certificado de esa entidad una vez en cada dispositivo y listo, ya confías para siempre en cualquier servicio nuevo que añada. Bonita teoría.

La práctica es que cada lenguaje de programación y cada motor de contenedores ha decidido, de forma completamente independiente, que necesita su propio almacén de confianza, como si fueran adolescentes que se niegan a compartir el mando de la tele.

El sistema operativo tiene el suyo. Chrome tiene el suyo, aparte, con su propia base de datos NSS. Firefox pasa de los dos anteriores y tiene un tercero.

Node.js, y por tanto n8n, ignora por completo el almacén del sistema operativo para sus propias peticiones salientes, así que tuve que indicarle la CA a mano con una variable de entorno específica. Python, a través de la librería requests, tampoco mira el almacén del sistema: usa el paquete certifi, así que hubo que apuntarle explícitamente el fichero de certificados o se negaba en redondo con un error de verificación. Y el colmo: el contenedor de BuildKit que uso para construir imágenes multiplataforma vive en su propio universo, sin heredar absolutamente nada del host, así que tuve que copiar el certificado a mano dentro de ese contenedor y reiniciarlo para que el push al registro privado dejara de fallar con un “certificado firmado por una autoridad desconocida”.

CA

Cinco capas de software distintas. Cinco sitios distintos donde instalar el mismo certificado. Nadie te avisa de que “instalar la CA una vez” es, en realidad, una promesa que se rompe la primera vez que tocas algo que no sea un navegador.

Mi tarjeta gráfica comparte cerebro con mi escritorio (y otros líos de VRAM)

El nodo ryzen tiene dos GPU: una RTX 5070 de 12 GB y una RTX 3070 de 8 GB. Sobre el papel, generosas. En la práctica, la 5070 es también la que tiene el monitor enchufado, porque ese equipo es a la vez mi puesto de trabajo, y el simple hecho de tener el escritorio abierto le roba a la GPU unos 2,5 GB de manera permanente. De doce GB nominales pasas a tener, en la práctica, unos nueve reales.

GPU vs Memory

Eso no se nota hasta que intentas cargar un modelo con vLLM pensado para ocupar el 90% de la memoria disponible y el proceso revienta a mitad de carga con un torch.OutOfMemoryError, porque el 90% de “doce” y el 90% de “nueve” son números muy distintos. Tuve que bajar ese porcentaje a un valor más conservador y, mientras no mueva físicamente el cable del monitor a la otra tarjeta, quedarme con un modelo algo más ligero por defecto en vez del que realmente quería usar.

Y por si fuera poco, en la otra GPU, la 3070, tuve un segundo susto: el servicio de transcripción de audio tenía configurado “usar cualquier GPU disponible” en vez de fijar una en concreto, así que CUDA elegía por su cuenta la GPU 0 (la misma que ya estaba ocupada por vLLM) y los dos servicios acababan compitiendo por la tarjeta equivocada. La solución fue decirle a cada servicio con nombre y apellido a qué GPU tiene que ir, sin dejarle margen de improvisación a nadie.

El interruptor que Asus escondió detrás de una ley europea

Quería poder apagar ryzen por la noche para ahorrar energía y encenderlo remotamente cuando lo necesitara, así que me puse a configurar Wake-on-LAN. Activé el ajuste correspondiente en Linux sin ningún problema. Entré en la BIOS para hacer lo propio del lado del firmware y… la opción de Wake-on-LAN no existía. No estaba desactivada: no aparecía en ningún sitio del menú, como si la placa base nunca hubiera oído hablar de esa función.

Después de un rato dudando de mi cordura, encontré la causa real: un ajuste llamado “ErP Ready”, escondido en la configuración de gestión de energía, que corta la alimentación en espera de los puertos USB y PCI-E para cumplir con la normativa europea de bajo consumo en modo apagado. Con ese ajuste activo, que venía así de fábrica, el propio menú de Wake-on-LAN quedaba oculto, no solo desactivado.

Desactivé “ErP Ready”, y como por arte de magia apareció justo al lado la opción que de verdad quería tocar: “Power On By PCI-E/PCI”. La activé, guardé, y desde entonces puedo apagar mi PC de sobremesa por completo y encenderlo desde cualquier otro nodo del clúster con un simple paquete mágico por red.

Una normativa medioambiental europea, pensada para ahorrar energía en salones de toda la Unión, estuvo a punto de convencerme de que mi placa base era defectuosa.

Cuando mi Raspberry Pi se moría de hambre (de voltios)

pi-dns es, sin ninguna duda, el nodo más importante del clúster: si se cae, se cae la resolución de nombres de todo lo demás. Así que cuando un día empezó a comportarse de forma errática, con reinicios que no cuadraban con nada, me tomé el asunto con la seriedad que merecía: corrí en círculo con las manos levantadas y gritando ¡aaaaaaaah!

El registro del sistema tenía la respuesta, y no era sutil: 348 avisos de Undervoltage detected! en menos de una hora. La Raspberry Pi 5 exige una alimentación estable de 5 voltios de verdad, no una aproximación optimista, y el cargador que tenía puesto, perfectamente válido para cualquier otro dispositivo USB-C de la casa, se quedaba corto en el momento justo en que la placa pedía más corriente.

La solución fue tan poco glamurosa como efectiva: cargador oficial de 27W con Power Delivery, cable de calidad con el chip de identificación correspondiente, y cero alargadores o hubs de por medio entre el enchufe y la placa. Desde entonces, silencio absoluto en los registros.

A veces el problema más crítico de toda tu infraestructura no es de software: es que el cable que usaste porque estaba “por ahí” no es tan bueno como parecía.

La ironía definitiva: monté un clúster entero y me olvidé de hacer git init

Guardo esta para el final porque me hace bastante gracia a mi propia costa. Después de días documentando cada decisión, cada incidente, cada solución, con una carpeta docs/ que ya roza las veinte páginas bien densas, hice una revisión completa del proyecto y descubrí algo bochornoso: todo ese trabajo vivía como ficheros sueltos en el disco de mi propio PC, sin control de versiones de ningún tipo.

Ni un solo commit. Ni una rama. Ni una red de seguridad si un día borraba algo sin querer.

Yo, que trabajo en informática, que le exijo a cualquier proyecto ajeno una disciplina razonable de versionado, tenía mi propio clúster casero desprotegido como si fuera un documento de Word de 2003 guardado únicamente en el escritorio.

Lo apunté en mi propia lista de mejoras pendientes con la prioridad más alta que existe en esa lista, junto a una nota que decía: “esto lleva quince minutos arreglarlo y el impacto es brutal”.

Para variar, me quedé corto calculando: git init, un .gitignore bien pensado para no colar ningún secreto por el camino, un commit inicial y un push al remoto: cinco minutos y un puñado de comandos, no quince.

La infraestructura mejor documentada de toda mi casa dejó de estar a un rm -rf de distancia del desastre total. Debería cambiarle el título a esta sección, pero lo dejaré como recordatorio de que “en casa del herrero, cuchillo de palo”.

Lo que queda por hacer (porque esto nunca termina)

Ningún homelab que se precie está “terminado”.

Ahora mismo tengo pendiente automatizar las copias de seguridad que hoy sigo lanzando a mano, montar un canal de notificaciones de verdad para no tener que entrar al panel a comprobar si algo está fallando, integrar el SAI físico que tengo desde hace meses sin conectar por software, y (con toda la ironía del mundo, después de la anécdota anterior) seguir puliendo la migración a un sistema de repositorios propio en vez de depender de terceros también para esto.

Nada de eso es urgente. Nada de eso bloquea que el clúster funcione hoy, ahora mismo, mientras escribo esto en un editor conectado a una base de datos que vive a un metro de mí y no en un centro de datos de otro continente.

Hay una ventaja de todo esto que no aparece en ninguna lista de tareas pendientes, precisamente porque ya la tengo ganada: aquí, probar algo no es lo mismo que probarlo “en mi ordenador”. Un portátil de desarrollo es limpio, generoso y un poco mentiroso: tiene todas las herramientas ya instaladas, red plana sin cortafuegos de por medio, permisos de administrador por defecto, y ningún otro servicio peleándose por el mismo puerto o la misma GPU.

Es el entorno perfecto para que algo funcione, y el peor entorno posible para saber si de verdad funciona.

El clúster se parece bastante más a un entorno de producción real, con todas sus incomodidades incluidas: hay un DNS interno que puede fallar (y ya falló), hay un cortafuegos que hay que entender antes de poder abrir un puerto, hay usuarios y permisos separados por servicio en vez de un único usuario todopoderoso, hay otros servicios ya en marcha y compitiendo por la misma RAM y el mismo ancho de banda, y hay una capa de autenticación real delante de casi todo.

Cuando algo funciona aquí dentro, funciona a pesar de esas fricciones, no gracias a su ausencia. Y esa es, sin ninguna duda, la garantía de que algo funciona, sin caer en la trampa de “qué bonita es la demo”.

Cluster Index

Por qué merece la pena, con todo

El precio de la comodidad

Podría haberme ahorrado el 90% de estos dolores de cabeza con una tarjeta de crédito y tres proveedores distintos. Lo sé. Lo supe desde el primer minuto.

Y aun así, cada vez que uno de estos incidentes se resolvía, cada vez que entendía de verdad por qué algo se había roto, no solo cómo silenciar el síntoma, aprendía algo que ninguna documentación de un producto SaaS me habría enseñado nunca, porque esa documentación está pensada precisamente para que no necesites entender lo que hay debajo.

Cloud vs Homelab

Tengo mi propia IA ejecutándose en mi propio hardware, con mis propios datos, sin que nadie más decida por mí cuándo se acaba el servicio. Tengo una Raspberry Pi que resuelve nombres de dominio internos más rápido de lo que tarda mi router en cargar su propio panel de administración. Y tengo, sobre todo, la certeza de saber exactamente dónde está cada tornillo de mi propia infraestructura.

Y hay un beneficio colateral que no estaba en ninguna hoja de especificaciones y que agradezco cada noviembre: seis máquinas encendidas de forma más o menos permanente, dos de ellas con GPU a pleno rendimiento cuando toca entrenar o servir modelos, generan una cantidad de calor considerable. En León, donde el invierno se toma su trabajo muy en serio, tener un rincón del salón que nunca baja de una temperatura razonable ha dejado de ser un efecto secundario molesto para convertirse, a efectos prácticos, en mi sistema de calefacción de repuesto. La factura de la luz sube, sí, pero la de la calefacción compensa una parte, y encima puedo decir con la cara muy seria que mis servidores trabajan para mí en más de un sentido.

La nube te vende comodidad. Yo elegí entender, y mantener mis pies calientes.

Documentación del proyecto

Todo lo contado aquí está documentado con mucho más detalle técnico en el propio repositorio del proyecto en GitHub : la topología completa del clúster, la instalación paso a paso de cada nodo, el incidente del DNS con su diagnóstico completo, la resolución de problemas habituales, la configuración de Tailscale para el acceso remoto, y la lista viva de mejoras futuras.


Glosario rápido

Si el clúster te ha dejado con más preguntas que un manual de IKEA, aquí tienes los términos clave sin necesidad de un máster en redes.

Sígueme

Escribo y opino sobre tecnología, desarrollo de software y lo que se me pase por la cabeza.