Como corrigir o relógio atrasado ou adiantado do VPS
Veja por que o relógio do VPS deriva, interprete chronyc e timedatectl e corrija o NTP que causa o erro nos códigos 2FA.
Por que o relógio do seu VPS deriva
O relógio de um VPS deriva porque nada o corrige. O kernel conta o tempo a partir de um contador de hardware que funciona ligeiramente depressa ou devagar. Sem um cliente de sincronização de tempo em execução, esse pequeno erro aumenta a cada hora. Numa máquina virtual, existe uma segunda causa: o seu guest partilha uma CPU física com outros guests. Por isso, os períodos em que não é agendado são períodos em que não consegue contar o tempo.
Num guest KVM atual, o contador raramente é o verdadeiro problema. A fonte kvm-clock paravirtualizada lê um valor mantido pelo host. Assim, um guest saudável acompanha de perto o relógio do host. Relógios visivelmente incorretos costumam estar errados por uma razão mais simples. Não há nenhum daemon de sincronização em execução, há dois em execução e estão a interferir entre si, ou a porta UDP de saída 123 nunca sai da rede do seu provedor. Um guest obtém a disciplina do relógio a partir do host ou do NTP (network time protocol), não do seu próprio oscilador.
O que um relógio incorreto realmente avaria
- Os códigos TOTP (palavra-passe de utilização única baseada no tempo) deixam de coincidir. Assim, perde o acesso a um servidor cuja palavra-passe e chave estão corretas.
- Um certificado emitido há um minuto é rejeitado, e
curlapresentaSSL certificate problem: certificate is not yet valid. apt updaterecusa um repositório comE: Release file for ... is not valid yet (invalid for another 1d 2h 3min 4s).- As tarefas agendadas são executadas no momento errado. Um salto do relógio pode fazer uma tarefa ser executada duas vezes e outra ser ignorada.
- Não é possível alinhar os logs de dois servidores. A cronologia de um incidente tem de ser reconstruída por tentativa.
A tolerância é menor do que a maioria das pessoas espera. Os valores abaixo são predefinições documentadas, não medições de um teste.
The data behind this chart
[
{
"label": "TLS certificate boundary",
"tolerance_seconds": 0,
"documented_in": "RFC 5280"
},
{
"label": "chrony steps instead of slewing",
"tolerance_seconds": 1,
"documented_in": "Debian and Ubuntu chrony.conf"
},
{
"label": "TOTP code, one time step",
"tolerance_seconds": 30,
"documented_in": "RFC 6238"
},
{
"label": "Kerberos clock skew",
"tolerance_seconds": 300,
"documented_in": "MIT krb5 default"
}
]Um código TOTP é calculado a partir de um contador que avança a cada 30 segundos, e a maioria dos validadores aceita um intervalo de um passo para cada lado. Trinta segundos de erro em cada direção esgotam toda a margem. O Kerberos é muito mais tolerante, com uma margem de desvio predefinida de 300 segundos. Um certificado não tem qualquer tolerância: é validado contra instantes fixos, com um período de tolerância de 0 segundos. Por isso, um relógio adiantado um segundo rejeita um certificado perfeitamente válido.
Os três relógios e qual deles importa
O relógio do sistema é o que importa. É o CLOCK_REALTIME do kernel: a contagem de segundos desde 1 January 1970 UTC, mantida na memória e lida por tudo o que regista uma hora. As linhas de log, as verificações de certificados, os códigos TOTP e as horas de modificação dos ficheiros vêm dele. Quando alguém diz que a hora do servidor está errada, é deste relógio que está a falar.
O relógio de hardware, também chamado RTC (real time clock), é um contador separado que continua a funcionar enquanto a máquina está desligada. Numa máquina física, é um chip alimentado por bateria. Dentro de um guest, é emulado pelo hypervisor, pelo que é sobretudo um elemento do host. O Linux lê-o uma vez durante o arranque para obter um valor inicial e, depois, mantém a sua própria contagem. timedatectl apresenta-o na linha RTC time. Não faça diagnóstico a partir dessa linha numa VPS, porque ela mostra a noção de hora do host, não o estado de sincronização do relógio do sistema. Num container, normalmente não existe qualquer /dev/rtc, pelo que hwclock --show falha com hwclock: Cannot access the Hardware Clock via any known method.
A fonte de relógio é o mecanismo que o kernel usa para contar entre essas leituras. Consulte qual foi escolhida pelo kernel:
cat /sys/devices/system/clocksource/clocksource0/current_clocksource
cat /sys/devices/system/clocksource/clocksource0/available_clocksourceNo KVM, normalmente verá kvm-clock. Esta fonte lê um valor mantido pelo host, razão pela qual um guest KVM sem qualquer cliente NTP continua aproximadamente certo durante algum tempo. tsc é o contador do próprio CPU. Os guests Xen comunicam xen e os guests Hyper-V comunicam uma fonte hyperv. Não altere esta definição sem uma razão medida, porque o kernel já escolhe a melhor fonte em que confia nesse hardware.
Alguns hosts também disponibilizam um dispositivo PTP (precision time protocol) ao guest, permitindo que o chrony leia diretamente o relógio do host em vez de o fazer através da rede. Vale a pena verificar, mas esta opção muitas vezes não está disponível numa VPS partilhada:
sudo modprobe ptp_kvm
ls /dev/ptp*
cat /sys/class/ptp/ptp0/clock_nameSe modprobe falhar ou não aparecer qualquer dispositivo, o seu host não o disponibiliza e o NTP pela rede é a solução. Se clock_name indicar o relógio virtual KVM, o chrony pode utilizá-lo com uma linha refclock PHC /dev/ptp0 poll 2 na sua configuração.
Leia o estado da hora na própria máquina
Comece com um comando. Ele responde à pergunta "há alguma coisa a manter este relógio certo" num único ecrã.
timedatectlLeia estas linhas em vez de confiar num número de que se lembra:
Local timeeUniversal timesão o mesmo instante apresentado no seu fuso horário e em UTC. Se forem idênticos, a máquina já está em UTC.RTC timeé o relógio de hardware descrito acima. Numa VPS, ignore-o.Time zoneé o que o sistema usa para formatar a hora local.System clock synchronizedé a flag do próprio kernel. Um daemon de hora define-a quando confia nas suas fontes, por issonosignifica que nenhum processo sincronizou este relógio desde o boot.NTP serviceapresenta informações específicas sobre o systemd-timesyncd.n/aé normal numa máquina que executa chrony, porque o timesyncd não está instalado nela.System clock synchronized: yesjuntamente comNTP service: n/asignifica que o chrony está a tratar da sincronização e que o kernel concorda com ele.
Em seguida, verifique qual é o desvio. Não o avalie visualmente comparando-o com o telemóvel. Se o chrony estiver em execução:
chronyc tracking
chronyc sources -vchronyc tracking apresenta os números que respondem à pergunta. System time é o desvio atual em relação à hora NTP, seguido da palavra fast ou slow. Last offset é o tamanho da correção mais recente. Frequency é o erro de frequência que o chrony mediu no seu relógio e já está a compensar. Leap status deve apresentar Normal. Se apresentar Not synchronised e Reference ID for 00000000 (), o chrony ainda não escolheu uma fonte.
chronyc sources -v apresenta uma legenda acima da lista, para não ter de memorizar os símbolos. Duas colunas contêm a maior parte da informação. O carácter de estado no início de cada linha indica como o chrony avalia essa fonte. * identifica a fonte atualmente utilizada, e ? em todas as linhas significa que nenhuma fonte está a responder. Reach é o histórico das respostas das últimas oito sondagens, apresentado em octal: 377 significa que as oito tiveram resposta; 0 significa que nenhuma teve resposta.
Se o systemd-timesyncd for o responsável:
timedatectl timesync-status
timedatectl show-timesync --alltimesync-status apresenta o servidor com o qual está a comunicar, o intervalo entre sondagens e um valor Offset. Se o comando devolver um erro sobre o serviço em vez de apresentar o estado, o timesyncd não é o daemon responsável nesta máquina. Essa informação responde, por si só, à sua pergunta.
Para uma verificação aproximada em relação ao exterior, sem ferramentas adicionais, compare o seu relógio com um cabeçalho HTTP público Date. Esse cabeçalho é servido em GMT com resolução de um segundo:
date -u
curl -sI https://www.cloudflare.com | grep -i '^date:'Uma diferença de um ou dois segundos é normal e não significa nada. Uma diferença de um minuto indica um problema na sua máquina.
chrony ou systemd-timesyncd numa VPS
Ubuntu e Debian incluem o systemd-timesyncd por predefinição. É um cliente SNTP (simple network time protocol): consulta um servidor de cada vez e ajusta gradualmente o relógio na direção desse servidor. Numa máquina que permanece online e começa com uma hora aproximadamente correta, isso é suficiente e quase não consome recursos.
O chrony é uma implementação completa de NTP e a melhor opção predefinida numa máquina virtual, por motivos que pode ver na própria saída do programa. Consulta várias fontes ao mesmo tempo e descarta as que divergem. Mede o erro de frequência do relógio e grava-o num ficheiro de drift, por isso corrige a tendência do relógio em vez de tentar acompanhar cada amostra. Também recupera rapidamente das duas situações que uma VM enfrenta e uma máquina física não: pode ser pausada pelo host e pode ser movida para outro host enquanto está em execução. Quando é disponibilizado um dispositivo PTP do host, é o chrony que o lê.
sudo apt update && sudo apt install -y chrony
systemctl status chrony --no-pager
chronyc sources -v
chronyc trackingLeia a saída do apt enquanto o comando é executado. No Debian e no Ubuntu, os pacotes chrony e systemd-timesyncd fornecem ambos time-daemon, por isso o apt remove o timesyncd ao instalar o chrony. Isto é correto e esperado. Nunca execute os dois, porque dois daemons a definir o mesmo relógio entram em conflito e não é possível confiar no offset indicado por nenhum deles enquanto ambos estiverem ativos. No Rocky e no AlmaLinux, instale com sudo dnf install -y chrony, onde a unidade se chama chronyd em vez de chrony.
O ficheiro de configuração é /etc/chrony/chrony.conf no Debian e no Ubuntu, e /etc/chrony.conf no Rocky e no Alma. A configuração predefinida da distribuição já é adequada para uma VPS, por isso altere-a apenas por uma razão concreta. Vale a pena compreender duas diretivas:
- As linhas
pooleserverdefinem as fontes de hora. Adicionariburstfaz com que o chrony envie uma sequência rápida de pedidos no arranque, para que a primeira sincronização ocorra em segundos em vez de minutos. makestepdetermina quando o chrony salta o relógio em vez de o ajustar gradualmente. Verifique o valor configurado comgrep -n makestep /etc/chrony/chrony.conf. O valor predefinido no Debian e no Ubuntu,makestep 1 3, significa o seguinte: durante as três primeiras atualizações depois do arranque do chronyd, ajustar o relógio de uma vez se o desvio for superior a um segundo; depois disso, corrigir apenas de forma gradual.
Se quiser autenticar o tráfego de hora para detetar alterações no caminho da rede, o chrony 4 e versões posteriores suportam NTS (network time security). Confirme primeiro a versão com chronyd -v e tenha em conta que o NTS também requer a porta TCP 4460 de saída aberta, além da UDP 123:
server time.cloudflare.com iburst ntsReinicie o serviço e verifique-o antes de confiar nele. Uma configuração que não possa ser analisada deixa-o sem qualquer daemon de hora, e o relógio não o informará desse problema.
sudo systemctl restart chrony
chronyc sources -v
chronyc trackingPor que um relógio atrasado vários minutos continua atrasado
Um daemon de tempo tem duas formas de corrigir um desvio. O ajuste gradual acelera ou abranda o relógio até eliminar o erro. Assim, o tempo continua a avançar e nenhum timestamp é repetido ou ignorado. O ajuste imediato salta diretamente para o valor correto. É rápido, mas pode fazer o relógio recuar. Isso é perigoso para qualquer sistema que meça o tempo decorrido a partir do relógio de parede. Por esse motivo, ambos os daemons preferem o ajuste gradual.
Essa preferência explica por que um relógio muito atrasado pode continuar incorreto durante bastante tempo. O chrony só faz um ajuste imediato dentro da janela que makestep permite. Por predefinição, essa janela corresponde às primeiras atualizações depois de o daemon arrancar. Se um chronyd estiver em execução há uma semana e encontrar um erro de quarenta segundos, fará um ajuste gradual. Corrigir quarenta segundos dessa forma demora muito mais do que é conveniente esperar. Force a correção uma vez, de forma deliberada, num momento de pouca atividade:
sudo chronyc makestep
chronyc trackingchronyc tracking deve agora apresentar um desvio System time próximo de zero. Last offset deve mostrar a dimensão da correção efetuada. Pense antes de executar isto num servidor de base de dados ocupado. Um relógio que recua pode confundir software que pressupõe que o tempo só avança. Reiniciar o daemon é uma versão mais suave da mesma correção, porque a janela makestep volta a abrir no arranque.
Os contêineres partilham o relógio do host
Um contêiner não tem um relógio próprio, portanto não há nada para sincronizar dentro dele. Os namespaces de tempo do Linux virtualizam apenas os relógios monotónico e de tempo de arranque. CLOCK_REALTIME não é virtualizado, o que significa que um contêiner lê o mesmo relógio do sistema que o host onde é executado. Corrija o relógio no host e todos os contêineres desse host serão corrigidos no mesmo momento.
Isso tem algumas consequências. Não instale chrony nem ntpd numa imagem, porque, na melhor das hipóteses, isso não faz nada. Definir a data dentro de um contêiner sem privilégios falha com date: cannot set date: Operation not permitted, porque o kernel exige CAP_SYS_TIME para essa chamada. Conceder CAP_SYS_TIME não dá ao contêiner um relógio privado. Dá-lhe a capacidade de alterar o relógio do host e, consequentemente, o relógio de todos os outros contêineres.
Um fuso horário diferente dentro de um contêiner não é um problema do relógio. Uma imagem que tenha o seu próprio /etc/localtime apresenta o mesmo instante formatado para outro fuso, portanto date parece incorreto embora o relógio esteja certo. Defina TZ=UTC no ambiente do contêiner para eliminar a confusão. O runtime escolhido não altera nada neste caso, e a comparação entre Podman e Docker rootless explica o que ele altera.
Fusos horários: UTC no servidor, hora local para as pessoas
Configure a máquina para UTC e mantenha-a assim.
timedatectl list-timezones | grep -i utc
sudo timedatectl set-timezone UTC
timedatectlO UTC não tem horário de verão, e esse é o argumento principal. Uma tarefa diária às 02:30 num fuso horário que observa o horário de verão é executada duas vezes no dia em que os relógios atrasam e não é executada no dia em que avançam. man 8 cron documenta o tratamento especial para mudanças inferiores a três horas: as tarefas ignoradas por um avanço são executadas pouco depois da mudança, e as tarefas apanhadas dentro de uma hora repetida por um recuo não são executadas uma segunda vez. Esse comportamento é razoável, mas não deveria ser necessário analisá-lo às 03:00. Com UTC, a tarefa é executada uma vez por dia, todos os dias do ano. Se uma tarefa sua não for executada de todo, em vez de ser executada a uma hora inesperada, as razões pelas quais uma tarefa cron nunca é executada silenciosamente são a explicação mais provável.
O mesmo argumento aplica-se à leitura de logs. journalctl formata os timestamps no fuso horário do sistema, e journalctl --utc força o UTC. Dois servidores em dois fusos horários transformam cada incidente num exercício de conversão, e as conversões feitas sob pressão são uma causa comum de leituras incorretas de uma linha temporal. Mantenha os sistemas em UTC, armazene os timestamps em UTC e faça a conversão uma vez, no ponto em que uma pessoa os lê. Quem precisar da hora local para um comando pode solicitá-la sem alterar a máquina:
TZ=Europe/Berlin dateMais uma linha do output de timedatectl pertence a esta secção. RTC in local TZ deve apresentar no. Defini-lo como yes é uma solução alternativa para arrancar Windows em dual boot num portátil; num servidor, apenas adiciona um desfasamento que poderá causar problemas mais tarde. Quando está definido, timedatectl apresenta um aviso de que o sistema está configurado para ler a hora do RTC no fuso horário local.
Diagnóstico por sintoma
O código de autenticação de dois fatores é recusado num servidor. Verifique o relógio antes de verificar qualquer outra coisa. O código vem de um contador que avança a cada 30 segundos, por isso um servidor atrasado 90 segundos calcula um código de um intervalo que o telemóvel já ultrapassou. timedatectl mostra System clock synchronized: no, ou chronyc tracking comunica um desvio System time elevado. Esta é uma falha diferente de uma chave rejeitada diretamente, que apresenta a sua própria mensagem e é abordada no guia sobre falhas de autenticação publickey.
apt update indica que um ficheiro Release ainda não é válido. A mensagem completa indica o repositório e durante quanto tempo continuará inválido, por exemplo is not valid yet (invalid for another 1d 2h 3min 4s). O relógio está atrasado em relação à data no ficheiro Release do repositório, e essa duração mede diretamente o atraso. Corrija o relógio. Não desative a verificação de data do apt para ultrapassar o erro, porque essa verificação impede que alguém lhe forneça um índice de pacotes desatualizado.
Todas as linhas das fontes mostram o estado inacessível e Reach é 0. Ninguém está a responder, por isso verifique o tráfego de saída em vez da configuração. O NTP usa a porta UDP 123 para tráfego de saída, e algumas redes filtram-no ou redirecionam-no. sudo chronyc ntpdata apresenta contadores por fonte, incluindo Total TX e Total RX. Um contador TX que aumenta enquanto RX permanece em zero significa que os seus pacotes saem e nada regressa, o que aponta para uma firewall entre si e a fonte.
O relógio estava correto e depois avançou bruscamente. Eventos no host podem causar isto. Um snapshot restaurado, um guest pausado ou uma migração em tempo real para outro host podem deixar a noção de tempo do guest atrasada em relação ao tempo real. O chrony deteta a diferença na sondagem seguinte e corrige-a; o systemd-timesyncd pode primeiro aguardar um intervalo de sondagem longo. Confirme que o daemon inicia no boot com systemctl is-enabled chrony, porque um daemon iniciado manualmente deixa de estar em execução após o reboot seguinte.
O desvio é pequeno, mas nunca estabiliza. Verifique o CPU steal. Um guest que não é agendado quando a sua interrupção de temporizador deveria ocorrer recebe as amostras com atraso, por isso o desvio varia em vez de convergir. top mostra este valor como a métrica st na linha do CPU. Ler o tempo de CPU steal num host partilhado explica o significado desse número e o que pode fazer para o corrigir.
Um certificado que acabou de emitir é rejeitado como ainda não válido. curl apresenta SSL certificate problem: certificate is not yet valid, e os browsers mostram algo semelhante. O certificado está correto; o relógio que o valida está atrasado. Qualquer uma das máquinas pode ser responsável, por isso verifique o cliente e o servidor. Se o servidor que emitiu o certificado for o que tem o relógio incorreto, o guia de certificados do certbot e nginx aborda a renovação na mesma configuração.
Adicione-o às verificações que já executa
A sincronização da hora é uma configuração de arranque que pode falhar silenciosamente meses mais tarde. É exatamente o tipo de problema que uma rotina deteta e a memória não. timedatectl e chronyc tracking demoram dois segundos a ler em conjunto. Execute-os como parte dos primeiros dez minutos num novo VPS e novamente quando seguir a lista de verificação regular de manutenção de servidores Linux. Se preferir que a própria verificação seja executada e emita um alerta quando o desvio aumentar, escrever um serviço e um temporizador systemd apresenta o padrão para uma unidade pequena que gera relatórios segundo um calendário. Uma verificação deste tipo é um script curto, não um daemon. Por isso, deve usar Type=oneshot em vez do valor predefinido. A explicação dos tipos de serviço do systemd esclarece por que motivo a opção errada deixa uma unidade comunicar sucesso sem o ter obtido.
FAQ
Como verifico se o relógio do meu VPS está sincronizado?
Execute timedatectl e leia a linha System clock synchronized. Essa é a própria flag do kernel, definida pelo daemon que disciplina o relógio. Por isso, yes juntamente com NTP service: n/a é normal e indica um estado saudável numa máquina com chrony. Para saber o tamanho do erro, execute chronyc tracking e leia System time. Se o systemd-timesyncd estiver a gerir a sincronização, execute timedatectl timesync-status e leia Offset. Para comparar com algo externo à máquina, compare date -u com o cabeçalho Date devolvido por qualquer site HTTPS.
Devo usar chrony ou systemd-timesyncd num VPS?
Use chrony em qualquer servidor importante. O systemd-timesyncd é um cliente SNTP que segue um único servidor. É suficiente numa máquina que permanece online e começa com a hora quase correta. O chrony consulta várias fontes, rejeita as que divergem, aprende o erro de ritmo do relógio e recupera rapidamente depois de uma pausa do host ou de uma migração em tempo real. Instalar chrony no Debian ou no Ubuntu remove automaticamente o systemd-timesyncd, porque ambos os pacotes fornecem time-daemon. Nunca execute dois daemons de hora ao mesmo tempo.
Porque é que os meus códigos TOTP falham num servidor, mas funcionam em todos os outros?
Porque um código TOTP é uma função da hora atual. O código é obtido a partir de um contador que avança a cada 30 segundos. Por isso, o servidor e o telefone têm de concordar sobre o intervalo atual. A maioria dos verificadores aceita um intervalo de cada lado. Isso proporciona uma margem de aproximadamente meio minuto em cada direção. Verifique timedatectl nesse servidor. Se System clock synchronized indicar no, corrija a sincronização. Os códigos voltarão a corresponder sem alterar o segredo partilhado.
Posso definir a hora dentro de um contentor Docker?
Não, e não precisa de o fazer. Um contentor partilha o CLOCK_REALTIME do host, porque os namespaces de tempo do Linux virtualizam apenas os relógios monotónico e de tempo de arranque. Um contentor sem privilégios recebe date: cannot set date: Operation not permitted. Adicionar CAP_SYS_TIME permite-lhe alterar o relógio do host, em vez de lhe fornecer um relógio próprio. Sincronize o host. Uma hora local diferente dentro de um contentor é uma definição de fuso horário. Por isso, defina TZ no ambiente do contentor.
Um servidor deve usar UTC ou a hora local?
UTC, aplicando a hora local no momento em que uma pessoa lê a saída. A UTC nunca muda devido à hora de verão. Assim, uma tarefa diária é executada uma vez por dia durante todo o ano, e os timestamps de servidores diferentes ficam alinhados sem conversão. Defina-a com sudo timedatectl set-timezone UTC. Quem precisar de consultar a hora local pode prefixar um único comando, por exemplo TZ=America/New_York date. Isso não altera o relógio do sistema.