Saltar al contenido
Volver al blog
HomelabIAClaude CodeAutomatización

Automatiza tu homelab con Claude Code

Un agente con acceso a tu servidor puede ahorrarte horas de mantenimiento, o dejarte sin datos. Cómo lo tengo montado yo para que solo pase lo primero.

Ismael Catala5 min de lectura

Tengo cinco máquinas en el homelab y ninguna gana de mantenerse sola. Actualizar paquetes, revisar por qué un contenedor se reinicia en bucle, comprobar que el backup de anoche existe de verdad. Nada difícil, pero es media hora que se te va cada semana sin darte cuenta.

Desde hace unos meses ese trabajo lo hace un agente. No de la forma irresponsable que te estás imaginando: con permisos acotados, sin acceso a nada que no deba tocar y con un humano aprobando lo que importa.

Lo primero: dónde vive el agente

No lo instalo en cada máquina. Tengo un contenedor LXC dedicado —el mismo enfoque del aislamiento con Docker, pero a nivel de máquina— que es el único que tiene claves SSH hacia el resto:

pct create 140 local:vztmpl/debian-12-standard_amd64.tar.zst \
  --hostname agente \
  --memory 2048 \
  --cores 2 \
  --net0 name=eth0,bridge=vmbr0,ip=dhcp \
  --unprivileged 1

La clave está en --unprivileged 1 y en que ese contenedor no tiene acceso al almacenamiento del NAS ni a la interfaz de gestión de Proxmox. Si alguien compromete el agente, ha llegado a una máquina que solo sabe hablar por SSH con otras. Es malo, pero es recuperable.

Las claves SSH son el verdadero límite

Aquí es donde la mayoría se relaja y donde de verdad se decide qué puede pasar. Cada destino tiene su propia clave, restringida por comando en ~/.ssh/authorized_keys del servidor de destino:

command="/usr/local/bin/agente-lectura",no-port-forwarding,no-X11-forwarding,no-pty ssh-ed25519 AAAA...

Y agente-lectura es un script que solo deja pasar lo que yo he decidido:

#!/usr/bin/env bash
set -euo pipefail
 
case "${SSH_ORIGINAL_COMMAND:-}" in
  "docker ps"*|"docker logs"*|"systemctl status"*|"df -h"|"journalctl"*)
    exec bash -c "$SSH_ORIGINAL_COMMAND"
    ;;
  *)
    echo "Comando no permitido: ${SSH_ORIGINAL_COMMAND:-vacío}" >&2
    exit 1
    ;;
esac

Con esto el agente puede diagnosticar cualquier cosa y no puede romper nada. Es la diferencia entre darle a alguien las llaves de casa o dejarle mirar por la ventana.

Qué le pido de verdad

El repaso de los lunes. Un cron lanza el agente con un encargo fijo: mira el estado de los contenedores, el espacio libre y los logs de las últimas 24 horas, y dime solo lo que se sale de lo normal. Nada de informes de tres páginas: si todo está bien, quiero un párrafo.

claude -p "Revisa el homelab siguiendo runbooks/repaso-semanal.md \
  y escribe el resultado en informes/$(date +%F).md" \
  --allowedTools "Bash(ssh:*)" "Read" "Write"

Los --allowedTools no son decoración. Sin ellos el agente decide por su cuenta qué herramienta usar, y no quiero descubrir un día que le ha parecido buena idea editar un fichero de configuración.

Traducir un error a lenguaje humano. Cuando algo falla, le paso el log y me dice qué ha pasado. Un exit code 137 es un proceso al que el kernel ha matado por consumir demasiada memoria, pero eso hay que saberlo. El agente lo sabe y además mira cuánta RAM tenía asignada esa máquina.

Escribir el docker-compose.yml de un servicio nuevo. Le doy la documentación oficial y mis convenciones —red, etiquetas de Traefik, dónde van los volúmenes— y me devuelve un fichero que encaja con el resto. Lo reviso yo, siempre, pero me ahorra el copiar y pegar de la documentación.

Documentar lo que ya existe. Esta ha sido la sorpresa. Le pedí que recorriera las máquinas y escribiera un inventario. Salieron dos servicios que llevaban un año encendidos y de los que yo ya no me acordaba.

Lo que nunca le dejo hacer

Aplicar actualizaciones solo. Puede decirme qué hay pendiente y qué cambia cada versión. El apt upgrade lo lanzo yo, después de un snapshot.

Tocar el proxy inverso. Es el único punto de entrada desde internet. Un error ahí no tira un servicio: los tira todos y encima te deja fuera.

Borrar nada. Ni logs antiguos, ni imágenes de Docker sin usar, ni backups caducados. La limpieza la hacen scripts tontos con reglas fijas, que es exactamente lo que quieres para algo irreversible.

Trabajar sin snapshot. Antes de cualquier sesión en la que vaya a escribir, snapshot de la máquina implicada. Cuesta quince segundos.

El fallo que me hizo cambiar de enfoque

Al principio le di acceso amplio a una máquina de pruebas. Le pedí liberar espacio y lo hizo: borró las imágenes de Docker sin usar. También la imagen base que yo tenía guardada precisamente porque ya no estaba en el registro público.

No perdí nada importante y tardé una tarde en reconstruirla. Pero aprendí lo que de verdad importa: el agente no distingue entre "sin usar" y "sin usar ahora mismo". Ese contexto lo tienes tú y solo tú, así que las decisiones irreversibles se quedan de tu lado.

Merece la pena, con matices

He pasado de media hora semanal de mantenimiento a unos diez minutos leyendo informes. El agente no ha arreglado nada solo —no se lo permito— pero me dice dónde mirar, y ese es el noventa por ciento del trabajo.

Si te estás planteando montarlo, empieza al revés de como lo hice yo: dale acceso de solo lectura y pídele que te cuente cosas. Cuando lleves un mes leyendo lo que escribe, sabrás exactamente qué le puedes confiar y qué no.