Todo servidor que gestionas se mudará al menos una vez. El proveedor sube los precios, o empieza a pedirte un documento que preferirías no enviar, o recibe una denuncia de abuso sobre un vecino de red y anula un /24 entero durante una tarde. La pregunta nunca fue si ibas a migrar — solo si ocurre un martes por la mañana que elegiste tú, o un sábado por la noche que eligió otro por ti.
La mecánica no es la parte difícil. Copiar archivos es rsync, y eso ya lo sabes. Lo que hace que las migraciones salgan mal es el tiempo: durante una mudanza corren tres relojes distintos, no están sincronizados, y todo fallo real ocurre en los huecos entre ellos. Esta guía trata de esos huecos — el TTL de DNS que deberías haber bajado hace una semana, la base de datos que copiaste mientras todavía se le seguía escribiendo, el certificado que solo existe en una máquina que acabas de apagar, y las credenciales que el host antiguo ha podido leer todo este tiempo.
Los comandos asumen Debian o Ubuntu en los dos extremos y una aplicación web con una base de datos, porque eso es lo que la mayoría está migrando. Un Nextcloud, un servidor de juego, un bot o una instancia de BTCPay siguen todos la misma forma — solo cambia el paso de los datos.
Los tres relojes, y por qué la “caída cero” es el objetivo equivocado
Una migración no es un solo evento. Son tres cronómetros corriendo a velocidades distintas, y todo el oficio está en evitar que se solapen mal:
- El reloj del DNS. Desde el momento en que cambias un registro A, los resolutores siguen respondiendo con la dirección antigua hasta que su copia en caché caduca. Ese reloj no lo controlas en el momento del corte — lo controlaste cuando fijaste el TTL, días antes.
- El reloj de los datos. Tu última copia de los datos es una fotografía de un instante. Todo lo escrito después de ese instante vive solo en la máquina antigua, y se perderá a menos que lo reproduzcas o evites que ocurra.
- El reloj de las sesiones. Subidas en curso, WebSockets abiertos, un callback de pago que va a llegar dentro de cuarenta segundos desde un procesador que resolvió tu nombre de host hace dos minutos. Estos aterrizan en la máquina que haya resuelto quien los envía, no en la que tú preferirías.
Perseguir la caída cero literal significa mantener los tres corriendo a la vez, lo que en la práctica significa ejecutar la aplicación en dos servidores escribiendo a la vez en dos bases de datos. Eso es un problema genuinamente difícil, y es el equivocado para resolver en un único VPS. El objetivo honesto es más estrecho y mucho más fácil de alcanzar:
Que ningún visitante vea un error, y que no se pierda ninguna escritura. Una ventana de noventa segundos en la que el sitio está activo pero en modo de solo lectura cumple ambas cosas, y casi nadie lo notará. Un corte en caliente sin ventana de mantenimiento que pierde en silencio los últimos cuarenta minutos de envíos de formularios no cumple ninguna de las dos, y te enterarás por un cliente.
Así que el plan es: que la ventana de solo lectura sea lo más corta posible, que sea aburrida, y que sea reversible. Todo lo que viene a continuación está al servicio de esas tres cosas.
Lo que el host antiguo se queda después de que te vayas
Esta parte se suele saltar, y es la razón por la que mucha gente migra en primer lugar, así que merece la pena ser precisos al respecto. Mientras tu servidor vivió en el hardware de otro, ese proveedor estaba en posición de ver:
- El disco, entero. A menos que el volumen estuviera cifrado con LUKS y solo tú pudieras desbloquearlo, el hipervisor podía leer cada byte de él — claves, tokens, el contenido de la base de datos, todo. Incluso con cifrado, la memoria de una VM en marcha contiene la clave ya desbloqueada.
- Cada credencial que usó la máquina. Tokens de API en archivos de entorno, contraseñas SMTP, secretos RPC del daemon de la wallet, tus claves SSH públicas y, si alguna vez pegaste una en una consola de rescate, bastante más que eso.
- Todo lo que exigiera la cuenta. Un nombre, una tarjeta, una dirección, un número de teléfono para la verificación por SMS, las direcciones IP desde las que iniciaste sesión. Ese conjunto no se reduce cuando cierras la cuenta, y en la mayoría de las jurisdicciones el proveedor está obligado a conservar parte de él durante años.
Nada de esto es siniestro — es lo que significa ejecutar una máquina virtual sobre el hierro de otro, en todas partes, incluida aquí. Lo que importa es que una migración es el único punto de ruptura limpio que vas a tener. La máquina nueva empieza con claves nuevas, tokens nuevos y una IP nueva; si arrastras los secretos antiguos, arrastras con ellos la exposición antigua, y la ruptura fue solo cosmética.
Así que trata cada secreto de la máquina antigua como comprometido por defecto y reemítelo durante la mudanza. Te cuesta una hora, una vez. Hacerlo después, por separado, es una tarea a la que nadie llega nunca. Y si parte de la razón por la que te mudas es que la propia cuenta es la fuga, pagar la nueva en Monero contra una cuenta no-KYC es el paso que hace real la ruptura en lugar de simbólica — aunque sé honesto contigo mismo sobre qué compra eso y qué no, que es un tema aparte.
El reloj del TTL empieza a correr una semana antes de la mudanza
El tiempo de vida (TTL) es el número de segundos que un resolutor puede quedarse con tu registro antes de volver a preguntar. Si tu registro A tiene el TTL por defecto de 3600, en el instante en que lo cambias, un resolutor que preguntó hace un segundo seguirá enviando visitantes al servidor antiguo durante los próximos cincuenta y nueve minutos y cincuenta y nueve segundos. Con el 86400 que muchos registradores todavía traen por defecto, eso se convierte en un día entero.
Comprueba lo que tienes de verdad — no lo que crees haber configurado:
dig +noall +answer example.com A
dig +noall +answer www.example.com A
dig +noall +answer example.com MX
dig +noall +answer example.com NSLa segunda columna de cada respuesta es el TTL, contando hacia atrás. Baja cada registro implicado en la mudanza a 300 segundos, y hazlo al menos con el doble del tiempo del TTL actual antes de tu corte: si el registro está en 86400, el cambio en sí tarda un día en ser universalmente visible, que es la broma recursiva en el centro de las migraciones de DNS.
Dos detalles que atrapan a la gente:
- Los registros NS tienen su propio TTL, normalmente largo, y se fija en el registrador y no en tu zona. Eso solo importa si además estás cambiando de servidores de nombres — algo que deberías evitar hacer la misma semana que una mudanza de servidor. Cambia de host, asiéntate, y luego cambia de proveedor de DNS si quieres. Dos variables, dos fines de semana.
- La “propagación de DNS” no existe. Nada se propaga; las cachés caducan. No hay ninguna cola en la que esperar ni ningún botón que empuje una actualización más rápido. La única palanca es el TTL, y para cuando llega el corte ya está accionada.
Mientras estés en el archivo de zona, anota cada registro que apunte a la dirección IP del servidor en lugar de a un nombre. Suele haber uno más de los que recuerdas: mail, webmail, un @ a secas, un viejo staging, el registro SPF con un literal ip4: dentro, y el registro AAAA que añadiste cuando conseguiste tu primer bloque de IPv6 y luego olvidaste. Cada uno de ellos necesita un plan, y el AAAA es el clásico fallo silencioso — cambias el registro A, todo parece correcto desde tu portátil, y cada visitante con IPv6 funcionando sigue aterrizando en un servidor que ya has borrado.
Dimensionar la máquina nueva, y qué comprobar antes de comprometerte con ella
Resiste la tentación de pedir la misma especificación que tienes ahora. Estás comprando a partir de las cifras de una factura, no de lo que realmente usa la carga de trabajo. Dedica dos minutos a medir primero:
# peak RAM actually in use, not allocated
free -m
# what has been paging, if anything
vmstat -s | grep -i swap
# real disk consumption, biggest first
du -xh --max-depth=2 / 2>/dev/null | sort -rh | head -20
# load relative to core count
uptime; nprocDos reglas generales funcionan bien. Si tu promedio de carga está por debajo de tu número de núcleos y la swap nunca se ha tocado, la máquina no está limitada por CPU ni por memoria y puedes moverte hacia los lados o hacia abajo. Si el disco está por encima del setenta por ciento, dimensiona la máquina nueva según lo que vayas a necesitar dentro de un año y no según lo que usas hoy — ampliar un volumen más adelante es una migración en miniatura, y ahora mismo estás haciendo una de esas.
Por nuestra parte, eso se traduce claramente: Pup (1 vCPU, 1 GB, 25 GB) ejecuta un sitio estático, una VPN o un bot pequeño; Cub (1 vCPU, 2 GB, 40 GB) es la máquina más pequeña que aloja una aplicación junto con su propia base de datos sin hacer swap; Scout (2 vCPU, 4 GB, 70 GB) es el valor por defecto cómodo para un sitio real con tráfico real; Hunter (4 vCPU, 8 GB, 140 GB) en adelante es donde empiezan a tener sentido los contenedores, la CI o varios servicios en una sola máquina. Todos son NVMe de principio a fin con tráfico ilimitado, así que el exceso de ancho de banda — una razón habitual para mudarse en primer lugar — deja de ser una variable. Toda la gama aquí.
Luego, antes de mover un solo byte, comprueba tres cosas sobre la máquina que te acaban de dar. Cada una de ellas es barata ahora y cara después del corte:
- La reputación de la IP. Una dirección reciclada con el historial de otro hará que rechacen tu correo y pongan a prueba a tus visitantes. Las nuestras se examinan y se segmentan por riesgo antes de emitirse, pero ahora es tu servicio el que corre sobre ella, así que verifícalo tú mismo — aquí está la versión de cinco minutos. Haz esto antes del cambio de DNS, cuando la respuesta todavía no te cuesta nada.
- DNS inverso. Si la máquina va a enviar correo alguna vez, el registro PTR debe resolver a un nombre de host que a su vez resuelva de vuelta a la misma IP. El rDNS personalizado está disponible bajo petición; pídelo ahora para que se haya asentado para cuando llegue el corte.
- La ruta desde donde están tus usuarios. Un
mtrdesde una máquina en la región de tus usuarios te dice más sobre la elección de jurisdicción que cualquier hoja de datos. La latencia que puedes medir vale más que la latencia que supusiste.
Paso a paso
- Baja cada TTL, días antes de que planees mudarte
Este va primero porque es el único paso con un período de espera obligatorio. Todo lo demás se puede hacer en una tarde; este no se puede acelerar, y saltárselo es lo que convierte un corte de cinco minutos en uno de dos días.
Entra donde viva tu zona y pon el TTL a 300 en cada registro que vaya a cambiar: el
Adel ápice, elAAAA,www,mail, y cualquier otro que apunte a un literal de IP. Luego confírmalo desde fuera, porque los paneles de control y la realidad a veces no coinciden:dig +noall +answer example.com A @1.1.1.1 dig +noall +answer example.com AAAA @1.1.1.1 dig +noall +answer www.example.com A @8.8.8.8El número antes de
INes el TTL restante. Consulta otra vez un minuto después: debería estar contando hacia atrás desde 300, no desde algo mayor. Si todavía cuenta hacia atrás desde 3600, el valor antiguo está en caché y toca esperar — que es exactamente por qué esto pasa el día menos siete y no la mañana de la mudanza.Deja el TTL en 300 durante toda la migración y durante una semana después, para que tu reversión también sea rápida. Vuelve a ponerlo en algo razonable — 3600 está bien — en cuanto la máquina antigua haya desaparecido.
- Haz inventario del servidor antiguo antes de copiar nada
No estás migrando un disco, estás migrando un sistema en marcha, y las partes que la gente olvida nunca están en
/var/www. Son la tarea cron que corre el día cuatro del mes, la regla de cortafuegos añadida durante un incidente, el paquete instalado desde un repositorio de terceros hace dos años. Captura el estado de la máquina como texto, y copia ese texto junto con todo lo demás:mkdir -p /root/mig dpkg --get-selections > /root/mig/packages.txt systemctl list-units --type=service --state=running --no-pager > /root/mig/services.txt systemctl list-timers --all --no-pager > /root/mig/timers.txt crontab -l > /root/mig/cron-root.txt 2>/dev/null for u in $(cut -d: -f1 /etc/passwd); do crontab -lu "$u" 2>/dev/null | sed "s/^/[$u] /"; done > /root/mig/cron-users.txt ss -tlnp > /root/mig/listening.txt nft list ruleset > /root/mig/firewall.txt 2>/dev/null || iptables-save > /root/mig/firewall.txt cp -a /etc/hosts /etc/fstab /root/mig/ du -xh --max-depth=2 / 2>/dev/null | sort -rh | head -40 > /root/mig/disk.txtAhora lee
listening.txtlínea a línea y da cuenta de cada puerto. Ese archivo es la respuesta definitiva a “qué hace esta máquina en realidad”, y suele ser una sorpresa — un exportador de métricas, una copia de staging olvidada, una base de datos escuchando en una interfaz pública que nunca debió estarlo.Escribe tu lista de exclusión al mismo tiempo, para que la primera sincronización no se pase una hora con datos que no quieres:
cat > /root/mig/excludes <<'EOF' /dev /proc /sys /run /tmp /var/tmp /var/cache /var/lib/apt/lists /swapfile /var/lib/docker/overlay2 /var/lib/mysql /var/lib/postgresql **/node_modules **/.cache EOFFíjate en que los directorios de las bases de datos están excluidos a propósito. Tienen su propio paso, y copiarlos aquí es el error que el paso seis existe para evitar.
- Despliega el servidor nuevo y endurécelo antes de que aloje nada
Pide la máquina, elige la ubicación y usa la misma versión mayor del sistema operativo que la antigua si puedes. Migrar de host y cambiar de Debian 12 a Debian 13 en la misma operación significa que, cuando algo se rompa, no sabrás qué cambio lo causó. Muévete primero, actualiza después.
Antes de que aterrice en ella nada sensible, dale a la máquina la pasada de endurecimiento de diez minutos: SSH solo con clave, inicio de sesión de root desactivado, un cortafuegos que deniega por defecto, actualizaciones de seguridad desatendidas. Ahora mismo cuesta diez minutos, y es genuinamente tedioso aplicarlo después alrededor de un servicio ya en marcha.
Luego crea una clave que exista solo para esta migración, en el servidor antiguo, para que revocar el acceso de migración después nunca signifique tocar tu propio inicio de sesión:
# on the OLD server ssh-keygen -t ed25519 -f /root/.ssh/id_migrate -C 'migration' -N '' cat /root/.ssh/id_migrate.pubPon esa clave pública en
/root/.ssh/authorized_keysen el servidor nuevo, y luego confirma el sentido del viaje — de la antigua empuja hacia la nueva, así que la credencial vive en la máquina que estás dejando y muere con ella:ssh -i /root/.ssh/id_migrate root@NEW_IP 'hostname; df -h /; free -m'Por último, pon la IP nueva en el
/etc/hostsdel servidor antiguo, bajo un nombre comonewbox. Cada comando que venga después se vuelve más corto y, más útil todavía, más difícil de apuntar a la máquina equivocada a la una de la madrugada. - Comprueba la IP nueva antes de confiarle nada
Ahora tienes una dirección que nadie ha usado antes para tu servicio, y este es el último momento en el que encontrarle un problema sale gratis. Tres comprobaciones, cinco minutos:
Listas negras. Pasa la dirección por las comprobaciones multi-RBL — aquí está el procedimiento completo y cómo leer los resultados. Un acierto en una lista de políticas como la PBL de Spamhaus es normal para una IP de centro de datos y significa poco para el tráfico web. Un acierto en la SBL o la XBL es real, y el momento de plantearlo es ahora, no después de que tus usuarios ya estén en ella.
DNS inverso. Comprueba con qué responde la dirección hoy:
dig +short -x NEW_IPSi la máquina va a enviar correo, solicita el registro PTR que quieras y asegúrate de que coincide con un nombre de host cuyo registro A apunte de vuelta a la misma IP. Lo directo y lo inverso deben coincidir; un desajuste es peor que un nombre genérico.
Alcanzabilidad y ruta. Confirma que los puertos que necesitas están realmente abiertos de extremo a extremo, desde fuera, en lugar de asumir que tu cortafuegos es lo único que hay en el camino:
# from a third machine, or your laptop nc -vz NEW_IP 22 mtr -rwc 20 NEW_IPLa salida de
mtres la que merece la pena guardar. La pérdida en el último salto importa; la pérdida en un salto intermedio suele ser un router despriorizando el ICMP y no significa nada. Si la latencia desde la zona del mundo de tus usuarios es notablemente peor que la del host antiguo, mejor averiguarlo ahora, mientras cambiar de opinión solo cuesta un pedido y ningún dato. - Copia el sistema de archivos con rsync — simúlalo antes de ejecutarlo
Ahora la transferencia masiva. Hazlo en dos pasadas: una primera copia completa con días de antelación, tardando lo que tenga que tardar, y luego pasadas delta cortas más adelante que solo mueven lo que haya cambiado. Simula siempre la ejecución antes — la salida es una lista exacta de lo que está a punto de suceder, y leerla una vez ha salvado más migraciones que cualquier otro hábito de esta guía.
# on the OLD server, dry run rsync -aHAXx --numeric-ids --info=progress2 --dry-run \ --exclude-from=/root/mig/excludes \ -e 'ssh -i /root/.ssh/id_migrate' \ /var/www/ root@newbox:/var/www/Luego el mismo comando sin
--dry-run. Repítelo para cada directorio que importe:/etcde forma selectiva y no entero,/home,/srv,/opt, y dondequiera que tu aplicación guarde de verdad sus archivos subidos.Los flags se ganan su sitio.
-apreserva permisos, propietario, marcas de tiempo y enlaces simbólicos;-Hconserva los enlaces duros;-Ay-Xllevan las ACL y los atributos extendidos, que es lo que necesita tu directorio de subidas si alguna vez se los pusieron;-xevita que rsync se adentre en otros sistemas de archivos montados.--numeric-idses el que la gente se deja fuera y luego lamenta: sin él, rsync asigna la propiedad por nombre, y siwww-datatiene un UID distinto en las dos máquinas, cada archivo llega con el propietario equivocado, de una forma tediosa de desenredar.Dos advertencias. Copiar
/etcentero sobre un sistema en marcha sobrescribirá la configuración de red de la máquina nueva, su fstab y sus claves de host SSH — copia la configuración concreta que necesites, no el directorio. Y reserva--deletesolo para la pasada final: es correcto para que la máquina nueva coincida exactamente con la antigua, y destructivo si ya has creado algo en el destino.Cuando termine la primera pasada completa, compara los dos lados para saber que hizo lo que crees:
du -sh /var/www ssh -i /root/.ssh/id_migrate root@newbox 'du -sh /var/www' - Mueve la base de datos con un volcado, nunca con una copia de archivos
Este es el paso que decide si tu migración es aburrida o memorable. El directorio de datos de una base de datos solo es consistente cuando el servidor está detenido. Cópialo en caliente y obtienes un conjunto de archivos que parecen correctos, se transfieren bien, y restauran en una base de datos sutil y permanentemente corrupta — a menudo sin ningún error hasta semanas después.
Vuélcala como es debido. Para MySQL o MariaDB,
--single-transactiones lo que te da una instantánea consistente sin bloquearlo todo:mysqldump --single-transaction --quick --routines --triggers --events \ --default-character-set=utf8mb4 --databases appdb \ | zstd -T0 > /root/mig/appdb.sql.zstPara PostgreSQL, el formato personalizado merece la pena — comprime, y te permite restaurar de forma selectiva si lo necesitas:
pg_dump -Fc -Z6 appdb > /root/mig/appdb.dumpEnvíalo y restaura:
scp -i /root/.ssh/id_migrate /root/mig/appdb.sql.zst root@newbox:/root/ # on the NEW server zstd -dc /root/appdb.sql.zst | mysql # postgres equivalent pg_restore -d appdb -j4 /root/appdb.dumpLuego verifica, porque “la restauración ha terminado” y “los datos están ahí” son afirmaciones distintas. Compara el recuento de filas en las tablas que importan, en los dos lados:
mysql -N -e "SELECT COUNT(*) FROM appdb.orders; SELECT COUNT(*) FROM appdb.users;"Dos cosas que se esconden en los volcados: el juego de caracteres y el collation, que es de donde vienen los caracteres acentuados corruptos — si la base de datos antigua está en
utf8en lugar deutf8mb4, decide deliberadamente si la mudanza es también el momento de arreglar eso; y los usuarios y permisos de la base de datos, quemysqldump --databasesno incluye. Recrea explícitamente el usuario y la contraseña de la aplicación en la máquina nueva, y luego recuerda que la cadena de conexión de tu configuración tiene que coincidir.Si tu aplicación usa SQLite, el archivo es la base de datos y se aplica la misma regla — no lo copies en caliente. Usa
sqlite3 app.db ".backup /root/mig/app.db", que hace una copia consistente de forma segura. - Levanta la pila y ensáyala mediante una anulación con el archivo hosts
El servidor nuevo ya tiene los archivos y los datos. Arranca todo y pruébalo bajo su nombre de host real — mientras el resto del mundo sigue usando tranquilamente la máquina antigua. Este es el truco más valioso de todo el procedimiento y cuesta una sola línea.
En tu propio portátil, añade la IP del servidor nuevo a
/etc/hosts(o aC:\Windows\System32\drivers\etc\hosts):203.0.113.10 example.com www.example.comTu navegador ahora resuelve el dominio real hacia el servidor nuevo, y el de nadie más lo hace. Cada URL es correcta, cada dominio de cookie coincide, cada ruta de redirección y de callback se comporta como lo hará después del corte — que es precisamente lo que no detecta probar contra un subdominio temporal
new.example.com, porque la mitad de lo que se rompe en una migración depende del nombre de host.Para una comprobación rápida y puntual sin editar nada,
curlpuede hacer lo mismo al vuelo:curl -sSI --resolve example.com:443:203.0.113.10 https://example.com/ curl -sS --resolve example.com:80:203.0.113.10 http://example.com/ -o /dev/null -w '%{http_code}\n'Recorre la aplicación entera, no solo la portada: inicia sesión, envía un formulario, sube un archivo, dispara un correo de restablecimiento de contraseña, carga una página de administración, golpea el endpoint que llama un procesador de pagos. Luego lee los registros de error aunque todo parezca correcto — extensiones de PHP que faltan, un modo de archivo incorrecto en un directorio de caché y un usuario de base de datos que todavía no existe, todo eso aparece ahí antes de aparecer en pantalla.
Recuerda quitar después esa línea del archivo hosts. Todo el mundo se olvida una vez, y luego se pasa veinte minutos preguntándose por qué la reversión parece no haber funcionado.
- Consigue que el TLS funcione en la máquina nueva antes de cambiar nada
Los certificados están ligados a nombres, no a direcciones IP, así que nada de una migración invalida un certificado que ya tengas. Lo que se rompe es la emisión: el desafío HTTP-01 habitual le pide a Let's Encrypt que descargue un archivo por el puerto 80 en el nombre que se está certificando, y ese nombre todavía apunta al servidor antiguo. El dilema del huevo y la gallina es toda la dificultad, y hay tres salidas limpias.
Copia los certificados existentes. La más simple y normalmente la correcta. La clave privada y la cadena se mueven como cualquier otro archivo:
rsync -aHAX -e 'ssh -i /root/.ssh/id_migrate' \ /etc/letsencrypt/ root@newbox:/etc/letsencrypt/El servidor nuevo puede servir TLS válido de inmediato, y la renovación empieza a funcionar por sí sola en cuanto el DNS apunte a él. Confirma que el temporizador está activado ahí:
systemctl list-timers | grep certbot.Usa un desafío DNS-01. Demuestra el control del dominio mediante un registro TXT en lugar de una petición HTTP, así que funciona desde un servidor al que todavía nada apunta. Ideal si quieres un certificado genuinamente independiente en la máquina nueva antes del corte, y la única opción para un comodín.
Emítelo después del cambio. Válido, pero deja un hueco en el que el sitio está en marcha en la IP nueva sin certificado, lo que para cualquier cosa con HSTS no es una advertencia que tus visitantes puedan sortear con un clic. Solo tiene sentido para un dominio totalmente nuevo que nadie ha visitado.
Elijas lo que elijas, verifícalo contra la IP nueva directamente antes del corte, usando el mismo truco de
--resolve:curl -sSI --resolve example.com:443:203.0.113.10 https://example.com/ | head -1 echo | openssl s_client -connect 203.0.113.10:443 -servername example.com 2>/dev/null \ | openssl x509 -noout -subject -datesComprueba las fechas y que el subject cubre cada nombre que sirves,
wwwincluido. Y si usas HSTS con un max-age largo, trata el certificado como lo único que tiene que estar bien antes del cambio y no después — esa cabecera es una promesa que ya le hiciste a cada visitante recurrente. - El corte: congela las escrituras, delta final, cambia el registro
Diez minutos de trabajo real, y la única parte con un reloj corriendo. Hazlo por la mañana, en tu propia zona horaria, un día en el que no estés ocupado por otro lado. Nunca en viernes.
Congela. Pon la aplicación antigua en modo de mantenimiento o de solo lectura. Detén los workers, los consumidores de colas y las tareas cron — cualquier cosa que escriba sin un navegador de por medio. A partir de aquí, no se escribe nada nuevo en la máquina antigua, que es lo que hace seguro todo lo que viene después:
# on the OLD server systemctl stop app-worker.service systemctl stop cron touch /var/www/maintenance.flagDelta final. Un rsync más, ahora con
--deletepara que el destino coincida exactamente, y un volcado más. Con la primera pasada hecha días antes, esto mueve muy poco y tarda segundos:rsync -aHAXx --numeric-ids --delete --exclude-from=/root/mig/excludes \ -e 'ssh -i /root/.ssh/id_migrate' /var/www/ root@newbox:/var/www/ mysqldump --single-transaction --quick --routines --triggers --events \ --default-character-set=utf8mb4 --databases appdb | zstd -T0 \ | ssh -i /root/.ssh/id_migrate root@newbox 'zstd -dc | mysql'Comprueba. El recuento de filas en los dos lados, un repaso más de la aplicación mediante la anulación con el archivo hosts, y quita el flag de mantenimiento en la máquina nueva.
Cambia. Cambia el registro
Aa la IP nueva. Cambia también el registroAAAA— esta es la forma más habitual en que un corte se queda a medias. Confírmalo desde un resolutor que no controles:dig +short example.com A @1.1.1.1 dig +short example.com AAAA @1.1.1.1Luego vigila las dos máquinas. El tráfico debería aparecer en la nueva en uno o dos minutos, y desvanecerse de la antigua en los cinco siguientes:
tail -f /var/log/nginx/access.log # on both, side by sideDeja la aplicación antigua en modo de mantenimiento en lugar de apagarla. Un rezagado que llegue hasta ahí verá una página educada en lugar de un error de conexión, y mantienes la máquina disponible para la reversión que probablemente no vayas a necesitar.
- Vigila una semana y luego retira el servidor correctamente
La migración no termina cuando el DNS resuelve. Termina cuando ha pasado un ciclo completo de facturación y de cron sin ninguna sorpresa.
Durante las primeras horas, vigila las tasas de error en lugar del uptime — un servidor puede estar perfectamente arriba y devolviendo 500 a un tercio de las solicitudes:
journalctl -u nginx -u php8.4-fpm -f awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | headLuego repasa una lista corta, porque esto es lo que de verdad se rompe después de una mudanza y nada de ello se anuncia solo: tareas cron y temporizadores de systemd corriendo en la máquina nueva (
systemctl list-timerscontra el inventario que hiciste en el paso dos); correo saliente que llega y no cae en spam; copias de seguridad programadas apuntando a la máquina nueva en lugar de seguir archivando la antigua; cualquier tercero con tu dirección IP en una lista de permitidos — un procesador de pagos, una API, el cortafuegos de un socio; y la tarea mensual que solo se demuestra a sí misma el día uno del mes.Deja el servidor antiguo en marcha, en modo de mantenimiento, sin tocar, durante al menos una semana. Es tu reversión y tu copia de referencia, y vale más que los pocos dólares que cuesta. Luego ciérralo en orden: rota cada secreto que pudiera haber leído, haz un último archivo cifrado hacia una tercera ubicación, sobrescribe los directorios de la aplicación y de la base de datos, ejecuta la rutina de destrucción o reinstalación del proveedor, y solo entonces cancela — después de comprobar la fecha de renovación, porque un mes extra de seguro de reversión suele ser el mejor cambio.
Por último, vuelve a subir el TTL a 3600 ahora que ya no necesitas reversibilidad de cinco minutos, y actualiza la documentación que conserves con la dirección nueva. El tú del futuro, en alguna madrugada posterior, te lo agradecerá muchísimo cuando el runbook coincida con el servidor.
El correo no migra con el resto
Si el servidor antiguo enviaba correo — aunque solo fuera para restablecer contraseñas — trata eso como una segunda migración, más lenta, corriendo en paralelo a la primera. La entregabilidad es un sistema de reputación, y la reputación está ligada a la dirección IP y al dominio, no al software que copiaste.
Cuatro registros deciden si tu correo se lee o se descarta, y tres de ellos contienen cosas que cambian cuando cambia el servidor:
- SPF enumera quién puede enviar en nombre de tu dominio. Si el tuyo contiene un literal
ip4:, ahora está mal. Añade la IP nueva antes del corte y elimina la antigua una semana después — tener las dos direcciones autorizadas durante unos días no cuesta nada y cubre el solape. - DKIM firma el mensaje con una clave privada. Copia la clave junto con el resto de la configuración y el selector sigue funcionando. Si en cambio generas una clave nueva, tienes que publicar el selector nuevo y esperar a que se propague, así que cópiala salvo que tengas una razón para no hacerlo.
- DMARC dice a los receptores qué hacer cuando los dos primeros fallan. Si estás en
p=reject, un SPF roto durante la ventana no es una advertencia, es un borrado silencioso. Considera bajar ap=nonedurante la semana de la migración y volver a subirlo después. - PTR es el registro inverso de arriba. Una IP nueva tiene uno genérico hasta que lo pidas, y varios proveedores grandes rechazan directamente el correo que viene de nombres inversos genéricos.
La expectativa honesta: una IP totalmente nueva empieza sin reputación alguna, que no es lo mismo que tener una buena. El volumen se acelera a lo largo de días, no de horas. Si el correo es crítico para ti, mantén el servidor antiguo vivo y enviando durante una semana después de la mudanza en lugar de cambiar de un solo paso — y si es crítico para el negocio, un relay dedicado es mejor respuesta que cualquiera de las dos máquinas.
Revertir sin empeorar las cosas
El sentido de tener un plan de reversión no es que esperes usarlo. Es que tenerlo te permite hacer el corte con calma a las 10 de la mañana en lugar de nervioso a las 2 de la madrugada, y la calma es lo que de verdad evita los errores.
Tu reversión es sencilla, y sigue siendo sencilla durante exactamente el tiempo en que la base de datos antigua siga siendo la autoritativa: vuelve a cambiar el registro A. Con un TTL de 300 segundos, te recuperas en cinco minutos. Esa ventana — entre el cambio y la primera escritura que solo existe en la máquina nueva — es tu deshacer gratuito, y por eso el servidor antiguo sigue funcionando, intacto y sin borrar, durante al menos una semana.
Lo que lo arruina es el split-brain: escrituras que caen en las dos máquinas. Ahora ninguna de las dos bases de datos es correcta, y reconciliarlas a mano es peor que cualquier caída que estuvieras evitando. Tres hábitos lo evitan por completo:
- Pon la aplicación antigua en modo de solo lectura o de mantenimiento al empezar la ventana, en lugar de confiar en que el DNS haya dejado de enviar tráfico. El DNS es una pista; un servicio detenido es un hecho.
- Después del cambio, vigila el registro de acceso del servidor antiguo, no el nuevo. Las solicitudes que todavía lleguen ahí son tus rezagadas, y cuando ese goteo se detenga, la migración habrá terminado de verdad.
tail -f /var/log/nginx/access.loges toda la herramienta que hace falta. - En cuanto aceptes la primera escritura real en la máquina nueva, revertir deja de ser un cambio de DNS — pasa a ser una restauración. Decide conscientemente cuándo cruzas esa línea, y dilo en voz alta si sois dos.
Ponte una regla de parada antes de empezar: si la pila nueva no está sirviendo correctamente en, digamos, treinta minutos, reviertes el registro, recuperas la tarde, y lo arreglas sin ningún reloj corriendo. Las migraciones salen mal cuando la gente sigue insistiendo hacia adelante porque volver atrás parece un fracaso. No lo es; es la opción barata, y solo está disponible durante un tiempo estrictamente limitado.
Dar de baja: rota, borra, verifica y luego cancela
Una semana después del corte, el servidor antiguo es una copia completa, en marcha y sin vigilancia de tus datos, sobre una infraestructura a la que ya has dejado de prestar atención. En ese punto, además, es la máquina menos parcheada que tienes. Termina el trabajo en este orden:
- Rota todo lo que la máquina antigua pudiera leer. Secretos de la aplicación, tokens de API, contraseñas de bases de datos, credenciales SMTP, secretos de firma de webhooks, cualquier contraseña RPC de wallet. Asume que se han filtrado, porque no puedes probar lo contrario. Si generaste una clave SSH nueva para la migración, este es el momento en que retiras las claves autorizadas antiguas.
- Haz un último archivo — una instantánea cifrada con restic o Borg hacia un destino que no sea ninguna de las dos máquinas. La vas a necesitar exactamente una vez, seis semanas después, para un archivo que nadie recordaba.
- Sobrescribe los datos. En un VPS no puedes verificar el medio físico, así que haz lo que puedas: usa
shredo sobrescribe los directorios de la aplicación y de la base de datos, y luego deja correr la rutina de reinstalación o destrucción del proveedor. El cifrado en reposo desde el principio es lo que hace esto barato; sin él, dependes de la política de borrado de otro. - Verifica, y luego cancela. Confirma que la máquina nueva lleva sirviéndolo todo una semana completa, incluido el cron mensual en el que nadie piensa, y confirma que nada en la máquina antigua sigue resolviendo. Luego cancela — y comprueba antes la fecha de renovación, porque pagar un mes extra de seguro de reversión suele ser más inteligente que ahorrarte ocho dólares.
Elimina la cuenta antigua en sí al final, y solo cuando estés seguro. Los tickets de soporte, las facturas y algún subservicio olvidado suelen vivir ahí, y una cuenta en la que no puedes iniciar sesión es un lugar incómodo para descubrir un registro DNS que olvidaste mover.
Un calendario que funciona
Repartido a lo largo de una semana, nada de esto da estrés. Comprimido en una sola tarde, todo lo da.
- Día −7. Baja cada TTL a 300. Haz inventario del servidor antiguo. Pide el nuevo y comprueba su IP, su rDNS y su ruta.
- Día −5. Endurece la máquina nueva. Instala la pila. Primer
rsynccompleto, que es el lento — cada pasada posterior solo mueve el delta. - Día −3. Restaura un volcado de base de datos en la máquina nueva y levanta la aplicación. Prueba todo el conjunto mediante una anulación con el archivo hosts. Arregla lo que esté roto mientras no hay nada en juego, porque algo lo habrá.
- Día −1. Emite el TLS en el servidor nuevo. Confirma la cadena de certificados y, si la usas, que el HSTS no vaya a convertir un pequeño error en uno imposible de sortear con un clic. Añade la IP nueva al SPF. Vuelve a comprobar que todos los TTL han bajado de verdad.
- Día 0, por la mañana. Modo de mantenimiento en la máquina antigua. Sincronización delta final. Volcado y restauración finales. Comprobación del recuento de filas. Cambia el registro A — y el AAAA. Vigila los dos registros de acceso.
- Día +1 a +7. El servidor antiguo sigue en marcha, intacto. Vigila los registros, el correo y la reputación de la IP nueva. Deja que las tareas mensuales corran al menos una vez si puedes.
- Día +7. Rota los secretos, haz el archivo final, borra, verifica, cancela.
El mejor indicador de una migración aburrida es que el paso uno ocurrió una semana antes que el paso cinco. Casi todo lo que sale mal en una mudanza de servidor es un TTL que a las once de la noche todavía estaba en 86400.
Preguntas frecuentes
¿Puede una migración de VPS tener de verdad cero caídas?
Un cero literal, con escrituras aceptadas de forma continua en las dos máquinas, exige replicación y una base de datos compartida o en clúster — un problema genuinamente difícil, y el equivocado para un servidor único. Lo que sí es alcanzable, de forma fiable, es que ningún visitante vea un error y no se pierda ninguna escritura: una ventana breve de solo lectura durante la sincronización final, con el DNS ya en un TTL de 300 segundos para que el cambio en sí tarde minutos. En la práctica son de uno a cinco minutos de página de mantenimiento, que en casi cualquier sitio es indistinguible de cero y muchísimo más seguro que la alternativa.
¿Cuánto tarda en realidad la propagación del DNS?
No existe la propagación. No se empuja nada a ningún sitio — los resolutores simplemente guardan tu registro en caché durante el número de segundos que especifica tu TTL, y vuelven a preguntar cuando caduca. Así que la respuesta honesta es “lo que dure el TTL que estuviera vigente cuando hiciste el cambio”. Con un TTL de 300 fijado una semana antes, esencialmente todo el mundo está en la dirección nueva en cinco minutos. Con el 86400 que muchos registradores todavía traen por defecto, algunos resolutores siguen enviando tráfico al servidor antiguo durante un día entero. Por eso bajar el TTL es el paso uno y no el paso nueve.
¿Puedo conservar mi dirección IP al cambiar de host?
No, a menos que seas dueño tú mismo del espacio de direcciones y puedas hacer que el proveedor nuevo lo anuncie, lo que significa ser miembro de RIPE o ARIN con tu propia asignación — realista para una empresa, no para un servidor único. Para todos los demás, un host nuevo significa una IP nueva, que es precisamente por lo que compruebas su reputación y su DNS inverso antes del corte y no después. Por nuestra parte, las direcciones se examinan contra Spamhaus y más de un centenar de otras listas, y se emiten desde pools segmentados por riesgo en lugar de reciclarse de quien las tuviera antes, pero verificarlo tú mismo lleva cinco minutos y siempre merece la pena.
¿Debería usar en su lugar una imagen de disco o una herramienta de migración del proveedor?
Si los dos extremos son el mismo proveedor y el mismo hipervisor, restaurar una imagen está bien y es mucho más rápido. Entre proveedores distintos suele ser una trampa: la imagen arrastra la configuración de red de la máquina antigua, sus módulos de kernel, sus controladores y sus suposiciones sobre el hardware, y te pasas la tarde depurando un sistema que arranca pensando que está en una máquina que ya no existe. Una instalación limpia más una copia meditada de tus datos y tu configuración te da un servidor que entiendes, y elimina la porquería acumulada del anterior. Migrar es la oportunidad más barata que vas a tener nunca para dejar cosas atrás.
¿Y una base de datos a la que se está escribiendo constantemente?
Dos opciones, en orden ascendente de esfuerzo. La sencilla es la ventana de solo lectura del paso nueve: un volcado con --single-transaction de una base de datos ocupada pero de tamaño normal tarda de segundos a un par de minutos, y una página de mantenimiento durante ese tiempo es un intercambio justo. La minuciosa es la replicación — configura el servidor nuevo como réplica con días de antelación, deja que se mantenga sincronizado, y luego promociónalo durante la ventana. Eso reduce la congelación a segundos, a costa de una configuración genuinamente más compleja. Elige la segunda solo si la primera no es aceptable, y nunca la improvises la noche del corte.
¿Cambiar de host perjudicará mi posicionamiento en buscadores?
No por sí solo. Google indexa nombres de host, no direcciones IP, y una mudanza en la que las URL y el contenido se mantienen idénticos resulta prácticamente invisible. Lo que sí te cuesta caro es lo que suele acompañar a una mala migración: páginas devolviendo 5xx mientras los rastreadores están de visita, un error de certificado, un robots.txt que llegó de una copia de staging con Disallow: / dentro, o redirecciones que cambiaron de forma en silencio. Comprueba robots.txt, tus etiquetas canonical y un puñado de URL reales justo después del cambio. Si el sitio sirve las mismas respuestas en la IP nueva que en la antigua, no hay nada de lo que recuperarse.
¿Mis certificados TLS siguen funcionando en el servidor nuevo?
Sí — los certificados se emiten para nombres de dominio, no para direcciones IP, así que copiar /etc/letsencrypt te da un certificado válido en la máquina nueva de inmediato. La complicación es la renovación, no la validez: un desafío HTTP-01 necesita que el dominio apunte a la máquina que hace la renovación, así que hasta que cambies el DNS, la renovación fallará ahí. Copia los certificados antes del corte, haz el cambio, y luego confirma que el temporizador de renovación se ejecuta correctamente en el servidor nuevo. Si necesitas un certificado independiente antes del cambio — o un comodín — usa en su lugar un desafío DNS-01.

