Publicación reversible, con verificación después, no solo antes
La publicación no termina cuando los archivos han llegado al servidor, sino cuando una solicitud real demuestra que la nueva versión es la que se sirve. En una de las implementaciones, el script sincroniza el directorio, conserva la versión anterior al lado, luego extrae el nombre del paquete de la página entregada y verifica en la dirección pública que se sirva exactamente ese archivo; si no, vuelve por sí solo a la versión anterior. No es teórico: el mecanismo detectó un paquete que quedó antiguo en el directorio del runner y anuló una publicación que, de otro modo, habría parecido exitosa.
Cambio atómico de versión, con el proceso bajo systemd
La alternativa a «paramos, copiamos encima, arrancamos» es el directorio de versiones más un enlace simbólico conmutado en una sola operación. La unidad systemd apunta siempre a la ruta estable, y la vuelta atrás significa conmutar el enlace de regreso. La unidad tiene política de reinicio ante fallo con una pausa breve, tiempo máximo de parada y restricciones de sistema: sin escalada de privilegios, sistema de archivos protegido, directorios personales inaccesibles, con una lista explícita de rutas en las que tiene permiso para escribir.
nginx al frente, con límites escritos para el caso real
Terminación TLS con renovación automática del certificado, HSTS con duración de un año e inclusión de subdominios, compresión con umbral mínimo de tamaño, recursos estáticos con expiración larga y marcado inmutable, y la aplicación vinculada a la interfaz local para que no pueda ser alcanzada directamente desde internet. Los límites de tasa se establecen por tipo de tráfico, no de forma global. Una lección pagada merece decirse: bajo HTTP/2, el límite de conexiones cuenta los flujos, no las conexiones — con un valor bajo, una sola carga de página rechaza por sí sola sus fuentes y scripts con 429.
Copia de seguridad que se verifica, no solo se ejecuta
Tarea diaria programada, con inicio en el siguiente arranque si la máquina estaba apagada a esa hora y con retraso aleatorio para que no arranque todo en el mismo segundo. La exportación de la base se comprime, y si el archivo resultante está vacío, la ejecución se trata como fallo — una exportación que termina «con éxito» y produce cero bytes es la forma habitual en que se descubre, seis meses después, que no existe copia. Los archivos del repositorio de objetos se sincronizan por separado. Una copia 100% local no sobrevive a la pérdida del disco, así que la copia también se lleva fuera de la máquina, a una cuenta de almacenamiento en la Unión Europea con replicación geográfica, versionado, eliminación reversible y expiración automática — con acceso mediante identidad gestionada, para que no exista ninguna clave de almacenamiento en el disco.
La eliminación programada solo se ejecuta después de una copia exitosa
La tarea de retención depende explícitamente de la de copiado y se inicia después de ella. Una limpieza sin copia reciente es la única forma de eliminación de la que no hay vuelta atrás. A diferencia del copiado, la eliminación no recupera las ejecuciones perdidas: si la máquina estaba apagada, no se borra dos veces al día siguiente. Cada ejecución escribe una fila en una tabla de ejecuciones, y antes de la primera activación real la tarea corre en vacío al menos una semana y se revisa el registro.
Alertas que no mienten ni hacen spam
Una tarea programada que devuelve 200 no significa una tarea que haya funcionado. Nuestro envoltorio de ejecución lee el cuerpo de la respuesta y busca en él fallos parciales, luego envía una alerta con limitación de frecuencia, para que un servicio caído todo el día no produzca noventa y seis mensajes idénticos. El motivo de que exista: un informe diario estuvo muerto once días seguidos, y la única pista era un vacío en una tabla que nadie miraba. La tarea programada se había disparado las once veces.
Cadena de publicación que no puede ser desviada desde arriba
Las acciones del flujo de integración se fijan en la huella completa del commit, no en la etiqueta. En marzo de 2026, una acción popular fue redirigida de las etiquetas `v1`…`v45` hacia código malicioso y llegó a más de 23.000 repositorios en 24 horas; una huella no se mueve. El flujo no conserva credenciales en la copia de trabajo, y la publicación no pasa por un token: pasa por un runner propio, en la máquina destino, con permisos concedidos de forma puntual. Así ninguna clave de acceso al servidor queda en la plataforma de código.
Contenedores con límites, comprobaciones de salud y registros que no llenan el disco
Cada servicio tiene política de reinicio, su propia comprobación de salud (preparación de la base de datos, un punto de estado de la aplicación), límites de CPU y memoria donde la carga lo requiere, y rotación de registros a nivel del motor de contenedores, con tamaño máximo y número de archivos. Los puertos de las bases de datos se enlazan a la interfaz local, nunca públicos. Las variables obligatorias se declaran de forma que el contenedor se niega a arrancar si faltan, en lugar de arrancar con un valor predeterminado peligroso.
Base de datos autogestionada, cuando la independencia importa
Pila completa en contenedores — base de datos, autenticación, interfaz REST, canal en tiempo real, almacenamiento de archivos, puerta de acceso — con las extensiones activadas explícitamente y con los parámetros de memoria y de conexiones adecuados a la máquina, no dejados en los valores predeterminados. Las migraciones son archivos versionados en el repositorio y se aplican manualmente, con el reinicio del componente que mantiene su esquema en memoria. El motivo de esta elección es simple: una plataforma gestionada desde fuera de la Unión Europea puede ser excelente técnicamente y, aun así, no ser adecuada jurídicamente.