← Voltar para o Blog

Atualização automática sem quebrar a produção

Atualizar tudo sozinho é arriscado e não atualizar nunca é pior. O meio-termo é aplicar automaticamente só o que corrige segurança, e reservar o resto para uma janela sua.

Equipe EasyOps Cloud · · 7 min de leitura

Existem dois jeitos ruins de lidar com atualização de servidor. O primeiro é atualizar tudo automaticamente e descobrir numa segunda-feira que a versão nova do PHP quebrou a aplicação. O segundo é não atualizar nunca e acumular vulnerabilidades conhecidas por anos.

O meio-termo é simples de configurar e resolve os dois problemas: aplicar automaticamente apenas correções de segurança, e reservar as demais atualizações para uma janela que você escolhe.

A distinção entre os dois tipos de atualização é a chave, e existe de verdade nas distribuições.

Segurança é diferente de versão nova

Repositórios de distribuições sérias separam correção de segurança das demais atualizações. A diferença é de política, não só de rótulo:

Correção de segurança é o mínimo necessário para fechar uma falha, aplicado sobre a versão que você já usa. Debian e Ubuntu chamam isso de *backport*: a correção é trazida para a versão antiga, sem mudar comportamento.

Atualização comum pode trazer recurso novo, mudar padrão de configuração e alterar comportamento.

É por isso que aplicar segurança automaticamente é razoavelmente seguro, enquanto aplicar tudo não é. O compromisso da distribuição, dentro de uma versão estável, é justamente não quebrar com correção de segurança.

Isso não é garantia absoluta — regressões acontecem —, mas a probabilidade é baixa o suficiente para que o risco de não aplicar seja maior.

Debian e Ubuntu

sudo apt install unattended-upgrades apt-listchanges
sudo dpkg-reconfigure -plow unattended-upgrades

A configuração que importa:

// /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
    "${distro_id}ESMApps:${distro_codename}-apps-security";
};

Unattended-Upgrade::Package-Blacklist {
    "postgresql-16";
    "docker-ce";
};

Unattended-Upgrade::Mail "ops@suaempresa.com.br";
Unattended-Upgrade::MailReport "on-change";

Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Automatic-Reboot "false";

Repare que apenas as origens terminadas em -security estão liberadas. Acrescentar ${distro_codename}-updates transforma isso em "atualizar tudo", que é justamente o que estamos evitando.

A lista de bloqueio é onde vão os pacotes que você prefere atualizar à mão — banco de dados, runtime da aplicação, Docker. São os que, se der errado, dão mais trabalho.

E ative o agendamento:

// /etc/apt/apt.conf.d/20auto-upgrades
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";

Teste sem aplicar nada:

sudo unattended-upgrade --dry-run --debug

Essa saída mostra exatamente o que seria instalado e quais pacotes foram bloqueados. Vale rodar depois de qualquer mudança na configuração.

RHEL, AlmaLinux e Rocky

sudo dnf install dnf-automatic
# /etc/dnf/automatic.conf
[commands]
upgrade_type = security
apply_updates = yes
reboot = never

[emitters]
emit_via = stdio
sudo systemctl enable --now dnf-automatic.timer
systemctl list-timers dnf-automatic.timer

O upgrade_type = security é o equivalente ao filtro de origem do Debian.

O reinício, que é a parte delicada

Correção de kernel e de bibliotecas centrais só passa a valer depois de reiniciar. Isso cria um dilema real: reiniciar automaticamente é arriscado, e nunca reiniciar anula parte do benefício.

A recomendação é não reiniciar sozinho, e sim saber quando é necessário:

# Debian e Ubuntu
ls -la /var/run/reboot-required 2>/dev/null
cat /var/run/reboot-required.pkgs 2>/dev/null

# RHEL e derivados
sudo dnf needs-restarting -r

Um aviso semanal transforma isso em rotina, em vez de deixar a decisão para o esquecimento:

#!/usr/bin/env bash
# /usr/local/bin/check-reboot.sh
if [ -f /var/run/reboot-required ]; then
  echo "Reinício pendente em $(hostname):"
  cat /var/run/reboot-required.pkgs 2>/dev/null
fi

Se você optar por reinício automático, ao menos restrinja a janela:

Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-WithUsers "false";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";

Isso só faz sentido em máquina redundante, onde a saída de uma não interrompe o serviço. Em servidor único, é trocar um risco conhecido por outro.

Vale saber que existe atualização de kernel sem reinício — livepatch no Ubuntu, kpatch no RHEL. Elas cobrem parte das correções e adiam o reinício, sem eliminá-lo.

Serviço que precisa recarregar

Atualizar uma biblioteca não faz os processos que já a carregaram passarem a usar a versão nova. Um openssl corrigido não protege o nginx que continua rodando com a versão antiga em memória.

sudo apt install needrestart
sudo needrestart -b

Ele lista os serviços que precisam reiniciar. Em modo automático, recarrega o que for seguro:

# /etc/needrestart/needrestart.conf
$nrconf{restart} = 'a';
$nrconf{blacklist} = [ qr(^postgresql), qr(^mysql) ];

A lista de bloqueio evita que o banco seja reiniciado no meio do expediente — o que seria uma indisponibilidade não planejada causada justamente pela ferramenta de automação.

Testar antes, quando o risco for maior

Para atualização manual maior — versão de banco, de runtime, ou o full-upgrade periódico —, a sequência que evita surpresa:

# 1. Ver o que mudaria, sem aplicar
sudo apt update
apt list --upgradable
sudo apt full-upgrade -s | grep -E '^(Inst|Remv)'

Preste atenção especial às linhas Remv. Um pacote que seria removido para satisfazer dependência é o sinal de alerta mais confiável de que algo vai quebrar.

# 2. Snapshot antes de aplicar
# 3. Aplicar
sudo apt full-upgrade
# 4. Conferir os serviços
systemctl --failed

O snapshot é o que torna essa operação reversível. Uma atualização que deixa a máquina sem subir é rara, e quando acontece a alternativa é reinstalar.

Para segurar um pacote específico em uma versão conhecida:

sudo apt-mark hold postgresql-16
apt-mark showhold

Pacote retido não é atualizado nem por segurança. Vale revisar a lista periodicamente, senão a retenção temporária vira dívida permanente — que é exatamente como se acumula o problema descrito no artigo sobre fim de suporte.

O que acompanhar depois

Automação silenciosa precisa de verificação, senão você não sabe se ela funciona:

# O que foi aplicado automaticamente
sudo grep -h 'Packages that will be upgraded' \
  /var/log/unattended-upgrades/unattended-upgrades.log | tail

# Quando rodou pela última vez
systemctl status unattended-upgrades.service
systemctl list-timers apt-daily-upgrade.timer

Vale conferir uma vez por mês que o log tem entradas recentes. Automação que parou de rodar é pior que não ter automação, porque gera confiança sem entregar o resultado — e o descobrimento costuma acontecer numa auditoria, meses depois.

O arranjo completo cabe em quinze minutos de configuração: segurança automática, lista de bloqueio para o que é crítico, reinício manual em janela conhecida e uma conferência mensal. É bem menos trabalho que a alternativa de atualizar tudo à mão — e muito menos que a de não atualizar.

O que fazer quando uma atualização quebra

Vai acontecer eventualmente, e a diferença entre um susto e um incidente longo é ter o caminho de volta claro antes de precisar dele.

O primeiro passo é identificar o que mudou. O histórico do gerenciador de pacotes responde com precisão:

# Debian e Ubuntu
grep -E 'Upgrade|Install' /var/log/apt/history.log | tail -20
zgrep -h 'Upgrade' /var/log/apt/history.log.*.gz | tail

# RHEL e derivados
sudo dnf history list | head
sudo dnf history info 42

Com o pacote identificado, dá para voltar apenas ele, o que é bem menos invasivo que restaurar a máquina inteira:

# Ver as versões disponíveis no repositório
apt-cache policy nome-do-pacote

# Instalar uma versão específica
sudo apt install nome-do-pacote=1.2.3-1ubuntu2

# E segurar, para não voltar a subir na próxima rodada
sudo apt-mark hold nome-do-pacote

Em RHEL e derivados, a reversão é ainda mais direta, porque o histórico é transacional:

sudo dnf history undo 42

Se a máquina não subir, o snapshot é a saída — e é por isso que ele vem antes de atualização manual grande. Vale lembrar que o console no browser continua acessível com a rede fora, o que permite diagnosticar uma máquina que não completa o boot sem depender de SSH.

Depois de resolver, registre o que aconteceu: qual pacote, qual versão, qual sintoma. Essa anotação é o que evita repetir o mesmo problema no próximo servidor — e o que justifica a entrada na lista de bloqueio para quem vier depois.

O arranjo que se sustenta

  • Segurança automática, só das origens -security.
  • Lista de bloqueio com banco, runtime e container.
  • needrestart para recarregar serviço após correção de biblioteca, exceto os bancos.
  • Reinício manual, em janela conhecida, com o aviso semanal do que está pendente.
  • Snapshot antes de qualquer atualização maior feita à mão.
  • Conferência mensal de que a automação continua rodando.

O objetivo não é eliminar o trabalho de atualizar, é reduzi-lo ao que exige julgamento. Correção de segurança não exige julgamento — ela precisa ser aplicada. O que exige decisão é a versão maior do banco, e essa continua sendo sua.

Uma última consideração sobre containers, que ficam de fora de tudo isso. O unattended-upgrades atualiza o sistema hospedeiro e não toca no que roda dentro das imagens. Uma máquina impecavelmente atualizada pode estar servindo uma aplicação sobre uma base de dois anos atrás, com todas as falhas conhecidas do período.

Para esse caso, o equivalente é reconstruir a imagem periodicamente a partir da base atualizada e reimplantar — mesmo quando o código da aplicação não mudou. Vale agendar como rotina mensal, junto da conferência acima, porque é o ponto cego mais comum em servidor que parece bem mantido.

Suba um servidor em minutos

Preço em real, suporte em português e dados no Brasil.

Criar conta