A cópia é a parte fácil — o que realmente causa o downtime
Pergunte a alguém quanto tempo a migração dele vai levar, e a resposta vai ser uma estimativa da transferência. Duzentos gigabytes em um link de um gigabit, digamos quarenta minutos, mais uma hora de folga. Esse número costuma estar certo e quase nunca é o número que importa, porque a transferência acontece enquanto o servidor antigo ainda está respondendo requisições. Ninguém fica fora do ar durante a cópia. As pessoas ficam fora do ar durante o intervalo entre a máquina nova estar correta e a internet concordar com isso, e a duração desse intervalo é definida por caches que você não controla.
Quatro modos de falha respondem pela maioria das indisponibilidades reais de migração, e nenhum deles é banda. Um registro DNS cujo time-to-live ainda estava em um dia quando você o alterou, de modo que uma parcela relevante do mundo continua se conectando a uma máquina que você já desligou. Um banco de dados que recebeu escritas depois que você tirou o dump dele, de modo que o novo host começa a vida com uma cópia discretamente desatualizada, e você só descobre quais vinte minutos estão faltando através da reclamação de um cliente. Um certificado TLS e sua chave de conta ACME que existiam só no disco antigo, de modo que o novo host apresenta uma incompatibilidade de nome para cada navegador. E uma integração de saída — uma processadora de pagamentos, um SFTP de banco, uma API de parceiro, um banco de dados em um terceiro provedor — que foi colocada em allowlist por endereço IP, o que falha silenciosamente no ponto mais distante possível da mudança que causou a falha.
Vale a pena ser direto sobre a frase que todo mundo usa. “Migração zero-downtime” quase sempre significa alguns segundos de conexões recusadas que nenhum humano percebeu, e esse é um objetivo perfeitamente bom para mirar. Zero de verdade exige as duas máquinas servindo corretamente ao mesmo tempo, o que exige uma aplicação que tolere ser duas máquinas: nenhum estado de sessão local, nenhum diretório de upload local que só um dos lados tenha, e um banco de dados que replica ou vive em outro lugar completamente à parte. A maioria das stacks self-hosted não alcança essa barra, e o plano honesto é um congelamento curto, controlado e ensaiado, em vez de um projeto de arquitetura que você não pretendia começar.
Então o formato de uma boa migração não tem nada de genial. Construa a máquina nova cedo e prove que ela funciona enquanto a antiga carrega a carga. Reduza a parte irreversível a poucos minutos de comandos de script. Mude uma coisa de cada vez. E mantenha a capacidade de voltar atrás, com uma data a partir da qual você para de pagar por ela.
Inventário: as partes de um servidor que não estão no seu repositório
Seu repositório de deploy descreve a aplicação. Ele não descreve a máquina. Em algum ponto entre o primeiro apt install e hoje, um servidor acumula uma camada que nenhum controle de versão jamais viu: pacotes instalados manualmente para resolver um problema pontual, uma unit do systemd que alguém escreveu às pressas, uma tarefa cron rodando sob uma conta de serviço, regras de firewall, ajustes de sysctl, um locale, um fuso horário, um arquivo de swap, certificados TLS, chaves de host SSH, roles e grants do banco de dados, e um diretório de mídia que não está no repositório justamente porque foram os usuários que o colocaram lá. Migrar significa reproduzir essa camada de forma deliberada, e a única maneira de fazer isso deliberadamente é anotar tudo primeiro.
Cinco comandos cobrem quase tudo. dpkg --get-selections no Debian e no Ubuntu, ou dnf repoquery --userinstalled no Rocky e no Alma, dá a você o conjunto de pacotes. systemctl list-unit-files --state=enabled dá a você tudo que está configurado para iniciar no boot, o que é uma pergunta melhor do que “o que está rodando”, porque inclui a coisa que está travada no momento. crontab -l -u para cada conta em /etc/passwd, mais o conteúdo de /etc/cron.d e de cada unit .timer, dá a você o trabalho agendado. nft list ruleset ou ufw status numbered dá a você o firewall. E ss -tulpn dá a você o que está de fato escutando, que é como você descobre o serviço que esqueceu que existia. Escreva os cinco em arquivos e copie-os para fora da máquina, não para dentro dela.
Depois há o inventário que ninguém anota, que é justamente o que morde semanas depois: tudo, em qualquer lugar, que confia no seu endereço IP atual. Gateways de pagamento com allowlists de IP. Um banco de dados gerenciado em outro provedor cujas regras de acesso citam o endereço antigo. Um relay SMTP que autentica pela rede. Um serviço de monitoramento, um remetente de webhook que só publica para endereços conhecidos, o firewall de um colega. Faça grep na sua própria configuração e documentação atrás do endereço antigo, depois confira o painel de controle de cada serviço de terceiros que você paga. Essas coisas quebram depois do corte, de forma assíncrona, no momento em que a integração rodar de novo — por isso são tão frequentemente diagnosticadas como “outra coisa deu errado ao mesmo tempo”.
Por fim, capture a própria zona DNS. Exporte-a ou, no mínimo, anote cada tipo de registro, valor e TTL, porque uma migração é exatamente o momento em que alguém percebe um registro que está errado há dois anos e, prestativamente, o corrige no meio de tudo o mais.
| O que inventariar | Onde isso vive | O que quebra se você esquecer |
|---|---|---|
| Pacotes instalados manualmente | Banco de dados de pacotes | Um serviço se recusa a iniciar no novo host por causa de uma biblioteca que ninguém lembra de ter instalado. |
| Units e timers habilitados | systemd | O trabalho em segundo plano para silenciosamente: sem backups, sem renovação de certificado, sem worker de fila. |
| Tarefas cron por usuário | Crontabs por conta | Tarefas noturnas somem e só são percebidas no fim do mês. |
| Conjunto de regras do firewall | nftables ou ufw | Ou uma porta fica fechada e o app parece quebrado, ou tudo fica aberto. |
| Certificados TLS e chave de conta ACME | Diretório de certificados | Os navegadores mostram uma incompatibilidade de nome, e as renovações começam uma conta do zero. |
| Roles e grants do banco de dados | Globais do servidor, não o dump | Os dados são restaurados perfeitamente e a aplicação não consegue fazer login neles. |
| Allowlists de IP de terceiros | Painéis de outras empresas | Pagamentos, webhooks e APIs de parceiros falham horas ou dias depois. |
| Zona DNS com os TTLs | Seu provedor de DNS | Você não consegue saber quais registros ainda precisam ser movidos, nem por quanto tempo ficam em cache. |
Baixe o TTL do DNS primeiro — e entenda por que isso precisa acontecer dias antes
Um resolvedor recursivo guarda em cache uma resposta pelo time-to-live que recebeu, e não tem nenhuma obrigação de perguntar de novo antes que esse prazo expire. Isso tem uma consequência que pega quase todo mundo na primeira vez: baixar o TTL de um registro de 86400 para 300 não muda absolutamente nada para um resolvedor que colocou a resposta antiga em cache dez minutos atrás. Esse resolvedor guarda a resposta de um dia inteiro por mais vinte e três horas e cinquenta minutos, e só depois disso toma conhecimento do seu novo TTL de cinco minutos. Por isso, o TTL baixo precisa ser publicado pelo menos um TTL antigo inteiro antes de você pretender mover qualquer coisa. Se os seus registros estão em um TTL de um dia, a primeira ação da migração acontece dois dias antes do corte, e é uma mudança de uma linha só.
Faça isso para todo registro que aponta para a máquina, não só para aquele que você tem em mente. O registro A e o registro AAAA — um endereço IPv6 esquecido apontando para o host antigo é um bug lindamente confuso, porque clientes dual-stack vão preferi-lo silenciosamente, e só uma parte dos seus usuários será afetada. Os registros MX. Qualquer CNAME na frente deles, lembrando que um cliente seguindo uma cadeia fica sujeito ao TTL de cada elo dela, então um registro A de cinco minutos atrás de um CNAME de um dia ainda equivale, na prática, a um dia inteiro. E se você também estiver trocando de provedor de DNS, não faça isso na mesma semana: a delegação de nameservers e os registros glue ficam em cache na zona pai segundo o próprio cronograma dela, e combinar as duas mudanças significa que, quando algo quebrar, você não vai saber qual delas foi a causa.
Verifique em vez de presumir. dig +noall +answer example.com A mostra o que um resolvedor guarda no momento e a contagem regressiva restante; consultar diretamente o seu servidor autoritativo com dig @ns1.example.net example.com A mostra o que você realmente publicou. Se os dois divergirem, você está olhando para o cache, e o número ao lado do registro é exatamente quanto tempo falta esperar.
Vale reservar espaço no planejamento para duas nuances. Alguns resolvedores aplicam um piso ao TTL: uma fração dos forwarders de provedores de internet e de redes corporativas impõe um TTL mínimo, independentemente do que você publica — o que é tecnicamente desaconselhado, mas inteiramente real. E, sob a RFC 8767, um resolvedor pode deliberadamente servir uma resposta obsoleta quando não consegue alcançar os seus servidores autoritativos — um ótimo comportamento para resiliência, inconveniente no dia em que você quer que uma mudança se propague. Somando as duas coisas, planeje para uma cauda longa medida em horas, ocasionalmente um dia, depois que o grosso do tráfego já tiver se mudado. Essa cauda não é um problema, contanto que a máquina antiga continue respondendo corretamente, que é exatamente por isso que ela permanece no ar. A RFC 2181 é a referência para como os TTLs devem se comportar quando as implementações divergem entre si.
| Quando | Ação | Por que nesse momento |
|---|---|---|
| T menos 7 dias | Inventariar o servidor antigo; escrever o runbook | Tudo que se descobre aqui muda o plano, então precisa acontecer antes de o plano ser fechado. |
| T menos 3 dias | Provisionar o novo VPS; primeira restauração; ensaiar | Deixa tempo para reconstruir a máquina uma segunda vez quando o ensaio encontra lacunas. |
| T menos 2 dias | Baixar os TTLs de A, AAAA e MX para 300 | Um TTL antigo inteiro precisa transcorrer antes de o valor baixo estar em todo cache. |
| T menos 1 dia | Primeira passada de rsync; iniciar a replicação do banco de dados | Longa e sem supervisão, com o servidor antigo ainda carregando o tráfego de produção. |
| T zero | Congelar escritas, sincronização final, verificar, mudar o DNS | A única janela irreversível; é curta porque tudo acima já aconteceu. |
| T mais 1 hora | Observar os dois logs de acesso | A decadência do tráfego no host antigo é a sua medida real da expiração do cache. |
| T mais 7 dias | Descomissionar o host antigo; restaurar os TTLs | O rollback expirou; um TTL permanente de 300 segundos custa latência sem nenhum benefício. |
Ensaie na máquina nova enquanto a antiga ainda está no ar
O hábito isolado de maior valor em todo esse processo é que a máquina nova existe e funciona dias antes de isso importar. Um VPS é, na prática, um aluguel por hora: nos nossos planos um servidor fica ativo cerca de sessenta segundos depois da confirmação do pagamento, não há taxa de setup nem contrato, então um ensaio de três dias em um plano de $8.50 custa cerca de um dólar. É uma forma notavelmente barata de transformar cada incógnita da sua migração em algo conhecido antes de o relógio começar a correr.
Teste por hostname, não por IP. Navegar até o endereço do servidor novo mostra a você o virtual host padrão, nenhum match de SNI, um aviso de certificado e um conjunto de rotas que pode não se parecer nada com a produção — e vai convencer você alegremente de que algo funciona quando não funciona. A ferramenta certa é um override de resolvedor. curl --resolve fixa um hostname a um endereço para um único comando, então curl --resolve example.com:443:203.0.113.10 https://example.com/ exercita o nome real, o handshake TLS real e o virtual host real contra a máquina nova, enquanto o resto do mundo ainda alcança a antiga. Para testes interativos, uma linha no arquivo hosts do seu computador faz o mesmo trabalho para um navegador.
O que o ensaio pega de forma confiável é a camada não documentada acumulada, descrita na seção anterior. Um daemon que está rodando desde antes do último reboot e que, na verdade, não está habilitado. Uma tarefa cron que depende de um transporte de e-mail local para reportar falhas. A propriedade de arquivos que sobreviveu à cópia como números, mas que significa outra coisa em uma máquina com um /etc/passwd diferente. Um endereço fixo (hardcoded) em um arquivo de configuração. Um banco de dados que foi criado com um character set em uma versão que tinha um padrão diferente. Uma versão menor de Python ou PHP que depreciou algo que você usa. Cada um desses itens custa dez minutos para corrigir durante um ensaio e uma hora para diagnosticar durante um corte.
Um teste vale mais que todos os outros: construa a máquina nova duas vezes. Reconstrua-a do zero usando apenas o seu inventário e o seu backup, sem olhar para o servidor antigo. Se ela subir correta na segunda vez, o seu inventário é real e o seu runbook é executável. Se não subir, você acabou de encontrar a lacuna em uma situação em que encontrá-la não custa nada. Tire um snapshot assim que estiver certo — os snapshots por hora com retenção de sete dias estão incluídos em todos os planos, e uma restauração leva cerca de trinta segundos — para que qualquer experimento posterior na máquina nova também seja reversível.
rsync duas vezes: uma passada longa enquanto o serviço roda, uma curta na janela
O padrão de duas passadas é o que mantém a janela de manutenção curta. A primeira passada roda com o serviço totalmente no ar e pode levar o tempo que precisar — horas, a noite inteira, um fim de semana inteiro. A segunda passada roda durante o congelamento e transfere só o que mudou desde a primeira, o que, em uma carga de trabalho normal, é uma fração pequena dos dados e um número previsível de minutos. Você está trocando uma cópia longa e sem supervisão por uma curta e supervisionada, e essa troca quase sempre vale a pena.
As flags importam mais do que as pessoas esperam. rsync -aHAX --numeric-ids é a base: -a para o modo archive, -H para preservar hardlinks — o que importa enormemente para armazenamentos Maildir e para árvores de backup deduplicadas, onde perdê-los pode multiplicar o uso do seu disco — -A para ACLs POSIX, -X para atributos estendidos como labels do SELinux e capabilities de arquivo, e --numeric-ids para que um user ID seja copiado como número em vez de ser resolvido pelo banco de usuários da origem e resolvido de novo por um banco diferente no destino. Adicione --info=progress2 para uma única linha de progresso sensata e --partial para que uma transferência interrompida retome em vez de recomeçar do zero. Deixe -z desligado a menos que o link seja genuinamente lento: comprimir mídia já comprimida e arquivos criptografados só move o gargalo para a CPU.
Use --delete só na segunda passada. Na primeira passada, é um tiro no pé sem nenhuma vantagem, porque não há nada no destino que precise ser removido. Na segunda passada, é essencial: sem ele, um arquivo que você apagou no servidor antigo entre as duas passadas vive para sempre no novo, que é como uma migração acaba servindo conteúdo que tinha sido removido de propósito.
O que você não deve fazer é dar rsync no filesystem raiz inteiro. É um atalho popular, e ele produz uma máquina sobre a qual ninguém consegue raciocinar. Mesmo excluindo /proc, /sys, /dev, /run e /tmp, você acaba com um sistema cujo kernel e initramfs vieram de um host, cuja nomenclatura de interface de rede foi derivada de um hardware diferente, cujo /etc/machine-id agora está duplicado entre duas máquinas ativas, e cujos cinco anos acumulados de configuration drift você acabou de pagar para preservar. Migre os dados e a configuração que você inventariou; instale o sistema operacional do zero, a partir de um template. Isso leva uma hora a mais, dá a você uma base moderna e limpa, e significa que o servidor novo é uma máquina que você entende, em vez de uma cópia de uma que você não entendia.
Verifique a cópia em vez de confiar no exit code. Depois das duas passadas, rode o mesmo comando de novo com -n --checksum --itemize-changes: um dry run que compara conteúdo em vez de timestamps e imprime uma linha por diferença. Silêncio é o resultado que você quer, e isso é uma afirmação bem mais forte do que du -s batendo dos dois lados.
O banco de dados é a parte que o rsync não consegue ajudar
Copiar o diretório de um banco de dados ativo no nível de arquivo dá a você uma cópia inconsistente: algumas páginas escritas, outras não, sem nenhuma garantia de que qualquer parte disso forma um limite de transação consistente. O InnoDB pode muito bem se recuperar disso e parecer funcionar bem, o que é pior do que simplesmente falhar, porque você só vai descobrir no dia em que a recuperação não funcionar. Existem exatamente duas estratégias honestas — tirar um dump transacionalmente consistente, ou replicar — e a escolha entre elas é uma escolha sobre quanto downtime você está comprando.
Para o caminho do dump no MySQL e no MariaDB, o mysqldump --single-transaction --routines --triggers --events dá um snapshot consistente sem travar o servidor inteiro, com duas ressalvas que vale a pena conhecer: ele só é consistente para tabelas transacionais, então uma única tabela legada em MyISAM quebra a garantia silenciosamente, e qualquer statement DDL executado durante o dump também a quebra. No PostgreSQL, o pg_dump -Fc cuida de cada banco de dados, e o pg_dumpall --globals-only cuida da metade que as pessoas esquecem — roles, senhas, grants e tablespaces vivem no nível do cluster, não dentro de nenhum banco de dados específico, então uma restauração sem eles produz dados perfeitos aos quais a aplicação não consegue se autenticar.
O número que decide a sua janela não é o tamanho do dump, é dump mais transferência mais restauração mais reconstrução de índice, e o último desses costuma ser o maior. Meça isso durante o ensaio, no dataset real, em vez de estimar. Alguns gigabytes são minutos; cem gigabytes com indexação substancial podem ser horas, e nesse ponto o caminho do dump deixa de ser viável para um serviço ativo, e a replicação passa a ser a resposta, não uma otimização.
O caminho da replicação inverte o custo: você faz o trabalho com antecedência, e o corte se torna trivial. Configure uma réplica no host novo com dias de antecedência — replicação baseada em GTID para MySQL e MariaDB, pg_basebackup e um standby por streaming para PostgreSQL, ou replicação lógica quando você também está cruzando uma versão major. Deixe-a alcançar o primário e se manter sincronizada. O corte então é: parar as escritas no primário, esperar a réplica reportar lag zero, promovê-la, apontar a aplicação para ela. Isso leva segundos, e é a única abordagem que honestamente merece a expressão downtime quase zero.
Não esqueça o estado que não está no banco de dados. Redis, Valkey e Memcached guardam sessões, contadores de rate limit e filas; um índice de busca em Elasticsearch, OpenSearch ou Meilisearch guarda uma cópia derivada dos seus dados. Para cada um deles, decida explicitamente se vai migrá-lo ou reconstruí-lo. Uma instância de Redis guardando sessões vale a pena mover com um BGSAVE e uma cópia do arquivo resultante, a menos que você não se importe em desconectar todo mundo. Um índice de busca quase sempre é mais rápido de reindexar no host novo do que de transferir — mas reindexar leva tempo, então comece durante o ensaio, e não durante o congelamento.
| Estratégia | Downtime no corte | Trabalho antes da janela | Quando é a escolha certa |
|---|---|---|---|
| Cópia de arquivo de um diretório de dados ativo | Nenhum, e os dados podem estar corrompidos | Nenhum | Nunca. Incluído aqui porque é a primeira coisa que as pessoas tentam. |
| Dump e restauração consistentes | Dump mais transferência mais restauração mais reindex | Meça uma vez durante o ensaio | Datasets pequenos o bastante para que o total medido caiba na sua tolerância. |
| Dump, restauração, depois replay do delta | Minutos | Retenção de binlog ou WAL configurada com antecedência | Datasets de porte médio, nos quais uma réplica completa é mais trabalho do que você quer. |
| Réplica promovida no corte | Segundos | Replicação rodando e sem lag por dias | Qualquer coisa grande, e qualquer caso em que um congelamento longo seja inaceitável. |
| Parar o banco de dados, copiar arquivos a frio | Duração da cópia | Nenhum | Serviços internos pequenos, nos quais uma hora fora do ar genuinamente não custa nada. |
Certificados TLS, chaves de host SSH e as identidades que você não pode simplesmente reemitir
A emissão de certificados tem um problema do tipo ovo e galinha bem na hora errada. O desafio HTTP-01 prova o controle de um nome buscando um arquivo através desse nome, o que exige que o nome já resolva para a máquina que está sendo validada — e, antes do corte, ele não resolve. Existem três saídas, e você deve escolher uma delas de forma deliberada. Copiar o diretório de certificados para o outro lado, o que funciona imediatamente e é inteiramente legítimo porque a chave é sua. Usar o desafio DNS-01 em vez disso, que valida publicando um registro TXT e, por isso, funciona em uma máquina para a qual nada ainda aponta, e que de qualquer forma é a única opção para um certificado wildcard. Ou aceitar uma janela curta depois da mudança de DNS, durante a qual o host novo solicita o próprio certificado, o que é aceitável para um site pessoal e não é aceitável para nada que tenha usuários.
Se você for copiar, copie tudo. Os certificados e as chaves privadas são a parte óbvia; a chave de conta ACME é a parte que fica para trás, e sem ela o cliente no host novo registra uma conta totalmente nova na primeira renovação. Tudo parece funcionar, e você perdeu silenciosamente o histórico da conta e qualquer estado vinculado a ela. Preserve também a posse e as permissões — chaves privadas em 600, o diretório archive em 700 — porque uma cópia que amplia as permissões de uma chave é um resultado pior do que a migração com a qual você estava preocupado.
Não planeje reemitir repetidamente só para ver o que acontece. Os limites de taxa do Let's Encrypt restringem certificados duplicados para o mesmo conjunto de hostnames por semana, e dois ensaios que falharam mais uma emissão real é uma forma surpreendentemente fácil de bater no teto justo no único dia em que você não pode se dar ao luxo de esperar. Aponte os ensaios para o ambiente de staging; guarde o endpoint de produção para a coisa de verdade.
As chaves de host SSH são a outra identidade em jogo, e aqui a resposta certa realmente depende do motivo pelo qual você está se mudando. Copiar /etc/ssh/ssh_host_* torna a migração invisível: o known_hosts de cada cliente continua batendo, e nenhuma automação para com um aviso de fingerprint. Isso é conveniente, e é a escolha certa para uma mudança de rotina entre provedores em quem você confia. É a escolha errada se o motivo de você estar saindo é que você não confia mais no host antigo ou no provedor antigo — qualquer um com acesso a esse disco teve a sua chave privada de host, e levá-la para o servidor novo leva o problema junto. Nesse caso, gere chaves novas, publique o fingerprint novo por um canal que não seja o servidor, e faça os clientes rodarem ssh-keygen -R contra a entrada antiga. Veja o manual do sshd do OpenSSH para saber onde as chaves vivem e como são selecionadas.
Uma regra é absoluta em qualquer um dos casos: nunca rode as duas máquinas simultaneamente com a mesma chave de host e o mesmo hostname resolvendo para as duas. Essa é uma configuração na qual um cliente não consegue saber qual servidor alcançou, que é exatamente a propriedade que as chaves de host existem para evitar. Durante a janela de sobreposição, o host antigo mantém a sua identidade e o novo tem a dele, ou o nome do host antigo é aposentado no instante em que o novo adota a sua chave.
O corte: os dez minutos que exigem uma ordem escrita
Tudo até aqui era reversível e sem pressa. O corte não é nenhum dos dois, o que é todo o argumento para escrevê-lo com antecedência: improvisar sob pressão de tempo é o que transforma uma janela de cinco minutos em um incidente de duas horas. O runbook deve ser comandos literais em ordem, com a saída esperada ao lado de cada um, de modo que executá-lo exija ler, não pensar.
A ordem que funciona. Primeiro, pare as escritas no host antigo — uma página de manutenção, uma flag somente leitura, ou simplesmente parar a aplicação enquanto o servidor web ainda responde com uma página de espera. Segundo, rode a passada final de rsync com --delete. Terceiro, termine a etapa do banco de dados: ou o dump-transferência-restauração que você mediu, ou parar as escritas no primário, confirmar lag de replicação zero e promover a réplica. Quarto, inicie os serviços no host novo e dê a eles um momento para se estabilizar — pools de conexão, workers de fila e carregamento de certificado, tudo demora mais em um cold start do que você lembra. Quinto, verifique. Sexto, e só depois que a verificação passar, mude os registros de DNS. Sétimo, deixe o host antigo rodando.
Verificação precisa significar alguma coisa. Buscar a homepage prova que o servidor web está de pé e nada além disso. Use curl --resolve contra o hostname real, em um caminho que toque o banco de dados e devolva algo sobre o qual você possa fazer uma asserção — um endpoint de health check que verifica conectividade com o banco de dados, conectividade com o cache e disco livre vale a pena escrever só por esse motivo. Depois leia o log de acesso do host novo e confirme que a sua requisição está nele. Esse último passo parece pedante, e é o passo que pega o caso em que o seu override de resolvedor não entrou em vigor e você acabou de verificar cuidadosamente o servidor antigo.
Depois de mudar o DNS, observe os dois logs de acesso lado a lado. O tráfego no host novo sobe; o tráfego no host antigo decai à medida que os caches expiram, e essa curva de decaimento é a única medida honesta de quanto tempo a cauda realmente dura. Quando o log do host antigo achatar perto de zero, a migração está terminada. Até lá, a máquina antiga precisa continuar se comportando corretamente para os usuários que ainda a alcançam — por isso ela permanece ligada e somente leitura, em vez de ser desligada num momento de entusiasmo. Se a aplicação não puder ser colocada em modo somente leitura, o host antigo servindo dados desatualizados por algumas horas costuma ser um dano menor do que o host antigo recusando conexão — mas esse é um julgamento a ser feito com antecedência, não na hora.
Mude uma coisa. Não a versão major do sistema operacional e o host ao mesmo tempo. Não o provedor de DNS e os registros ao mesmo tempo. Não a versão do PHP e a máquina ao mesmo tempo. Cada mudança simultânea multiplica as hipóteses que você vai ter que testar quando algo se comportar mal às três da manhã, e o upgrade que você ficou tentado a encaixar junto ainda vai estar lá na semana que vem, em uma máquina para a qual você agora pode voltar.
E-mail, rDNS e a reputação que não viaja com você
Se o servidor envia e-mail, a migração tem uma segunda metade que não tem nada a ver com a migração em si. Um endereço IP carrega uma reputação de envio, essa reputação é construída ao longo de semanas, e ela não vai junto com você. Essa é a forma mais comum de uma migração tecnicamente impecável gerar uma semana de reclamações de usuários, e as mitigações todas precisam começar antes do corte, não depois.
O primeiro registro a quebrar é o SPF. Uma política contendo um mecanismo ip4: que nomeia o endereço antigo começa a falhar no instante em que você envia a partir do novo, e, como as políticas de RFC 7208 são registros DNS, elas têm o próprio TTL para planejar em torno. Adicione o endereço novo ao SPF antes do corte, mantenha os dois listados durante a sobreposição, e remova o antigo quando você descomissionar. O DKIM viaja sem problemas, desde que você copie a chave privada junto com o resto da configuração, já que a metade pública já está publicada. O DMARC não precisa de nenhuma mudança, mas vale a pena confirmar que o endereço de relatórios ainda existe em uma máquina que está prestes a ser destruída.
O DNS reverso não é opcional para um host que envia e-mail. O registro PTR do endereço novo precisa existir e precisa bater com o nome que o servidor anuncia no seu HELO ou EHLO, ou boa parte dos destinatários vai rejeitar só por causa disso. Nos nossos planos, o PTR é editável pelo painel, então é uma caixinha para marcar, não um chamado de suporte — configure-o durante o ensaio, verifique se ele resolve, e confirme que o registro direto bate de volta. Depois, verifique o endereço novo contra as principais blocklists antes de enviar qualquer coisa: endereços reciclados às vezes chegam já listados, e descobrir isso a partir da sua própria mensagem de teste não custa nada, enquanto descobrir isso a partir de um cliente custa caro. O Spamhaus é o que mais importa.
Para o recebimento, mantenha os dois hosts alcançáveis. Adicione o servidor novo como o MX de prioridade 10 e deixe o antigo na prioridade 20 por uma semana, em vez de apagá-lo: remetentes tentam de novo, alguns deles guardaram o seu registro MX em cache, e um servidor de e-mail que aceita discretamente no host antigo é bem melhor do que uma devolução (bounce). Depois, antes de destruir a máquina antiga, esvazie e drene a fila dela — postqueue -f para forçar uma tentativa de entrega e mailq para confirmar que o resultado está vazio. Mensagens paradas em uma fila em um servidor que você está prestes a apagar não estão atrasadas. Elas sumiram. O guia de servidor de e-mail self-hosted cobre o lado da entregabilidade por completo.
Quando o provedor antigo já desligou a máquina
Nem toda migração é planejada. Uma suspensão depois de uma denúncia de abuso, um cartão que venceu, uma conta bloqueada por um motivo que ninguém vai explicar — o fio condutor é que agora você está migrando a partir de uma máquina na qual não consegue fazer login, e a ordem de operações confortável descrita acima deixa de valer. Vale a pena saber com antecedência o que geralmente ainda é possível, porque a janela em que isso é possível costuma ser curta.
Enquanto uma instância está suspensa, mas ainda não apagada, três caminhos costumam continuar disponíveis, em ordem decrescente de utilidade. O painel de controle ainda pode oferecer um snapshot ou download de backup, o que resolve o problema inteiro em uma única etapa. Um modo de resgate ou recuperação ainda pode inicializar uma imagem ativa com o seu disco anexado, permitindo montar o filesystem e copiar o que importa pela rede. E o console de emergência ainda pode conectar mesmo com a rede desabilitada, o que é suficiente para ler arquivos de configuração, recuperar uma chave, ou anotar o que estava instalado — mas não é um caminho para um banco de dados, então não conte com ele para isso. Tente-os nessa ordem, e tente imediatamente: a retenção depois de uma suspensão é uma política, não um direito, e costuma ser medida em dias.
Existe um limite que nenhum chamado de suporte resolve, e vale a pena dizer isso claramente, porque é uma consequência direta do modelo que este site vende. Em um host que nunca coletou uma identidade — incluindo este — não existe forma de provar que você é o titular da conta além de estar de posse das credenciais da conta. Esse é o ponto da hospedagem sem KYC, e é também a conta que ela cobra: ninguém consegue restaurar o seu acesso com base em uma foto de passaporte, porque nenhum passaporte jamais foi vinculado a nada. O guia de hospedagem sem KYC cobre essa troca por completo; a consequência operacional é simplesmente que o seu plano de recuperação não pode depender da boa vontade de mais ninguém.
A sequência de emergência é a sequência planejada com a sobreposição removida. Suba o host novo a partir do seu backup fora da máquina. Verifique-o adequadamente por hostname, porque a tentação de pular a verificação é mais forte exatamente quando você já está fora do ar. Depois mude o DNS imediatamente — a disciplina de TTL continua valendo, exceto que agora você está pagando a cauda do cache como indisponibilidade, em vez de gastá-la como sobreposição, o que é o argumento mais claro possível para manter os TTLs modestos como política permanente, e não como um passo de migração. Espere e-mail degradado por um tempo, e avise as pessoas cedo, em vez de explicar depois.
A lição vai além deste dia ruim específico. Um backup que vive no servidor não é um backup; é uma segunda cópia da coisa que você está prestes a perder. A propriedade que importa é que a cópia esteja em outro lugar, criptografada antes de sair, append-only, para que um host comprometido ou suspenso não consiga apagar o próprio histórico, e — a parte que todo mundo pula — de fato restaurada uma vez, em uma instância descartável, para que você saiba que a restauração funciona. O checklist de hardening cobre como configurar isso em uma máquina nova; se você está lendo esta seção porque já é tarde demais, configure isso na máquina para a qual você está migrando, hoje, antes de qualquer outra coisa.
Rollback: defina o gatilho, e dê a ele uma data de validade
Quase todo mundo diz que tem um plano de rollback, e quase ninguém escreveu o que dispararia esse rollback. Sem um gatilho, a decisão acaba sendo tomada no pior momento possível, por quem estiver mais cansado, e o resultado costuma ser que ninguém faz o rollback, porque sempre parece que o problema atual está a cinco minutos de ser resolvido. Decida com antecedência: uma taxa de erro acima de algum limite por algum período, uma função específica quebrada, ou simplesmente um horário no relógio depois do qual você para de debugar e volta atrás.
A restrição que determina o que rollback sequer significa são as escritas. A partir do momento em que o host novo aceita a sua primeira escrita, voltar atrás significa ou descartar essas escritas, ou reaplicá-las na máquina antiga. Então você está, na verdade, escolhendo entre dois produtos diferentes. Um rollback feito antes da primeira escrita é uma mudança de DNS e leva minutos. Um rollback feito depois de um dia de tráfego de produção é uma migração no sentido oposto, com todos os mesmos passos, e leva tanto tempo quanto este guia descreve. Saiba qual dos dois você tem em cada momento, e note que o segundo tipo fica muito mais fácil se você manteve o banco de dados da máquina antiga capaz de receber uma restauração, em vez de reaproveitar a máquina para outra coisa.
Mantenha o servidor antigo por cerca de uma semana: ligado, somente leitura, com o TTL do DNS ainda baixo, e o monitoramento ainda apontado para ele. No menor plano, esse seguro custa cerca de dois dólares, o que não é um número que deveria pesar na decisão. O que deveria pesar é que uma semana é tempo suficiente para que as tarefas cron semanais, os relatórios mais ou menos mensais e a integração que só dispara às sextas-feiras tenham rodado pelo menos uma vez no host novo — essas são exatamente as falhas que uma janela de dois dias deixa passar por completo.
Depois, descomissione de propósito. Confirme que o log de acesso do host antigo está achatado há um dia. Tire um último backup dele e guarde-o por mais tempo do que você acha que precisa. Revogue tudo que ele detinha: chaves de API, chaves de deploy, usuários de banco de dados, as entradas dele em allowlists de IP de outras empresas, as checagens de monitoramento dele, a entrada dele no SPF, o registro MX dele. Destrua a instância. E, por fim, coloque os TTLs de DNS de volta em algo sensato — um TTL permanente de 300 segundos significa que os resolvedores revalidam vinte vezes por hora pelo resto da vida do site, o que não traz nenhum benefício depois que a migração termina e custa um pouco de latência a cada consulta fria. Uma hora é um valor permanente razoável; um dia é aceitável para registros que você nunca espera que mudem rapidamente.
A migração, na ordem para executá-la
Uma semana antes, inventarie a máquina antiga e escreva o runbook: pacotes, units habilitadas, crontabs, firewall, sockets em escuta, roles do banco de dados, e todo terceiro que colocou o endereço antigo em allowlist. Três dias antes, provisione o novo VPS, restaure os dados nele, e ensaie tudo por hostname com um override de resolvedor — depois reconstrua-o mais uma vez a partir só do inventário, para provar que o inventário é real. Dois dias antes, baixe os TTLs de A, AAAA e MX para 300, para que um TTL antigo inteiro transcorra antes de você precisar deles baixos.
Um dia antes, rode a primeira passada de rsync com -aHAX --numeric-ids enquanto a produção continua rodando, e suba a replicação do banco de dados ou meça a janela do dump no dataset real. Resolva os certificados na mesma passada — copie o diretório de certificados, incluindo a chave de conta ACME, ou mude para o DNS-01 — e configure o registro PTR e a nova entrada de SPF no endereço novo antes que qualquer coisa envie e-mail a partir dele.
Na janela: congele as escritas, rsync final com --delete, termine o banco de dados, inicie os serviços, verifique contra o hostname real em um caminho que toque o banco de dados, confirme que a requisição chegou ao log do host novo, e só então mude o DNS. Deixe o host antigo ligado e somente leitura. Observe os dois logs de acesso até o antigo achatar.
Uma semana depois: confirme que as tarefas semanais rodaram no host novo, tire um último backup do antigo, revogue as chaves dele e as entradas em allowlists em todo lugar, destrua-o, e suba os TTLs de volta. Se você quer que a máquina nova seja melhor do que a que você deixou, e não só mais nova, os primeiros quinze minutos de hardening são o próximo passo natural, e é bem mais fácil fazer isso em um servidor que ainda não acumulou a própria camada não documentada. Se você ainda está escolhendo onde pousar, o guia de jurisdições cobre o que de fato muda entre Islândia, Países Baixos, Romênia e Suíça — e você pode deixar a máquina de destino rodando em cerca de um minuto para começar o ensaio hoje.