Cómo migrar un servidor dedicado sin downtime (o casi)

    Introducción

    Las razones para migrar un servidor dedicado son muchas y todas válidas: el proveedor se está volviendo caro, el hardware ya tiene años y el rendimiento se nota, el soporte técnico es pésimo, o simplemente necesitas mover tu infraestructura a un datacenter más cercano a tus usuarios para reducir latencia. Cualquiera de estas razones es suficiente. El problema no es por qué migrar, sino cómo hacerlo sin que todo explote en el proceso.

    El miedo clásico es "¿y si se rompe todo?". Perder datos, horas de downtime, clientes llamando, el jefe encima. Ese miedo es completamente válido — una migración mal ejecutada puede ser catastrófica. Pero la buena noticia es que ese escenario no viene de la complejidad técnica, viene de la falta de preparación. La mayoría de migraciones que salen mal no fallan porque el administrador no sabe usar rsync, sino porque nadie documentó qué estaba corriendo en el servidor antes de empezar.

    La clave está en una sola idea: la mayoría de migraciones fallan por falta de preparación, no por complejidad técnica. Un servidor que has documentado completamente, con un plan de rollback claro y un proceso de testing antes de tocar el DNS, es un servidor que puedes migrar con confianza. El downtime "cero" es casi imposible si tienes bases de datos con escrituras constantes, pero "menos de 10 minutos" es perfectamente alcanzable para la mayoría de casos.

    En esta guía vas a tener un proceso sistemático con checklist, comandos reales y un plan de rollback. El objetivo no es que memorices cada paso, sino que lo sigas como protocolo la próxima vez que tengas que mover un servidor. Al final tendrás el servidor nuevo corriendo en paralelo, habrás verificado que funciona bien, y harás el corte de DNS cuando estés seguro — no a ciegas.

    Fase 1 — Auditoría del servidor actual

    Esta es la fase más importante. No puedes migrar lo que no has documentado. El objetivo aquí no es solo hacer un listado, sino entender completamente qué está corriendo, qué depende de qué, y qué se puede romper si algo falta en el servidor nuevo.

    Inventariar servicios activos

    Empieza por saber exactamente qué procesos están activos y qué están escuchando en qué puertos. Esto te dará la lista completa de lo que tienes que replicar.

    # Ver todos los servicios activos
    sudo systemctl list-units --type=service --state=active
    
    # Ver los que arrancan al inicio
    sudo systemctl list-unit-files --type=service --state=enabled
    
    # Puertos en escucha (muestra qué está corriendo)
    sudo ss -tlnp
    # o
    sudo netstat -tlnp
    
    # Procesos por consumo de CPU/RAM
    ps aux --sort=-%mem | head -20

    Documentar configuraciones críticas

    Los servicios son el "qué", la configuración es el "cómo". Necesitas documentar cómo está configurado cada servicio importante antes de intentar replicarlo.

    # Listar todos los vhosts de nginx
    ls -la /etc/nginx/sites-enabled/
    cat /etc/nginx/nginx.conf
    
    # Crontabs de todos los usuarios
    sudo crontab -l
    crontab -l
    sudo bash -c 'for user in $(cut -f1 -d: /etc/passwd); do echo "=== $user ==="; crontab -u $user -l 2>/dev/null; done'
    
    # Usuarios del sistema y sus homes
    cat /etc/passwd | grep -v nologin | grep -v false
    
    # Variables de entorno en uso
    sudo cat /etc/environment
    sudo cat /etc/profile.d/*.sh 2>/dev/null

    Medir uso real de recursos

    Esto te ayuda a elegir el hardware adecuado en el servidor nuevo y a identificar qué procesos consumen más recursos.

    # Disco
    df -h
    du -sh /var/www/* 2>/dev/null | sort -rh | head -20
    
    # RAM en uso real
    free -h
    vmstat -s | head -10
    
    # CPU — average load
    uptime
    cat /proc/cpuinfo | grep "model name" | head -1
    
    # Bandwidth (si tienes vnstat instalado)
    vnstat -m

    Checklist de pre-migración

    Antes de tocar el servidor nuevo, este checklist debe estar completo. No saltes ningún punto.

    Item Comando/Acción
    Lista de servicios activos systemctl list-units
    Versiones exactas (nginx, PHP, MySQL...) nginx -v; php -v; mysql -V
    Lista de bases de datos mysqlshow o psql -l
    Crontabs documentados crontab -l (todos los usuarios)
    SSL certificates y fechas de vencimiento certbot certificates
    Variables de entorno y .env files cat /etc/environment
    Usuarios SSH con acceso cat /etc/ssh/sshd_config; cat /root/.ssh/authorized_keys
    Reglas de firewall actuales iptables -L -n; ufw status
    DNS records del dominio dig +short A dominio.com
    TTL actual del DNS dig dominio.com | grep TTL

    Fase 2 — Preparar el servidor nuevo

    El servidor nuevo tiene que ser configurado antes de migrar ningún dato. El objetivo es tener un entorno idéntico al original en cuanto a versiones de software y configuración de seguridad base.

    Instalar el mismo stack

    Las versiones importan. Una aplicación que corre sobre PHP 8.0 puede comportarse diferente en PHP 8.2. Replica las versiones exactas del servidor viejo.

    # En el servidor NUEVO
    # Replicar versiones exactas del viejo
    
    # Ver versiones en el servidor viejo
    nginx -v
    php -v
    mysql --version
    node --version
    python3 --version
    
    # Instalar en el nuevo (ejemplo para Ubuntu 22.04 + nginx + PHP 8.1 + MySQL 8)
    sudo apt update
    sudo apt install -y nginx php8.1-fpm php8.1-mysql php8.1-curl php8.1-zip \
        php8.1-gd php8.1-mbstring php8.1-xml php8.1-bcmath
    sudo apt install -y mysql-server-8.0

    Seguridad base antes de migrar datos

    No pongas datos en un servidor que no está protegido. Antes de copiar nada, asegura el acceso SSH y configura el firewall.

    # Deshabilitar login con contraseña — solo keys SSH
    sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
    sudo sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
    sudo systemctl reload sshd
    
    # Configurar firewall básico
    sudo ufw allow 22/tcp
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw --force enable
    
    # Instalar fail2ban
    sudo apt install fail2ban -y
    sudo systemctl enable --now fail2ban

    Configurar acceso SSH del viejo al nuevo

    Para que rsync funcione sin interrupciones (y sin pedir contraseña cada vez), el servidor viejo necesita poder conectarse al nuevo por SSH usando una clave dedicada para la migración.

    # En el servidor VIEJO: agregar clave pública al nuevo
    # Esto permite que rsync funcione sin contraseña
    ssh-keygen -t ed25519 -C "migration-key" -f ~/.ssh/migration_key -N ""
    ssh-copy-id -i ~/.ssh/migration_key.pub root@IP-SERVIDOR-NUEVO
    # o
    cat ~/.ssh/migration_key.pub | ssh root@IP-SERVIDOR-NUEVO "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

    Fase 3 — Migrar los datos

    Aquí está el grueso del trabajo. La estrategia es hacer una sincronización inicial (que puede tardar horas si tienes muchos datos) y luego una sincronización final justo antes del corte de DNS para copiar solo los cambios recientes.

    Archivos con rsync

    rsync es la herramienta ideal para esto: copia solo los cambios, soporta compresión en tránsito, puede reanudar si se interrumpe, y preserva permisos y timestamps.

    # Desde el servidor VIEJO hacia el NUEVO
    # -a: archive (preserva permisos, timestamps, owner)
    # -v: verbose
    # -z: comprimir en tránsito
    # -P: mostrar progreso + resumir si se interrumpe
    # --delete: eliminar archivos en destino que no están en origen
    
    # Sincronización inicial (puede tardar horas)
    rsync -avzP --delete \
        /var/www/ \
        root@IP-NUEVO:/var/www/
    
    # Config de nginx
    rsync -avzP \
        /etc/nginx/ \
        root@IP-NUEVO:/etc/nginx/
    
    # SSL certificates
    rsync -avzP \
        /etc/letsencrypt/ \
        root@IP-NUEVO:/etc/letsencrypt/
    
    # Hacer rsync final justo antes del corte DNS (sincroniza solo los cambios)
    rsync -avzP --delete \
        /var/www/ \
        root@IP-NUEVO:/var/www/
    Importante: Ejecuta siempre un rsync de prueba con --dry-run primero para ver qué se va a copiar sin realmente hacerlo. Especialmente cuando usas --delete.

    Bases de datos MySQL

    Para MySQL, la estrategia depende del tamaño. La opción segura para bases de datos de cualquier tamaño es --single-transaction, que hace el dump sin bloquear tablas en servidores InnoDB.

    # En el servidor VIEJO
    # Exportar todas las bases de datos
    mysqldump \
        --single-transaction \
        --quick \
        --lock-tables=false \
        --all-databases \
        --routines \
        --triggers \
        | gzip > /tmp/all-databases-$(date +%Y%m%d).sql.gz
    
    # Copiar al servidor nuevo
    rsync -avzP /tmp/all-databases-*.sql.gz root@IP-NUEVO:/tmp/
    
    # En el servidor NUEVO: importar
    gunzip < /tmp/all-databases-YYYYMMDD.sql.gz | mysql -u root -p

    Para bases de datos grandes (>10GB), usa streaming directo para ahorrar espacio en disco:

    # Pipe directo sin archivo intermedio (ahorra espacio de disco)
    mysqldump --single-transaction --quick --lock-tables=false --all-databases | \
        gzip | \
        ssh root@IP-NUEVO "gunzip | mysql -u root"

    PostgreSQL

    # Exportar
    sudo -u postgres pg_dumpall | gzip > /tmp/postgres-all-$(date +%Y%m%d).sql.gz
    
    # Importar en el nuevo
    gunzip < /tmp/postgres-all-*.sql.gz | sudo -u postgres psql

    Crontabs

    Los crontabs son fáciles de olvidar y silenciosamente críticos — si no los migras, los jobs dejan de correr sin ningún error visible.

    # Exportar crontab de root en el servidor VIEJO
    sudo crontab -l > /tmp/crontab-root-backup.txt
    rsync -avzP /tmp/crontab-root-backup.txt root@IP-NUEVO:/tmp/
    
    # Importar en el NUEVO
    sudo crontab /tmp/crontab-root-backup.txt
    sudo crontab -l  # verificar

    Fase 4 — Testing en paralelo

    Esta fase es la diferencia entre una migración que te da confianza y una que hacen con los ojos cerrados. El objetivo es verificar que todo funciona en el servidor nuevo antes de cambiar el DNS, mientras el servidor viejo sigue sirviendo tráfico real.

    Probar con /etc/hosts local

    Antes de cambiar el DNS (que afectaría a todos tus usuarios), puedes apuntar el dominio al servidor nuevo solo desde tu máquina local editando el archivo hosts.

    # En tu máquina local (NO en el servidor)
    # Editar /etc/hosts (Linux/Mac) o C:\Windows\System32\drivers\etc\hosts (Windows)
    
    # Agregar al final:
    IP-SERVIDOR-NUEVO  tudominio.com www.tudominio.com

    Ahora cuando navegas a tudominio.com desde tu máquina, llega al servidor nuevo, mientras que el resto del mundo sigue llegando al servidor viejo.

    # Verificar qué IP estás resolviendo localmente
    dig +short tudominio.com @localhost
    # o
    curl -H "Host: tudominio.com" http://IP-SERVIDOR-NUEVO/

    Checklist de verificación

    Con el hosts modificado, ejecuta estas verificaciones una por una:

    Verificación Método
    Sitio web carga Abrir navegador, ver que no hay errores
    HTTPS funciona Candado verde, no warning de certificado
    Login/autenticación Probar usuario/contraseña si aplica
    Base de datos conecta Ver que las páginas dinámicas cargan
    Formularios funcionan Enviar formulario de contacto de prueba
    Emails se envían Enviar email de prueba desde la app
    Crons corren Revisar log de cron después de la hora programada
    Rendimiento Comparar TTFB con el servidor viejo

    Comparar rendimiento

    Una migración también es una oportunidad de verificar que el nuevo servidor es al menos tan rápido como el viejo. Si el TTFB es peor, investiga antes de hacer el corte.

    # Comparar TTFB (Time to First Byte) entre viejo y nuevo
    curl -o /dev/null -s -w "TTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
        http://IP-SERVIDOR-VIEJO/
    
    curl -o /dev/null -s -w "TTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
        -H "Host: tudominio.com" http://IP-SERVIDOR-NUEVO/

    Fase 5 — El corte DNS

    Si llegaste aquí con el checklist de verificación completo, el trabajo difícil ya está hecho. El corte DNS es el momento en que el tráfico real empieza a llegar al servidor nuevo. Con la preparación correcta, debería ser el paso más tranquilo de todos.

    Reducir el TTL 24-48 horas antes

    El TTL (Time to Live) del DNS controla cuánto tiempo los resolvers cachean el registro. Si tu TTL está en 86400 (24 horas) y cambias el registro A, algunos visitantes seguirán llegando al servidor viejo durante hasta 24 horas. La solución: bajar el TTL a 300 (5 minutos) un día antes de la migración.

    # Verificar TTL actual del dominio
    dig tudominio.com | grep -E "^tudominio|TTL"
    
    # Desde la interfaz de tu DNS provider (Cloudflare, etc.)
    # Cambiar TTL del registro A a 300 (5 minutos)
    # Esperar 24-48 horas (que el TTL viejo expire en todos los resolvers)

    El rsync final

    Justo antes de cambiar el DNS (menos de 30 minutos antes), haz una última sincronización para capturar todos los archivos que cambiaron desde la sincronización inicial. Como rsync solo copia los cambios, esto suele ser muy rápido.

    # Justo antes de cambiar el DNS (< 30 minutos antes)
    # Sincronizar solo los cambios desde la última vez
    rsync -avzP --delete /var/www/ root@IP-NUEVO:/var/www/
    
    # Verificar bases de datos: ¿hay datos nuevos desde el último dump?
    # Si hay transacciones activas, considera:
    # 1. Hacer un mysqldump rápido y reimportar los registros nuevos
    # 2. Si es crítico: brief maintenance mode mientras cambias DNS
    
    echo "Hora del rsync final: $(date)"

    Cambiar el DNS

    En tu proveedor DNS (Cloudflare, Namecheap, etc.), cambia el registro A del dominio de la IP del servidor viejo a la IP del servidor nuevo. Con TTL en 300, la mayoría de resolvers actualizarán en 5-15 minutos.

    # Verificar propagación desde tu terminal
    watch -n 5 "dig +short tudominio.com"
    
    # Ver propagación global online
    # Usar: whatsmydns.net o dnschecker.org
    
    # Verificar que el nuevo servidor recibe tráfico
    sudo tail -f /var/log/nginx/access.log
    Sobre la propagación DNS: La propagación puede tomar desde segundos hasta 48 horas dependiendo del resolver. Con TTL=300, la mayoría de resolvers refrescan en 5-15 minutos. Es normal que durante ese período algunos usuarios lleguen al viejo y otros al nuevo.

    Mantener el servidor viejo activo

    No apagues el servidor viejo inmediatamente. Mantenlo activo por 48-72 horas después del corte:

    • La propagación DNS puede tardar hasta 48h en algunos resolvers
    • Lo necesitas como fallback si algo falla en el servidor nuevo
    • Te permite comparar comportamiento si algo se ve diferente
    • Si hay que hacer rollback, tener el viejo activo hace que sea instantáneo

    Fase 6 — Post-migración

    El DNS ya apunta al servidor nuevo y el tráfico está fluyendo. Ahora toca verificar con DNS real (sin los cambios en /etc/hosts), monitorear errores y dejar todo configurado correctamente para el largo plazo.

    Verificar con DNS real

    # Quitar los cambios en /etc/hosts de tu máquina local
    # y verificar que el dominio resuelve al servidor nuevo
    
    dig +short tudominio.com
    # Debe mostrar: IP-SERVIDOR-NUEVO
    
    # Monitoreo de errores en tiempo real
    sudo tail -f /var/log/nginx/error.log
    sudo journalctl -u nginx -f

    Restaurar TTL normal

    # Después de 24-48h confirmando que todo funciona
    # Volver TTL a valor normal: 3600 (1 hora) o 86400 (1 día)
    # Esto reduce la carga en los DNS de tu proveedor

    Mantener el TTL en 300 indefinidamente genera más queries a los nameservers de tu proveedor sin razón. Una vez que estés seguro de que la migración fue exitosa, vuelve al TTL normal.

    Configurar monitoreo y backups en el servidor nuevo

    El servidor nuevo es una pizarra limpia — aprovecha para configurar bien el monitoreo y los backups desde el principio.

    # Instalar Uptime Kuma u otro monitor
    # Configurar rclone backups (ver guía de backups)
    # Configurar alertas de disco/RAM
    
    # Verificar que fail2ban está activo
    sudo fail2ban-client status
    
    # Configurar logrotate para no quedarse sin disco
    sudo nano /etc/logrotate.d/nginx

    Dar de baja el servidor viejo

    No canceles el servidor viejo de inmediato. Espera al menos una semana sin problemas antes de hacerlo.

    # Una semana después de la migración exitosa:
    # 1. Hacer un backup final del servidor viejo
    # 2. Descargar el backup a algún lugar seguro
    # 3. Cancelar la suscripción del servidor viejo
    
    # Si tiene datos valiosos, tener snapshot/backup por 30 días más

    Plan de rollback

    Esta sección es crítica. Tienes que tenerla preparada antes de empezar la migración, no cuando ya algo salió mal. La buena noticia: con TTL=300 y el servidor viejo activo, hacer rollback es tan simple como cambiar el registro A de vuelta.

    Si algo sale mal

    Con TTL=300, revertir el DNS toma menos de 5 minutos:

    # En tu proveedor DNS: volver el registro A a IP-SERVIDOR-VIEJO
    # Con TTL=300, la mayoría de resolvers actualizarán en 5-15 minutos
    
    # Verificar que el tráfico vuelve al viejo
    watch -n 5 "dig +short tudominio.com"

    Por eso es tan importante bajar el TTL antes y mantener el servidor viejo activo. El costo de mantener el servidor viejo unos días extra es mínimo comparado con el costo de no poder hacer rollback rápido.

    Qué hacer si los datos divergieron

    Si el servidor viejo recibió operaciones de escritura después del rsync final (nuevos registros, pedidos, etc.) y tienes que hacer rollback, necesitas migrar esos datos nuevos cuando vuelvas a intentar la migración.

    # Exportar solo los registros NUEVOS desde el timestamp del rsync final
    mysqldump --where="created_at > '2026-03-28 14:30:00'" mi_base tabla_usuarios > /tmp/nuevos-usuarios.sql
    mysqldump --where="created_at > '2026-03-28 14:30:00'" mi_base tabla_pedidos > /tmp/nuevos-pedidos.sql
    
    # Importar en el servidor nuevo cuando vuelvas a intentar
    mysql mi_base < /tmp/nuevos-usuarios.sql
    mysql mi_base < /tmp/nuevos-pedidos.sql

    Para minimizar la divergencia de datos, el window de tiempo entre el rsync final y el corte de DNS debería ser lo más corto posible — idealmente menos de 30 minutos. Para aplicaciones con alto volumen de escrituras, considera poner un modo mantenimiento breve justo en ese window.

    ¿Tienes una migración pendiente?

    He hecho 15+ migraciones de servidores. La mayoría con menos de 10 minutos de downtime.

    El proceso funciona bien cuando está bien planificado. Si no quieres encargarte tú mismo — auditoría, migración, verificación y configuración del servidor nuevo — es exactamente lo que hago.

    Escríbeme por WhatsApp contacto@fixdop.com