SSD Nodes Learn 🎉 VPS da $5.50/mese
Guide Matt ConnorDi Matt Connor

Come correggere l’orologio che perde precisione sul VPS

Scopri quale orologio conta davvero, interpreta chronyc e timedatectl e risolvi la sincronizzazione NTP che causa errori di accesso 2FA.

Perché l’orologio del tuo VPS accumula deriva

L’orologio di un VPS accumula deriva perché nulla lo corregge. Il kernel calcola il tempo a partire da un contatore hardware che può avanzare leggermente più velocemente o più lentamente. Se non è in esecuzione alcun client di sincronizzazione dell’ora, questo piccolo errore aumenta ogni ora. In una macchina virtuale esiste una seconda causa: il guest condivide una CPU fisica con altri guest, quindi durante gli intervalli in cui non viene schedulato non può conteggiare il tempo.

Su un guest KVM attuale, il contatore non è quasi mai il vero problema. La sorgente paravirtuale kvm-clock legge un valore mantenuto dall’host, quindi un guest funzionante segue con precisione l’host. Gli orologi che mostrano un’ora chiaramente errata sono solitamente imprecisi per un motivo più semplice. Non è in esecuzione alcun demone di sincronizzazione, oppure ne sono in esecuzione due che interferiscono tra loro, oppure le connessioni UDP in uscita sulla porta 123 non lasciano mai la rete del provider. Un guest sincronizza il proprio orologio con l’host o tramite NTP (network time protocol), non tramite il proprio oscillatore.

Che cosa compromette realmente un orologio non sincronizzato

  • I codici TOTP (password monouso basate sul tempo) per l'autenticazione a due fattori non corrispondono più; di conseguenza, l'accesso al server viene negato anche quando password e chiave sono corrette.
  • Un certificato emesso un minuto prima viene rifiutato e curl stampa SSL certificate problem: certificate is not yet valid.
  • apt update rifiuta un repository con E: Release file for ... is not valid yet (invalid for another 1d 2h 3min 4s).
  • Le attività pianificate vengono eseguite nel momento sbagliato. Un salto dell'orologio può far eseguire due volte un'attività e saltarne un'altra.
  • I log di due server non possono essere allineati. La sequenza temporale di un incidente deve quindi essere ricostruita per tentativi.

La tolleranza è inferiore a quanto molti si aspettano. I valori riportati di seguito sono impostazioni predefinite documentate, non misurazioni effettuate durante un test.

ChartHow far the clock can be off before something breaks (documented defaults)
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"
  }
]

Un codice TOTP viene calcolato a partire da un contatore che avanza ogni 30 secondi. La maggior parte dei verificatori accetta anche l'intervallo immediatamente precedente o successivo. Un errore di mezzo minuto in entrambe le direzioni esaurisce l'intero margine disponibile. Kerberos è molto più permissivo, con una tolleranza predefinita di 300 secondi. I certificati, invece, non prevedono alcuna tolleranza: vengono verificati rispetto a istanti precisi, con un periodo di tolleranza di 0 secondi. Di conseguenza, un orologio indietro di un secondo rifiuta un certificato perfettamente valido.

I tre orologi e quale conta davvero

L'orologio di sistema è quello che conta. È il CLOCK_REALTIME del kernel: il conteggio dei secondi dal 1 gennaio 1970 UTC, mantenuto in memoria e letto da tutto ciò che assegna un timestamp. Le righe dei log, i controlli dei certificati, i codici TOTP e gli orari di modifica dei file derivano tutti da questo valore. Quando si dice che l'ora del server è errata, si intende questo orologio.

L'orologio hardware, chiamato anche RTC (real time clock), è un contatore separato che continua a funzionare mentre la macchina è spenta. Su una macchina fisica è un chip alimentato da una batteria. All'interno di un guest viene emulato dall'hypervisor, quindi dipende in gran parte dall'host. Linux lo legge una volta all'avvio per ottenere un valore iniziale, quindi mantiene il proprio conteggio. timedatectl lo stampa sulla riga RTC time. Non usare quella riga per il troubleshooting su un VPS, perché indica l'ora dell'host e non lo stato di sincronizzazione dell'orologio di sistema. In un container di solito non esiste alcun /dev/rtc, quindi hwclock --show fallisce con hwclock: Cannot access the Hardware Clock via any known method.

La sorgente dell'orologio è il riferimento usato dal kernel per contare tra una lettura e l'altra. Chiedi al kernel quale sorgente ha selezionato:

cat /sys/devices/system/clocksource/clocksource0/current_clocksource
cat /sys/devices/system/clocksource/clocksource0/available_clocksource

Su KVM vedrai di solito kvm-clock. Legge un valore mantenuto dall'host; per questo un guest KVM senza alcun client NTP continua a mantenere un'ora approssimativamente corretta per un certo periodo. tsc è il contatore interno della CPU. I guest Xen riportano xen, mentre i guest Hyper-V riportano una sorgente hyperv. Lascia questa impostazione invariata, salvo che tu abbia un motivo misurato per modificarla, perché il kernel seleziona già la sorgente migliore di cui si fida su quell'hardware.

Alcuni host forniscono al guest anche un dispositivo PTP (precision time protocol), che consente a chrony di leggere direttamente l'orologio dell'host invece di usare la rete. Vale la pena verificarne la disponibilità, anche se spesso non è disponibile su un VPS condiviso:

sudo modprobe ptp_kvm
ls /dev/ptp*
cat /sys/class/ptp/ptp0/clock_name

Se modprobe fallisce o non viene visualizzato alcun dispositivo, l'host non lo fornisce e devi usare NTP tramite la rete. Se clock_name indica il clock virtuale KVM, chrony può usarlo con una riga refclock PHC /dev/ptp0 poll 2 nella propria configurazione.

Leggere lo stato dell'ora sulla macchina locale

Iniziare con un comando. Risponde alla domanda «c'è qualcosa che mantiene corretta questa ora?» in una sola schermata.

timedatectl

Leggere queste righe invece di affidarsi a un numero ricordato:

  • Local time e Universal time rappresentano lo stesso istante, visualizzato nel fuso orario locale e in UTC. Se sono identici, la macchina usa già UTC.
  • RTC time è l'orologio hardware descritto sopra. Su un VPS, ignorarlo.
  • Time zone indica ciò che il sistema usa per formattare l'ora locale.
  • System clock synchronized è il flag interno del kernel. Un demone per la sincronizzazione dell'ora lo imposta quando considera affidabili le proprie sorgenti; quindi no significa che nessun demone ha corretto questo orologio dall'avvio.
  • NTP service restituisce informazioni specifiche su systemd-timesyncd. n/a è normale su una macchina che esegue chrony, perché timesyncd non è installato. System clock synchronized: yes insieme a NTP service: n/a significa che chrony sta eseguendo la sincronizzazione e che il kernel lo conferma.

Successivamente, verificare di quanto l'orologio è fuori sincronizzazione. Non confrontarlo a vista con il telefono. Se chrony è in esecuzione:

chronyc tracking
chronyc sources -v

chronyc tracking stampa i valori che rispondono alla domanda. System time è l'offset corrente rispetto all'ora NTP, seguito dalla parola fast o slow. Last offset è l'entità della correzione più recente. Frequency è l'errore di frequenza misurato da chrony nell'orologio, che chrony sta già compensando. Leap status dovrebbe restituire Normal. Se restituisce Not synchronised e Reference ID è 00000000 (), chrony non ha ancora selezionato una sorgente.

chronyc sources -v stampa una legenda sopra l'elenco, quindi non è necessario ricordare i simboli. Due colonne contengono la maggior parte delle informazioni. Il carattere di stato all'inizio di ogni riga indica la valutazione che chrony assegna alla sorgente: * identifica la sorgente attualmente utilizzata, mentre ? su ogni riga significa che nessuna sorgente risponde. Reach rappresenta la cronologia delle risposte degli ultimi otto sondaggi, stampata in ottale: 377 significa che tutte le otto richieste hanno ricevuto risposta, mentre 0 significa che non ne ha ricevuta nessuna.

Se invece il servizio responsabile è systemd-timesyncd:

timedatectl timesync-status
timedatectl show-timesync --all

timesync-status stampa il server con cui sta comunicando, l'intervallo di sondaggio e un valore Offset. Se il comando restituisce un errore relativo al servizio invece di stampare lo stato, timesyncd non è il demone responsabile su questa macchina. Anche questo risponde alla domanda iniziale.

Per un controllo approssimativo rispetto a una sorgente esterna, senza strumenti aggiuntivi, confrontare l'orologio con un'intestazione HTTP pubblica Date, fornita in GMT con una risoluzione di un secondo:

date -u
curl -sI https://www.cloudflare.com | grep -i '^date:'

Una differenza di uno o due secondi è normale e non indica alcun problema. Una differenza di un minuto indica un errore nella configurazione.

chrony o systemd-timesyncd su un VPS

Ubuntu e Debian includono systemd-timesyncd per impostazione predefinita. È un client SNTP (simple network time protocol): interroga un server alla volta e avvicina gradualmente l’orologio al suo riferimento. Su una macchina sempre connessa e inizialmente abbastanza precisa, è sufficiente e richiede risorse trascurabili.

chrony è un’implementazione NTP completa e rappresenta la scelta predefinita migliore su una macchina virtuale, per motivi visibili nel suo stesso output. Interroga più sorgenti contemporaneamente e scarta quelle che non concordano. Misura l’errore di frequenza dell’orologio e lo scrive in un file di deriva, correggendo così la tendenza dell’orologio invece di inseguire ogni singolo campione. Inoltre recupera rapidamente dalle due condizioni tipiche di una VM e non di un server fisico: l’host può metterla in pausa e può trasferirla a un altro host mentre è in esecuzione. Quando è disponibile un dispositivo PTP dell’host, è chrony a leggerlo.

sudo apt update && sudo apt install -y chrony
systemctl status chrony --no-pager
chronyc sources -v
chronyc tracking

Leggere l’output di apt mentre il comando è in esecuzione. Su Debian e Ubuntu, i pacchetti chrony e systemd-timesyncd forniscono entrambi time-daemon, quindi apt rimuove timesyncd mentre installa chrony. È il comportamento corretto e previsto. Non eseguire mai entrambi, perché due demoni che impostano lo stesso orologio entrano in conflitto e, finché il conflitto continua, non è possibile considerare attendibile l’offset riportato da nessuno dei due. Su Rocky e AlmaLinux, installare con sudo dnf install -y chrony, dove l’unità si chiama chronyd anziché chrony.

Il file di configurazione è /etc/chrony/chrony.conf su Debian e Ubuntu e /etc/chrony.conf su Rocky e Alma. La configurazione predefinita della distribuzione è già adatta a un VPS, quindi modificarla solo per un motivo specifico. È utile comprendere due direttive:

  • Le righe pool e server indicano le sorgenti temporali. Aggiungendo iburst si ordina a chrony di inviare un burst rapido all’avvio, in modo che la prima sincronizzazione avvenga in pochi secondi anziché in alcuni minuti.
  • makestep stabilisce quando chrony deve correggere bruscamente l’orologio invece di modificarlo gradualmente. Verificare il valore configurato con grep -n makestep /etc/chrony/chrony.conf. Il valore predefinito di Debian e Ubuntu, makestep 1 3, significa quanto segue: durante i primi tre aggiornamenti dopo l’avvio di chronyd, correggere bruscamente l’orologio se lo scarto supera un secondo; in seguito, correggerlo soltanto gradualmente.

Se si desidera autenticare il traffico dell’ora per proteggerlo da manomissioni durante il transito, chrony 4 e versioni successive supportano NTS (network time security). Verificare prima la versione con chronyd -v e tenere presente che NTS richiede aperta anche la porta TCP 4460, oltre alla porta UDP 123:

server time.cloudflare.com iburst nts

Riavviare il servizio e verificarlo prima di considerarlo affidabile. Se la configurazione non viene analizzata correttamente, non rimane alcun demone per la sincronizzazione dell’ora e l’orologio non lo segnala.

sudo systemctl restart chrony
chronyc sources -v
chronyc tracking

Perché un orologio che è indietro di alcuni minuti continua a esserlo

Un demone per la sincronizzazione dell’ora può correggere lo scostamento in due modi. Con lo slewing accelera o rallenta l’orologio finché l’errore non scompare. In questo modo l’ora continua ad avanzare e non vengono mai ripetuti o saltati timestamp. Con lo stepping imposta direttamente il valore corretto. È più rapido, ma può spostare l’orologio all’indietro. Questo comportamento è rischioso per tutto ciò che misura il tempo trascorso usando l’orologio di sistema. Per questo entrambi i demoni preferiscono lo slewing.

Questa preferenza spiega perché un orologio molto fuori fase può rimanere errato a lungo. chrony esegue lo stepping solo all’interno della finestra consentita da makestep, che per impostazione predefinita comprende i primi aggiornamenti dopo l’avvio del demone. Se chronyd è in esecuzione da una settimana e rileva poi un errore di quaranta secondi, lo corregge con lo slewing. Correggere quaranta secondi in questo modo richiede molto più tempo di quanto sia opportuno attendere. Forza la correzione una volta, in modo deliberato e in un momento di bassa attività:

sudo chronyc makestep
chronyc tracking

chronyc tracking dovrebbe ora riportare un offset System time vicino a zero, mentre Last offset dovrebbe mostrare l’entità della correzione appena applicata. Valuta con attenzione l’esecuzione di questo comando su un database molto utilizzato, perché uno spostamento all’indietro dell’orologio può confondere il software che presuppone un avanzamento sempre crescente del tempo. Riavviare il demone è una variante più prudente della stessa correzione, perché all’avvio la finestra makestep si apre nuovamente.

I container condividono l'orologio dell'host

Un container non ha un proprio orologio civile, quindi al suo interno non c'è nulla da sincronizzare. I namespace temporali di Linux virtualizzano solo gli orologi monotonic e di avvio. CLOCK_REALTIME non è virtualizzato: un container legge quindi lo stesso orologio di sistema dell'host su cui è in esecuzione. Correggi l'orologio sull'host e tutti i container su quell'host verranno corretti nello stesso momento.

Da questo derivano alcune conseguenze. Non installare chrony o ntpd in un'immagine, perché nella migliore delle ipotesi non producono alcun effetto. L'impostazione della data all'interno di un container senza privilegi fallisce con date: cannot set date: Operation not permitted, perché per quella chiamata il kernel richiede CAP_SYS_TIME. La concessione di CAP_SYS_TIME non assegna al container un orologio privato: gli consente di modificare l'orologio dell'host e quindi anche quello di tutti gli altri container.

Un fuso orario diverso all'interno di un container non è un problema dell'orologio. Un'immagine che contiene il proprio /etc/localtime stampa lo stesso istante formattato per un altro fuso, quindi date sembra errato mentre l'orologio è corretto. Imposta TZ=UTC nell'ambiente del container per eliminare la confusione. Il runtime scelto non cambia nulla in questo caso; il confronto tra Podman e Docker rootless descrive invece ciò che cambia.

Fusi orari: UTC sul server, ora locale per gli utenti

Impostate la macchina su UTC e lasciatela così.

timedatectl list-timezones | grep -i utc
sudo timedatectl set-timezone UTC
timedatectl

UTC non applica l’ora legale, e questo è l’argomento principale. Un’attività giornaliera alle 02:30 in un fuso che applica l’ora legale viene eseguita due volte nel giorno in cui gli orologi tornano indietro e non viene eseguita affatto nel giorno in cui avanzano. man 8 cron documenta la gestione speciale per gli spostamenti inferiori a tre ore: le attività saltate a causa di un avanzamento vengono eseguite poco dopo il cambio, mentre le attività che ricadono nell’ora ripetuta a causa di un arretramento non vengono eseguite una seconda volta. Questo comportamento è ragionevole, ma non dovreste doverlo valutare alle 03:00. Con UTC l’attività viene eseguita una volta al giorno, ogni giorno dell’anno. Se un’attività non viene proprio eseguita, invece di partire a un’ora insolita, è più probabile che la causa sia un’attività cron che non viene mai eseguita senza messaggi.

Lo stesso principio vale per la lettura dei log. journalctl formatta i timestamp usando il fuso orario del sistema, mentre journalctl --utc forza l’uso di UTC. Due server in due fusi diversi trasformano ogni incidente in un esercizio di conversione, e le conversioni eseguite sotto pressione sono una causa comune di interpretazioni errate della sequenza temporale. Mantenete i sistemi su UTC, memorizzate i timestamp in UTC e convertiteli una sola volta, nel punto in cui li legge una persona. Chi vuole visualizzare l’ora locale per un singolo comando può farlo senza modificare la configurazione della macchina:

TZ=Europe/Berlin date

Nell’output di timedatectl c’è un’altra riga pertinente a questa sezione. RTC in local TZ dovrebbe restituire no. Impostarlo su yes è una soluzione temporanea per usare Windows in dual boot su un laptop; su un server aggiunge soltanto un offset che in seguito può causare errori. Quando è impostato, timedatectl stampa un avviso che indica che il sistema è configurato per leggere l’ora dell’RTC nel fuso orario locale.

Risoluzione dei problemi in base al sintomo

Il codice di autenticazione a due fattori viene rifiutato su un server. Controlla l'orologio prima di qualsiasi altra cosa. Il codice deriva da un contatore che avanza ogni 30 secondi. Un server indietro di 90 secondi calcola quindi il codice relativo a un intervallo già superato dal telefono. timedatectl mostrerà System clock synchronized: no oppure chronyc tracking segnalerà uno scostamento System time elevato. Questo errore è diverso dal rifiuto diretto di una chiave, che visualizza un messaggio specifico ed è trattato nella guida agli errori di autenticazione con chiave pubblica.

apt update segnala che un file Release non è ancora valido. Il messaggio completo indica il repository e per quanto tempo resterà non valido, ad esempio is not valid yet (invalid for another 1d 2h 3min 4s). L'orologio è indietro rispetto alla data contenuta nel file Release del repository. La durata indicata misura direttamente di quanto è indietro. Correggi l'orologio. Non disabilitare il controllo della data di apt per superare il problema, perché questo controllo impedisce a qualcuno di fornirti un indice dei pacchetti obsoleto.

Ogni riga delle sorgenti mostra lo stato irraggiungibile e Reach è 0. Nessuno risponde, quindi controlla il traffico in uscita invece della configurazione. NTP usa la porta UDP 123 in uscita e alcune reti filtrano o reindirizzano questo traffico. sudo chronyc ntpdata visualizza i contatori per ogni sorgente, inclusi Total TX e Total RX. Se il conteggio TX aumenta mentre RX resta a zero, i pacchetti escono ma non arriva alcuna risposta. Questo indica un firewall tra il sistema e la sorgente.

L'orologio era corretto, poi ha fatto un salto. Gli eventi dell'host possono causare questo comportamento. Il ripristino di uno snapshot, la sospensione di una macchina guest o una migrazione live verso un altro host possono lasciare l'ora della guest indietro rispetto a quella reale. chrony rileva il problema al polling successivo e corregge l'orologio; systemd-timesyncd può invece attendere prima un lungo intervallo di polling. Verifica che il daemon venga avviato al boot con systemctl is-enabled chrony, perché un daemon avviato manualmente non sarà più attivo dopo il riavvio successivo.

Lo scostamento è ridotto, ma non si stabilizza mai. Controlla il CPU steal. Se una guest non viene schedulata quando scade l'interrupt del timer, i campioni vengono ritardati e lo scostamento oscilla invece di convergere. top mostra questo valore come parametro st nella riga della CPU. La lettura del CPU steal time su un host condiviso spiega il significato di questo valore e come intervenire.

Un certificato appena emesso viene rifiutato perché non è ancora valido. curl visualizza SSL certificate problem: certificate is not yet valid e i browser mostrano un messaggio simile. Il certificato è valido; è l'orologio che lo verifica a essere indietro. Il problema può riguardare il client o il server, quindi controlla entrambi. Se il server che ha emesso il certificato è quello con l'orologio errato, la guida ai certificati di certbot e nginx tratta il rinnovo nella stessa configurazione.

Aggiungilo ai controlli che esegui già

La sincronizzazione dell'ora è un'impostazione del processo di avvio che può smettere di funzionare senza produrre errori evidenti mesi dopo. È esattamente il tipo di problema che un controllo periodico rileva, mentre la memoria può dimenticarlo. timedatectl e chronyc tracking richiedono due secondi per essere letti insieme. Eseguili nell'ambito di primi dieci minuti su un nuovo VPS, quindi ripetili durante la checklist ordinaria di manutenzione di un server Linux. Se preferisci eseguire automaticamente il controllo e ricevere un avviso quando l'offset aumenta, la scrittura di un servizio e di un timer systemd illustra il modello per una piccola unità che genera report secondo una pianificazione.

FAQ

Come verificare se l'orologio del mio VPS è sincronizzato?

Eseguire timedatectl e leggere la riga System clock synchronized. Questo è il flag interno del kernel, impostato dal demone che sincronizza l'orologio. Pertanto, su una macchina che usa chrony, la presenza contemporanea di yes e NTP service: n/a è normale e indica uno stato corretto. Per conoscere l'entità dell'errore, eseguire chronyc tracking e leggere System time oppure eseguire timedatectl timesync-status e leggere Offset se il servizio responsabile è systemd-timesyncd. Per un controllo basato su un sistema esterno alla macchina, confrontare date -u con l'header Date restituito da un sito HTTPS qualsiasi.

È meglio usare chrony o systemd-timesyncd su un VPS?

Usare chrony per i sistemi importanti. systemd-timesyncd è un client SNTP che utilizza un solo server ed è adeguato per una macchina sempre online che parte con un orologio già abbastanza preciso. chrony interroga più sorgenti, scarta quelle discordanti, apprende l'errore di frequenza dell'orologio e recupera rapidamente dopo una pausa dell'host o una migrazione live. L'installazione di chrony su Debian o Ubuntu rimuove automaticamente systemd-timesyncd, perché entrambi i pacchetti forniscono time-daemon. Non eseguire mai due demoni di sincronizzazione dell'ora contemporaneamente.

Perché i codici TOTP non funzionano su un server, ma funzionano ovunque altro?

Perché un codice TOTP è una funzione dell'ora corrente. Il codice deriva da un contatore che avanza ogni 30 secondi, quindi il server e il telefono devono concordare sull'intervallo temporale corrente. La maggior parte dei verificatori accetta anche l'intervallo precedente o quello successivo, con un margine di circa mezzo minuto in entrambe le direzioni. Controllare timedatectl sul server interessato. Se System clock synchronized restituisce no, correggere la sincronizzazione: i codici torneranno a corrispondere senza modificare il secret condiviso.

Posso impostare l'ora all'interno di un container Docker?

No, e non è necessario. Un container condivide CLOCK_REALTIME dell'host, perché i namespace temporali di Linux virtualizzano soltanto gli orologi monotonic e di avvio. Un container senza privilegi riceve date: cannot set date: Operation not permitted e l'aggiunta di CAP_SYS_TIME gli consente di modificare l'orologio dell'host, invece di assegnargliene uno proprio. Sincronizzare quindi l'host. Un'ora locale diversa all'interno di un container è un'impostazione del fuso orario; impostare TZ nell'ambiente del container.

Un server deve usare UTC o l'ora locale?

UTC, applicando l'ora locale nel momento in cui una persona legge l'output. UTC non cambia con l'ora legale, quindi un'attività giornaliera viene eseguita una volta al giorno per tutto l'anno e i timestamp di server diversi restano allineati senza conversioni. Impostarla con sudo timedatectl set-timezone UTC. Chi ha bisogno di visualizzare l'ora locale può anteporre un singolo comando, ad esempio TZ=America/New_York date, senza modificare l'orologio di sistema.