[🛠] IT Operations #2: Para el servidor Linux de la empresa, diseñé la operación antes de instalar los servicios
✨ Resumen de GPT-5.6 Sol
Un registro de cómo configuré el disco, el SSH interno y una dirección estable en un Ubuntu Server dedicado; separé los permisos de personas, AI Cells y runtimes de automatización; y documenté toda la red como una base operativa que Codex pudiera retomar.
Por fin monté un servidor Linux dedicado a los servicios de la empresa.
Pero lo que construí esta vez no fue solo un ordenador capaz de arrancar Ubuntu. Se parecía más a una base operativa preparada para que personas, IA y servicios de automatización trabajaran al mismo tiempo en un servidor sin invadir los permisos ni el estado de los demás.
Cuando conseguí el SSD, mi idea era sencilla: instalar Linux en un PC con Windows, conectarme por SSH y convertirlo en servidor. Enseguida empecé a pensar en la GUI. ¿No acabaría lamentando haberme empeñado en usar solo CLI para que pareciera un «servidor de verdad» cuando necesitara iniciar sesión en un navegador o usar Computer Use?
Al analizarlo paso a paso entendí que el servidor necesitara una GUI y que yo necesitara usar una GUI eran dos asuntos completamente distintos. Si hacía falta OAuth o iniciar sesión en Codex, podía abrir en el navegador del MacBook la URL que apareciera por SSH. Si necesitaba Computer Use, podía ejecutarlo en mi Mac o en un equipo de trabajo y dejar Linux como Runtime donde se desplegaría el resultado.
Un servidor no es una máquina para mostrar una pantalla, sino un entorno que sigue ejecutándose.
UEFI, GPT y LVM para conservar el disco de Windows
Hasta el USB de instalación me confundió. Pensaba que, si el USB de Ventoy usaba MBR, Ubuntu también se instalaría con MBR. Cuando el menú de arranque mostró UEFI: USB, Partition 2, tampoco sabía si era la ruta correcta.
El esquema de particiones del USB y el del SSD donde se instala Ubuntu son independientes. Bastaba con iniciar el instalador desde la opción UEFI y elegir con precisión el SSD de destino. No toqué el NVMe de Windows existente y creé la EFI System Partition, /boot, LVM y el root filesystem únicamente en el nuevo SSD de 250 GB.
Lo más aterrador no era la dificultad de Linux, sino la posibilidad de borrar el disco equivocado. Al ver incluso la partición Reservado para el sistema de Windows, parecía algo que se podía eliminar. Volví a comparar el modelo y la capacidad de cada disco en el instalador y elegí solo el SSD dedicado a Ubuntu. El disco de Windows quedó intacto.
Elegí la instalación estándar de Ubuntu Server 24.04.4 LTS, ni minimized ni una Desktop image. Sin GUI, quedó una base centrada en SSH y systemd, lista para añadir después un Docker Runtime.
Reserva DHCP y SSH interno antes que una dirección fija
Durante la instalación, la LAN cableada recibió inmediatamente una dirección por DHCP. Al principio pensé que Create bond haría que SSH conectara mejor o que fijaría la dirección. Sin embargo, un bond agrupa varias NIC para ofrecer redundancia o sumar ancho de banda. No tiene relación con fijar la dirección de una sola NIC cableada.
En lugar de grabar una static IP arbitraria dentro del servidor, asocié la dirección MAC de la NIC a una IP interna mediante una reserva DHCP en el router principal. El servidor sigue siendo DHCP client, pero recibe la misma dirección después de reiniciarse. Además, desde el router se pueden comprobar posibles conflictos con otros dispositivos reservados.
Tampoco expuse SSH a Internet. Creé una clave Ed25519 exclusiva para el MacBook, comparé la host key del servidor con la consola y la fijé a la dirección de la red interna. No configuré forwarding externo del puerto 22 en el router.
Justo después de instalar, ssh.service aparecía como disabled, y por un momento creí que SSH estaba mal instalado. En realidad, ssh.socket estaba activo y escuchaba en el puerto 22; el public-key login siguió funcionando repetidamente después de reiniciar. Socket activation puede iniciar el servicio correspondiente cuando llega una solicitud, así que no debía diagnosticar un fallo por una sola línea del estado del servicio.1
La diferencia entre DHCP lease, reservation e IP–MAC binding que aprendí unos días antes mientras reparaba la caída de Internet del router de la empresa se convirtió directamente en la base de este servidor. Recibir una dirección y poder administrar una máquina de forma segura mediante ella no son lo mismo.
Personas, AI Cells y servicios fuera de una sola cuenta
En cuanto funcionó SSH, estuve a punto de instalar Oh My Zsh, Powerlevel10k y mis alias personales, como de costumbre. Entonces volví a detenerme.
La primera cuenta creada durante la instalación pertenece a la empresa y sirve para bootstrap y recuperación. Reunir en ella mi shell cotidiano, el AI Runtime y Operations Automation sería cómodo. Pero impediría distinguir quién ejecutó qué y con qué permisos, y todo quedaría enredado cuando hubiera más responsables o se revocara una cuenta.
Por eso empecé separando las cuentas según estas reglas.
administrador de bootstrap
└─ solo para instalación y recuperación
usr-<person>
└─ cuenta que usa una persona para SSH, sudo y desarrollo
aio-cell-<person>
└─ cuenta bajo la que se ejecuta continuamente un AI Cell personal
svc-<domain>-<purpose>
└─ Runtime de aplicación, importer de datos o broker de operaciones restringidas
También fue deliberado no incluir la empresa ni el puesto en el username. La persona sigue siendo la misma aunque cambien su pertenencia y su función. Es mejor que el Linux login represente solo una identidad estable y que permisos como administrador, desarrollador o participante en un proyecto cambien aparte mediante groups y RBAC.
Decidí dejar OMZ, P10K y mis alias únicamente en la cuenta humana. Los AI Cells y service accounts no leerán la configuración del interactive shell, sino que se ejecutarán mediante systemd units fijas, EnvironmentFiles y rutas absolutas. Un prompt atractivo mejora mi productividad, pero no tiene relación con la estabilidad del servicio.
Todavía no he creado todas esas cuentas con prisa. Primero fijé sus nombres, los archivos que poseerán, si podrán iniciar sesión y los límites de acceso a sudo y Docker. Definir estas fronteras cuando el servidor aún está vacío es mucho más sencillo que separar todo después de haberlo mezclado en una sola cuenta.
La frontera de un AI Cell llega hasta UID, HOME y OAuth
El mayor cambio de comprensión esta vez tuvo que ver con los sistemas multiusuario.
Cuando uno solo ve GUI de escritorio, parece que el usuario visible en la pantalla de inicio de sesión ocupa todo el ordenador. En Linux, la pantalla de inicio de sesión y los usuarios con procesos en ejecución son conceptos distintos. Varios usuarios pueden conectarse por SSH al mismo tiempo, y los procesos de service accounts que no han iniciado sesión pueden seguir activos bajo systemd.
Esta estructura era especialmente importante al llevar a Linux el modelo de AI Cell que había redefinido por usuario de macOS. Un AI Cell no era simplemente el nombre de un proceso.
1 AI Cell
= 1 conjunto de Linux UID y HOME
= 1 conjunto de OAuth y CODEX_HOME
= 1 conjunto de Gateway y Port
= 1 conjunto de Session, Memory y Workspace
= 1 conjunto de systemd unit y cgroup budget
Cuando el Cell de cada persona tiene su propio UID y HOME, la autenticación, la memoria y el espacio de trabajo se separan de forma natural. Cada Cell se ejecuta en un port o Unix socket distinto, y systemd lo mantiene en marcha tras el arranque aunque el usuario no haya iniciado sesión por SSH. Pueden coexistir varios Cells en el mismo servidor sin que el OAuth o la Memory de uno se utilicen como fallback de otro.
En cambio, decidí no dar a los AI Cells sudo, un mount completo del NAS, credenciales de administrador de la DB de producción ni acceso al Docker socket. La documentación oficial de Docker también advierte que el group docker concede permisos equivalentes a root.2 Añadir por comodidad las cuentas humanas, de IA y de servicio a ese group borraría en la práctica las fronteras que acababa de separar.
Las operaciones de Docker las realizará explícitamente un administrador humano con sudo, o bien un helper limitado propiedad de root y una systemd unit que solo acepten operaciones predefinidas. La IA podrá coordinar un despliegue, pero no dispondrá directamente de un shell arbitrario ni de todos los permisos de Docker.
El NAS como ingress y Linux como application Runtime
El servidor Linux no es un equipo destinado solo a AI Orchestration. La Web, la API y la DB de Operations Automation también se ejecutarán allí en un Docker Runtime. Eso no significa reunirlo todo en una cuenta, un Compose project y una network.
Las conexiones externas seguirán utilizando el HTTPS y el reverse proxy que ya gestiona el NAS. Linux ejecutará las aplicaciones reales.
usuario externo
→ HTTPS 443
→ router de la empresa
→ TLS y hostname reverse proxy del NAS
→ frontend de Linux
→ API interna de Docker
→ DB interna de Docker
No hace falta exponer directamente a Internet el port de administración del NAS, el SSH de Linux ni los ports de la API y la DB. El NAS permanece como ingress para hostnames y certificados, además de punto de storage y backup, mientras Linux asume el application Runtime. No se desecha la ruta HTTPS externa creada al trasladar la automatización de vacaciones al NAS; solo se mueve el backend final al servidor dedicado.
Tampoco uní el despliegue de código con la importación de datos de RR. HH. desde el NAS.
código
→ verificar release y artifact hash
→ deploy helper restringido
→ health check y rollback
datos de RR. HH.
→ carpeta read-only aprobada en el NAS
→ staging, validation y preview
→ aprobación
→ DB transaction y audit
AI Orchestration puede analizar un cambio y solicitar aprobación. Sin embargo, el despliegue real y la importación de datos se ejecutarán por separado mediante un broker y un importer que solo acepten operaciones definidas. El MacBook puede utilizarse para desarrollo, dry-run, revisión de previews e inicio de tareas aprobadas, pero no será el punto de canonical mutation de la DB de producción.
El servidor Linux aún no tiene Docker ni una application DB. Por tanto, no lo llamé production backend solo porque funcionaran la reserva DHCP y SSH. El target del reverse proxy del NAS solo podrá cambiar después de preparar el frontend port exacto, el health check, backup y restore, y rollback.
Un Codex Skill que conserva toda la topology de la red
La continuidad con la siguiente conversación era tan importante como la propia configuración del servidor.
Actualicé un Codex Skill dedicado a la red de la empresa y su inventario detallado con las relaciones entre el router, los dos NAS, el Mac Runtime existente, el nuevo servidor Linux, el HTTPS externo y el SSH interno. No es solo una lista de IP: distingue la función de cada dispositivo y el origen, los hops intermedios y el Runtime final de cada flujo de traffic.
El Skill tampoco mezcla los hechos ya completados con la estructura futura.
- La instalación y el reinicio de Ubuntu, y el SSH interno, están terminados.
- Las identities multiusuario y los límites de permisos están decididos, pero las cuentas aún no se han creado.
- Docker, los AI Cells y Operations Automation todavía no se han desplegado en Linux.
- El reverse proxy del NAS solo cambiará a Linux cuando existan health checks y rollback.
Ahora, aunque abra una nueva sesión de Codex, ya no tengo que empezar explicando: «¿Cuál era la IP del servidor?», «¿El NAS ejecuta la application?» o «¿Por qué estaba disabled el servicio SSH?». El Skill transmite conjuntamente la topology real, los límites de seguridad, el estado verificado y lo que todavía no está terminado.
Por eso este servidor aún no es un production server completo, pero tampoco es un SSD vacío con Ubuntu instalado. El siguiente trabajo consiste en poner realmente en marcha las cuentas humanas, los AI Cells y el Operations Automation Runtime dentro de los límites ya definidos.
A partir de ahora, cada vez que instale algo, creo que primero preguntaré: «¿Con qué cuenta se ejecutará?», «¿Qué HOME y credenciales poseerá?» y «¿Qué ports y data flows estarán permitidos?». Más que haber montado un servidor, siento que primero definí las reglas para poder ampliarlo sin romperlo una y otra vez.
Referencias
-
Una socket unit de systemd puede supervisar un socket y activar el servicio correspondiente al recibir incoming traffic. Manual oficial de systemd.socket ↩
-
El group
docker, que puede acceder al Unix socket del Docker daemon, concede privilegios equivalentes a root. Pasos posteriores a la instalación de Docker Engine en Linux ↩
Deja un comentario