La mayoría de las migraciones que fallan no lo hacen por un comando mal escrito, sino por algo que nadie anotó: una tarea de cron, un certificado, una regla de cortafuegos o una IP escrita a mano en la configuración de otro servidor. Esta guía es una lista de verificación para migrar un servidor Linux (web, base de datos o aplicación) a uno nuevo, ordenada por fases, con los comandos que te permiten comprobar cada punto en Ubuntu 24.04. Úsala como plantilla y adáptala a cada migración.

Requisitos previos

  • Acceso con un usuario con sudo al servidor de origen y al de destino. El destino puede ser, por ejemplo, un VPS de CubePath con Ubuntu 24.04 LTS.
  • Acceso al panel DNS de los dominios afectados.
  • Un documento compartido (una hoja de cálculo o una página de wiki) donde anotar el inventario y marcar cada punto.

Fase 1: Inventariar el servidor de origen

El inventario es la base de todo lo demás. Lo que no aparezca aquí no se migrará.

Sistema y recursos. Anota la distribución, el kernel, la CPU, la memoria y el uso de disco, para dimensionar el destino:

cat /etc/os-release
uname -r
nproc
free -h
df -hT -x tmpfs -x devtmpfs

Servicios en ejecución. Lista los servicios de systemd activos y los que arrancan con el sistema:

systemctl list-units --type=service --state=running --no-pager
systemctl list-unit-files --type=service --state=enabled --no-pager

Puertos a la escucha. Cada puerto abierto es un servicio que alguien usa:

sudo ss -tulpn
Netid State  Local Address:Port  Peer Address:Port Process
tcp   LISTEN 0.0.0.0:22          0.0.0.0:*         users:(("sshd",pid=812,fd=3))
tcp   LISTEN 0.0.0.0:443         0.0.0.0:*         users:(("nginx",pid=1044,fd=6))
tcp   LISTEN 127.0.0.1:3306      0.0.0.0:*         users:(("mysqld",pid=930,fd=21))

Tareas programadas. Son las más olvidadas. Revisa el crontab de cada usuario, los directorios de cron del sistema y los temporizadores de systemd:

sudo ls /var/spool/cron/crontabs/
sudo crontab -l -u www-data
ls /etc/cron.d/ /etc/cron.daily/ /etc/cron.hourly/
systemctl list-timers --all --no-pager

Paquetes instalados manualmente. Te ayuda a reproducir el software en el destino:

apt-mark showmanual

Datos. Localiza dónde viven los datos y cuánto ocupan: webs (/var/www), bases de datos (/var/lib/mysql, /var/lib/postgresql), volúmenes de Docker (/var/lib/docker/volumes), directorios personales y cualquier ruta propia:

sudo du -sh /var/www /var/lib/mysql /var/lib/postgresql /home 2>/dev/null

Configuración. Anota qué archivos de /etc has modificado: servidor web, PHP, base de datos, /etc/hosts, /etc/fstab, reglas de cortafuegos (sudo ufw status verbose o sudo nft list ruleset), claves SSH autorizadas y usuarios del sistema con shell:

grep -vE 'nologin|false$' /etc/passwd

Certificados TLS. Lista los certificados y su caducidad:

sudo certbot certificates

Dependencias externas. Busca la IP y el nombre del servidor antiguo en la configuración de todo lo demás: otros servidores que se conectan a su base de datos, reglas de cortafuegos que lo permiten por IP, listas blancas en APIs de terceros, registros SPF, monitorización y copias de seguridad remotas.

Fase 2: Preparar el destino y el plan

  • Dimensionar el destino con los datos del inventario: al menos la misma memoria y un 30 % más de disco que el usado.

  • Elegir versiones: si el destino tiene versiones más nuevas (PHP, PostgreSQL, MySQL, Python), anótalo. Cambiar de versión mayor durante la migración añade riesgo; hazlo antes o después, no a la vez, salvo que lo hayas probado.

  • Instalar y configurar el software a partir de la lista de paquetes y de la configuración copiada. Crea los usuarios de las aplicaciones con los mismos UID y GID que en el origen (id www-data, id usuario) para que los permisos de los datos copiados sigan siendo válidos.

  • Endurecer el acceso: usuario con sudo, SSH solo con clave y cortafuegos con los puertos del inventario:

    sudo ufw allow OpenSSH
    sudo ufw allow 80,443/tcp
    sudo ufw enable
    sudo ufw status verbose
    
  • Decidir el método de copia para cada tipo de dato: rsync para archivos, volcado o replicación para bases de datos, y la estrategia de cada aplicación. Para los datos que cambian continuamente, planifica una primera copia en caliente y una sincronización final durante el corte.

  • Estimar la ventana de corte: cronometra una pasada incremental de rsync y una restauración de la base de datos en una prueba. Eso es, aproximadamente, lo que durará el corte.

  • Escribir el plan de vuelta atrás (ver fase 6) y el criterio para activarlo, por ejemplo "si a los 30 minutos del corte el pago no funciona, se vuelve atrás".

  • Avisar a los usuarios afectados de la fecha y la duración prevista de la interrupción.

Fase 3: Copias de seguridad y DNS (días antes)

  • Hacer una copia de seguridad completa del origen y comprobar que se puede restaurar. Una copia que no has restaurado nunca no es una copia fiable. Para bases de datos, restaura el volcado en el servidor de destino o en uno de pruebas:

    sudo mysqldump --single-transaction --routines --triggers --events --databases app_db > app_db.sql
    
  • Bajar el TTL de los registros DNS que vas a cambiar (A, AAAA, MX, CNAME) a 300 segundos, al menos con un TTL antiguo de antelación (si era 86400, un día antes). Comprueba que el cambio se ve desde fuera:

    dig +noall +answer A your_domain @1.1.1.1
    
    your_domain.		300	IN	A	old_server_ip
    
  • Hacer la primera copia de los datos al destino con el servicio en marcha. Las pasadas siguientes solo transferirán cambios.

  • Probar la aplicación en el destino sin tocar el DNS público, apuntando tu equipo al servidor nuevo en tu archivo hosts local (/etc/hosts en Linux y macOS) con una línea new_server_ip your_domain. Recorre los flujos principales: inicio de sesión, formularios, subida de archivos, pagos, envío de correo.

Fase 4: El día del corte

Sigue este orden y marca cada punto en el documento compartido con la hora:

  1. Confirma que la última copia de seguridad del origen terminó correctamente.

  2. Activa la página de mantenimiento o detén las escrituras en el origen (servicios de aplicación, tareas de cron, consumidores de colas). Detén el cron en el origen para que las tareas no se ejecuten en los dos servidores a la vez:

    sudo systemctl stop cron
    
  3. Haz la sincronización final de los archivos con rsync --delete, tras una prueba en seco con -n.

  4. Haz el volcado final de las bases de datos y restáuralo en el destino, o detén la replicación y promociona el destino si estabas replicando.

  5. Arranca los servicios en el destino y comprueba que están activos:

    systemctl --failed --no-pager
    
  6. Prueba el destino contra su IP con tu archivo hosts local antes de cambiar el DNS.

  7. Cambia los registros DNS a la IP nueva y comprueba la propagación:

    dig +short A your_domain @1.1.1.1
    dig +short A your_domain @8.8.8.8
    
  8. Activa las tareas programadas en el destino y emite o renueva los certificados TLS si es necesario (sudo certbot renew --dry-run).

  9. Deja el origen parado pero intacto. No borres nada todavía.

Fase 5: Verificar después del corte

Durante las primeras horas:

  • Servicios: systemctl --failed no muestra nada y sudo ss -tulpn coincide con el inventario.

  • Logs: no aparecen errores nuevos. Revisa los del servidor web y de la aplicación, y el diario del sistema:

    sudo journalctl -p err --since "1 hour ago" --no-pager
    
  • HTTPS: el certificado es válido y el sitio responde desde fuera:

    curl -sSI https://your_domain | head -n 1
    
  • Funcionalidad: repite las pruebas de la fase 3 con usuarios reales o con una lista de comprobaciones escrita.

  • Correo saliente: si el servidor envía correo, la IP nueva está en el SPF y tiene un PTR correcto.

  • Tráfico en el origen: revisa los logs de acceso del servidor antiguo. Si sigue recibiendo peticiones pasadas unas horas, algún cliente o servidor tiene la IP antigua escrita a mano.

  • Tareas programadas: la primera ejecución de cada tarea de cron y de cada copia de seguridad en el destino termina bien.

  • Monitorización: los checks y alertas apuntan al servidor nuevo.

Fase 6: Plan de vuelta atrás

Ten escrito y probado cómo volver al servidor antiguo antes de empezar:

  • Revertir los registros DNS a old_server_ip. Con el TTL a 300 segundos, surte efecto en minutos.
  • Arrancar de nuevo los servicios y el cron del origen (sudo systemctl start cron).
  • Decidir qué hacer con los datos escritos en el destino después del corte: copiarlos de vuelta con rsync (sin --delete) o aceptar su pérdida. Cuanto más tiempo pase desde el corte, más cuesta volver atrás, así que fija un límite (por ejemplo, 24 horas) a partir del cual solo se corrigen errores hacia delante.

Fase 7: Cierre y retirada del servidor antiguo

Pasada una o dos semanas sin incidencias:

  • Vuelve a subir el TTL de los registros DNS a su valor habitual (por ejemplo, 3600 segundos).
  • Retira la IP antigua de registros SPF, listas blancas y reglas de cortafuegos de otros servidores.
  • Actualiza la documentación, el inventario y los diagramas con el servidor nuevo.
  • Haz una última copia de seguridad completa del origen y guárdala el tiempo que exija tu política.
  • Elimina las claves SSH y las reglas de sudo temporales creadas para la migración en ambos servidores.
  • Da de baja el servidor antiguo.
  • Anota qué se olvidó en el inventario y qué tardó más de lo previsto, y añádelo a esta lista para la próxima migración.

Conclusión

Una migración ordenada consiste en inventariar todo, copiar los datos en caliente, reducir el corte a una sincronización final y un cambio de DNS, y tener siempre un camino de vuelta. Guarda esta lista como plantilla en tu wiki y complétala con los detalles de cada servidor. Como siguientes pasos, prepara la transferencia de los datos con rsync y, si la ventana de corte debe ser mínima, configura una sincronización continua o replicación de la base de datos hasta el momento del cambio.