SSD Nodes Learn Hosting plans →
Guides Matt ConnorPar Matt Connor · Mis à jour le 2026-08-22

VPS : corriger une horloge qui dérive

Votre VPS dérive-t-il ? Vérifiez timedatectl, chronyc et les paquets UDP 123 pour rétablir la synchronisation et récupérer vos connexions 2FA.

Pourquoi l’horloge de votre VPS dérive

L’horloge d’un VPS dérive parce que rien ne la corrige. Le noyau mesure le temps à partir d’un compteur matériel qui avance légèrement trop vite ou trop lentement. Sans client de synchronisation horaire, cette petite erreur s’accumule au fil des heures. Dans une machine virtuelle, une deuxième cause s’ajoute : votre invité partage un processeur physique avec d’autres invités. Lorsqu’il n’est pas planifié, il ne peut pas mesurer le temps.

Sur un invité KVM récent, le compteur lui-même est rarement à l’origine du problème. La source paravirtualisée kvm-clock lit une valeur maintenue par l’hôte. Un invité en bon état reste donc étroitement synchronisé avec son hôte. Les horloges manifestement incorrectes le sont généralement pour une raison plus simple. Aucun daemon de synchronisation ne fonctionne, ou deux daemons fonctionnent simultanément et se perturbent, ou les paquets UDP sortants vers le port 123 ne quittent jamais le réseau de votre fournisseur. Un invité synchronise son horloge avec l’hôte ou avec NTP (network time protocol), et non avec son propre oscillateur.

Ce qu’une horloge incorrecte casse réellement

  • Les codes TOTP (mots de passe à usage unique basés sur le temps) ne correspondent plus. Vous pouvez donc être bloqué hors d’un serveur dont le mot de passe et la clé sont pourtant corrects.
  • Un certificat émis il y a une minute est rejeté, et curl affiche SSL certificate problem: certificate is not yet valid.
  • apt update refuse un dépôt avec E: Release file for ... is not valid yet (invalid for another 1d 2h 3min 4s).
  • Les tâches planifiées s’exécutent au mauvais moment. Un saut de l’horloge peut faire exécuter deux fois une tâche et en ignorer une autre.
  • Les journaux de deux serveurs ne peuvent pas être alignés. La chronologie d’un incident doit donc être reconstituée au jugé.

La marge de tolérance est plus faible que la plupart des gens ne le pensent. Les valeurs ci-dessous sont des valeurs par défaut documentées, et non des mesures effectuées lors d’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 code TOTP est calculé à partir d’un compteur qui avance toutes les 30 secondes. La plupart des vérificateurs acceptent aussi l’étape précédente ou suivante. Une erreur d’une demi-minute dans chaque direction représente toute la marge disponible. Kerberos est beaucoup plus tolérant, avec une marge de dérive par défaut de 300 secondes. Un certificat, en revanche, ne tolère aucune dérive : il est vérifié par rapport à des instants précis, avec une période de grâce de 0 secondes. Une horloge retardée d’une seconde rejette donc un certificat parfaitement valide.

Les trois horloges, et celle qui compte

L’horloge système est celle qui compte. C’est le CLOCK_REALTIME du noyau : le nombre de secondes écoulées depuis le 1 janvier 1970 UTC, conservé en mémoire et lu par tout ce qui horodate des événements. Les lignes de journal, les vérifications de certificats, les codes TOTP et les dates de modification des fichiers proviennent tous de cette horloge. Quand quelqu’un dit que l’heure du serveur est incorrecte, c’est de cette horloge qu’il parle.

L’horloge matérielle, également appelée RTC (real time clock), est un compteur distinct qui continue de fonctionner lorsque la machine est éteinte. Sur une machine physique, il s’agit d’une puce alimentée par une batterie. Dans une machine virtuelle, elle est émulée par l’hyperviseur et dépend donc largement de l’hôte. Linux la lit une fois au démarrage pour obtenir une valeur initiale, puis conserve son propre compteur. timedatectl l’affiche sur la ligne RTC time. Ne vous basez pas sur cette ligne pour diagnostiquer un VPS : elle indique l’heure selon l’hôte, pas l’état de synchronisation de l’horloge système. Dans un conteneur, il n’y a généralement aucun /dev/rtc, et hwclock --show échoue avec hwclock: Cannot access the Hardware Clock via any known method.

La source d’horloge est le mécanisme utilisé par le noyau pour compter entre ces lectures. Demandez au noyau celle qu’il a sélectionnée :

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

Avec KVM, vous verrez généralement kvm-clock. Cette source lit une valeur maintenue par l’hôte. C’est pourquoi une machine virtuelle KVM sans client NTP reste approximativement à l’heure pendant un certain temps. tsc est le compteur interne du processeur. Les machines virtuelles Xen indiquent xen, et les machines virtuelles Hyper-V indiquent une source hyperv. Ne modifiez pas ce réglage sans raison mesurée : le noyau sélectionne déjà la meilleure source fiable pour ce matériel.

Certains hôtes exposent également un périphérique PTP (precision time protocol) à la machine virtuelle. chrony peut ainsi lire directement l’horloge de l’hôte au lieu de passer par le réseau. Vérifiez sa présence, car il est souvent indisponible sur un VPS mutualisé :

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

Si modprobe échoue ou si aucun périphérique n’apparaît, votre hôte ne le propose pas et NTP sur le réseau est votre seule option. Si clock_name désigne l’horloge virtuelle KVM, chrony peut l’utiliser avec une ligne refclock PHC /dev/ptp0 poll 2 dans sa configuration.

Lire l’état de l’heure sur votre propre machine

Commencez par une commande. Elle répond en un écran à la question « quelque chose maintient-il cette horloge à l’heure ? ».

timedatectl

Lisez ces lignes au lieu de vous fier à un nombre dont vous vous souvenez :

  • Local time et Universal time correspondent au même instant, affiché dans votre fuseau horaire et en UTC. S’ils sont identiques, la machine utilise déjà UTC.
  • RTC time est l’horloge matérielle décrite plus haut. Sur un VPS, ignorez-la.
  • Time zone indique ce que le système utilise pour formater l’heure locale.
  • System clock synchronized est le propre indicateur du kernel. Un daemon de temps le définit une fois qu’il fait confiance à ses sources. Ainsi, no signifie qu’aucun processus n’a discipliné cette horloge depuis le boot.
  • NTP service concerne spécifiquement systemd-timesyncd. n/a est normal sur une machine qui utilise chrony, car timesyncd n’y est pas installé. System clock synchronized: yes associé à NTP service: n/a signifie que chrony fait le travail et que le kernel est d’accord avec lui.

Demandez ensuite quelle est l’ampleur du décalage. Ne l’estimez pas à l’œil en la comparant à votre téléphone. Si chrony fonctionne :

chronyc tracking
chronyc sources -v

chronyc tracking affiche les nombres qui répondent à cette question. System time est le décalage actuel par rapport à l’heure NTP, suivi du mot fast ou slow. Last offset est l’ampleur de la correction la plus récente. Frequency est l’erreur de fréquence que chrony a mesurée sur votre horloge et qu’il compense déjà. Leap status devrait afficher Normal. S’il affiche Not synchronised et que Reference ID vaut 00000000 (), chrony n’a pas encore sélectionné de source.

chronyc sources -v affiche une légende au-dessus de la liste. Vous n’avez donc pas besoin de retenir les symboles. Deux colonnes contiennent l’essentiel des informations. Le caractère d’état au début de chaque ligne indique la façon dont chrony évalue cette source : * marque la source actuellement utilisée et ? sur chaque ligne signifie qu’aucune source ne répond. Reach indique l’historique des réponses aux huit derniers polls, affiché en octal : 377 signifie que les huit requêtes ont reçu une réponse, tandis que 0 signifie qu’aucune n’en a reçu.

Si systemd-timesyncd est utilisé à la place :

timedatectl timesync-status
timedatectl show-timesync --all

timesync-status affiche le serveur auquel la machine se connecte, l’intervalle entre les polls et une valeur Offset. Si la commande renvoie une erreur concernant le service au lieu d’afficher son état, timesyncd n’est pas le daemon utilisé sur cette machine. C’est déjà la réponse à votre question.

Pour effectuer une vérification approximative avec le monde extérieur sans outil supplémentaire, comparez votre horloge à un en-tête HTTP public Date, transmis en GMT avec une résolution d’une seconde :

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

Un écart d’une ou deux secondes est normal et ne signifie rien. Un écart d’une minute indique un problème sur votre machine.

chrony ou systemd-timesyncd sur un VPS

Ubuntu et Debian fournissent systemd-timesyncd par défaut. Il s’agit d’un client SNTP (simple network time protocol) : il interroge un serveur à la fois et rapproche l’horloge de cette référence. Sur une machine qui reste en ligne et dont l’heure initiale est à peu près correcte, cela suffit et le service consomme très peu de ressources.

chrony est une implémentation NTP complète et constitue un meilleur choix par défaut sur une machine virtuelle, comme le montrent ses propres sorties. Il interroge plusieurs sources simultanément et écarte celles qui sont incohérentes. Il mesure l’erreur de fréquence de l’horloge et l’enregistre dans un fichier de dérive. Il corrige ainsi la tendance de l’horloge au lieu de suivre chaque mesure. Il récupère également rapidement après les deux événements qu’une VM peut subir contrairement à une machine physique : son hôte peut la mettre en pause, et elle peut être déplacée vers un autre hôte pendant son fonctionnement. Lorsqu’un périphérique PTP de l’hôte est proposé, c’est chrony qui le lit.

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

Lisez la sortie d’apt pendant l’installation. Sur Debian et Ubuntu, les paquets chrony et systemd-timesyncd fournissent tous deux time-daemon. apt supprime donc timesyncd lors de l’installation de chrony. C’est le comportement attendu. N’exécutez jamais les deux services en même temps : deux démons qui règlent la même horloge vont entrer en conflit, et aucun des décalages indiqués ne sera fiable pendant ce conflit. Sur Rocky et AlmaLinux, installez chrony avec sudo dnf install -y chrony. L’unité s’appelle alors chronyd et non chrony.

Le fichier de configuration est /etc/chrony/chrony.conf sur Debian et Ubuntu, et /etc/chrony.conf sur Rocky et Alma. La configuration par défaut de la distribution convient déjà à un VPS. Ne la modifiez que pour une raison précise. Deux directives méritent d’être comprises :

  • Les lignes pool et server indiquent les sources de temps. Ajouter iburst demande à chrony d’envoyer une rafale rapide au démarrage. La première synchronisation a ainsi lieu en quelques secondes au lieu de plusieurs minutes.
  • makestep détermine quand chrony avance ou recule brusquement l’horloge au lieu de la corriger progressivement. Vérifiez sa valeur avec grep -n makestep /etc/chrony/chrony.conf. La valeur par défaut de Debian et Ubuntu, makestep 1 3, signifie ceci : lors des trois premières mises à jour après le démarrage de chronyd, l’horloge est corrigée d’un coup si son décalage dépasse une seconde. Ensuite, seule une correction progressive est appliquée.

Si vous voulez authentifier le trafic de temps afin de le protéger contre les altérations sur le chemin, chrony 4 et les versions ultérieures prennent en charge NTS (network time security). Vérifiez d’abord votre version avec chronyd -v. NTS nécessite également que le port TCP 4460 sortant soit ouvert, en plus du port UDP 123 :

server time.cloudflare.com iburst nts

Redémarrez le service et vérifiez son état avant de lui faire confiance. Une configuration impossible à analyser vous laisse sans démon de synchronisation de l’heure, et l’horloge ne vous l’indiquera pas.

sudo systemctl restart chrony
chronyc sources -v
chronyc tracking

Pourquoi une horloge décalée de plusieurs minutes le reste

Un démon de synchronisation de l’heure peut corriger un décalage de deux façons. Le ralentissement ou l’accélération progressive ajuste la vitesse de l’horloge jusqu’à disparition de l’erreur. Le temps continue ainsi d’avancer et aucun horodatage n’est répété ni ignoré. La correction par saut règle directement l’horloge sur la bonne valeur. Elle est rapide, mais peut faire reculer l’horloge. Ce recul est dangereux pour tout ce qui mesure une durée à partir de l’heure système. Les deux démons privilégient donc l’ajustement progressif.

C’est pourquoi une horloge fortement décalée peut le rester longtemps. chrony n’effectue une correction par saut que dans la fenêtre que makestep autorise, par défaut lors des premières mises à jour après le démarrage du démon. Si chronyd fonctionne depuis une semaine et détecte ensuite un décalage de quarante secondes, il l’ajuste progressivement. Corriger quarante secondes de cette façon prend beaucoup plus de temps que vous ne souhaitez en attendre. Forcez la correction une fois, volontairement, à un moment calme :

sudo chronyc makestep
chronyc tracking

chronyc tracking doit maintenant signaler un décalage System time proche de zéro, et Last offset doit afficher l’ampleur de la correction qui vient d’être appliquée. Réfléchissez avant d’exécuter cette commande sur un serveur de base de données très sollicité : un recul de l’horloge peut perturber les logiciels qui supposent que l’heure avance toujours. Redémarrer le démon est une version plus douce de la même correction, car la fenêtre makestep s’ouvre de nouveau au démarrage.

Les conteneurs partagent l’horloge de l’hôte

Un conteneur n’a pas sa propre horloge civile. Il n’y a donc rien à synchroniser à l’intérieur. Les namespaces temporels Linux virtualisent uniquement les horloges monotone et de démarrage. CLOCK_REALTIME n’est pas virtualisée, ce qui signifie qu’un conteneur lit la même horloge système que l’hôte sur lequel il s’exécute. Corrigez l’horloge sur l’hôte et tous les conteneurs de cet hôte seront corrigés au même moment.

Cela a plusieurs conséquences. N’installez pas chrony ou ntpd dans une image, car cela ne sert au mieux à rien. Modifier la date dans un conteneur non privilégié échoue avec date: cannot set date: Operation not permitted, car le noyau exige CAP_SYS_TIME pour cet appel. Accorder CAP_SYS_TIME ne donne pas au conteneur une horloge privée. Cela lui permet de modifier l’horloge de l’hôte, et donc celle de tous les autres conteneurs.

Un fuseau horaire différent dans un conteneur ne signale pas un problème d’horloge. Une image qui contient son propre /etc/localtime affiche le même instant, formaté pour un autre fuseau. Ainsi, date semble incorrect alors que l’horloge est correcte. Définissez TZ=UTC dans l’environnement du conteneur pour supprimer cette confusion. Le runtime choisi ne change rien à ce fonctionnement. La comparaison entre Podman et Docker rootless explique ce qu’il change effectivement.

Fuseaux horaires : UTC sur le serveur, heure locale pour les utilisateurs

Configurez la machine en UTC et ne modifiez plus ce réglage.

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

UTC n’applique pas l’heure d’été, et c’est l’argument principal. Une tâche quotidienne planifiée à 02:30 dans un fuseau qui applique l’heure d’été s’exécute deux fois le jour où les horloges reculent, et ne s’exécute pas du tout le jour où elles avancent. man 8 cron décrit le traitement particulier des décalages de moins de trois heures : les tâches ignorées lors d’un saut en avant sont exécutées peu après le changement, et les tâches situées dans l’heure répétée lors d’un recul ne sont pas exécutées une seconde fois. Ce comportement est raisonnable, mais vous ne devriez pas avoir à en tenir compte à 03:00. Avec UTC, la tâche s’exécute une fois par jour, chaque jour de l’année. Si une de vos tâches est totalement absente au lieu de s’exécuter à une heure inhabituelle, les raisons pour lesquelles une tâche cron ne s’exécute jamais sans message sont probablement à rechercher en priorité.

Le même raisonnement s’applique à la lecture des journaux. journalctl formate les horodatages selon le fuseau horaire du système, tandis que journalctl --utc force l’utilisation d’UTC. Deux serveurs situés dans deux fuseaux différents transforment chaque incident en exercice de conversion, et les conversions effectuées sous pression sont une source d’erreurs dans la chronologie. Laissez les systèmes en UTC, stockez les horodatages en UTC et effectuez la conversion une seule fois, au moment où une personne les lit. Toute personne qui souhaite obtenir l’heure locale pour une seule commande peut le faire sans modifier la machine :

TZ=Europe/Berlin date

Une autre ligne de la sortie de timedatectl concerne cette section. RTC in local TZ doit afficher no. Le définir sur yes est une solution de contournement pour un double démarrage de Windows sur un ordinateur portable. Sur un serveur, cela ajoute seulement un décalage qui risque de poser problème ultérieurement. Lorsque ce réglage est activé, timedatectl affiche un avertissement indiquant que le système est configuré pour lire l’heure de la RTC dans le fuseau horaire local.

Dépannage par symptôme

Votre code à deux facteurs est refusé sur un serveur. Vérifiez l’horloge avant toute autre chose. Le code provient d’un compteur qui avance toutes les 30 secondes. Un serveur en retard de 90 secondes calcule donc un code correspondant à une période déjà dépassée par votre téléphone. timedatectl affiche System clock synchronized: no, ou chronyc tracking signale un grand décalage de System time. Ce problème est différent d’une clé rejetée directement, qui affiche son propre message et qui est traité dans le guide des échecs d’authentification par clé publique.

apt update indique qu’un fichier Release n’est pas encore valide. Le message complet indique le dépôt concerné et la durée pendant laquelle il restera invalide, par exemple is not valid yet (invalid for another 1d 2h 3min 4s). Votre horloge retarde par rapport à la date indiquée dans le fichier Release du dépôt. Cette durée mesure directement le retard. Corrigez l’horloge. Ne désactivez pas la vérification de date d’apt pour contourner le problème, car cette vérification empêche qu’un tiers vous serve un index de paquets obsolète.

Chaque ligne de source affiche l’état inaccessible et Reach vaut 0. Rien ne répond. Examinez donc la connectivité sortante plutôt que votre configuration. NTP utilise le port UDP 123 en sortie, et certains réseaux filtrent ou redirigent ce trafic. sudo chronyc ntpdata affiche les compteurs par source, notamment Total TX et Total RX. Un compteur TX qui augmente alors que RX reste à zéro signifie que vos paquets partent sans qu’aucune réponse ne revienne. Cela indique la présence probable d’un firewall entre vous et la source.

L’horloge était correcte, puis a changé brusquement. Des événements liés à l’hôte peuvent provoquer ce comportement. La restauration d’un snapshot, la mise en pause d’un guest ou une migration à chaud vers un autre hôte peut laisser l’heure du guest en retard sur l’heure réelle. chrony le détecte lors du polling suivant et corrige l’écart. systemd-timesyncd peut d’abord attendre la fin d’un long intervalle de polling. Vérifiez que le daemon démarre au boot avec systemctl is-enabled chrony, car un daemon lancé manuellement ne survivra pas au redémarrage suivant.

Le décalage est faible, mais ne se stabilise jamais. Examinez le CPU steal. Un guest qui n’est pas planifié lorsque son interruption de timer doit être traitée obtient ses échantillons en retard. Le décalage varie alors au lieu de converger. top affiche cette valeur dans le champ st de la ligne du CPU. Lire le CPU steal time sur un hôte partagé explique la signification de cette valeur et les mesures possibles.

Un certificat que vous venez d’émettre est rejeté comme n’étant pas encore valide. curl affiche SSL certificate problem: certificate is not yet valid, et les navigateurs indiquent un message similaire. Le certificat est correct. C’est l’horloge qui le vérifie qui retarde. La machine cliente comme le serveur peuvent être en cause. Vérifiez donc les deux. Si le serveur qui a émis le certificat est celui dont l’horloge est incorrecte, le guide des certificats certbot et nginx traite le renouvellement dans cette même configuration.

Ajoutez-le aux contrôles que vous exécutez déjà

La synchronisation de l’heure est un paramètre appliqué au démarrage qui peut échouer silencieusement des mois plus tard. C’est exactement le type de problème qu’une routine détecte, contrairement à la mémoire. timedatectl et chronyc tracking prennent deux secondes à lire ensemble. Exécutez-les dans le cadre des dix premières minutes sur un nouveau VPS, puis de nouveau lorsque vous suivez la checklist de maintenance régulière d’un serveur Linux. Si vous préférez que le contrôle s’exécute automatiquement et vous alerte lorsque le décalage augmente, écrire un service et un timer systemd présente le modèle d’une petite unité qui génère un rapport selon un calendrier. Un contrôle de ce type est un script court, pas un daemon. Il nécessite donc Type=oneshot au lieu de la valeur par défaut, et le récapitulatif des types de services systemd explique pourquoi un type incorrect vous laisse avec une unité qui signale une réussite qu’elle n’a jamais obtenue.

FAQ

Comment vérifier que l’horloge de mon VPS est synchronisée ?

Exécutez timedatectl et lisez la ligne System clock synchronized. Il s’agit de l’indicateur propre au kernel, défini par le daemon qui synchronise l’horloge. La présence de yes avec NTP service: n/a est donc normale et indique que chrony fonctionne correctement. Pour connaître l’importance de l’écart, exécutez chronyc tracking et lisez System time. Vous pouvez aussi exécuter timedatectl timesync-status et lire Offset si systemd-timesyncd est utilisé. Pour comparer l’horloge à une source externe, comparez date -u avec l’en-tête Date renvoyé par n’importe quel site HTTPS.

Dois-je utiliser chrony ou systemd-timesyncd sur un VPS ?

Utilisez chrony pour tout serveur important. systemd-timesyncd est un client SNTP qui utilise un seul serveur. Il convient à une machine qui reste en ligne et dont l’horloge est déjà proche de l’heure correcte. chrony interroge plusieurs sources, écarte celles qui sont divergentes, apprend la dérive de l’horloge et se resynchronise rapidement après une pause de l’hôte ou une live migration. L’installation de chrony sur Debian ou Ubuntu supprime automatiquement systemd-timesyncd, car les deux paquets fournissent time-daemon. N’exécutez jamais deux daemons de synchronisation de l’heure en même temps.

Pourquoi mes codes TOTP échouent-ils sur un serveur alors qu’ils fonctionnent partout ailleurs ?

Parce qu’un code TOTP dépend de l’heure actuelle. Le code provient d’un compteur qui avance toutes les 30 secondes. Le serveur et votre téléphone doivent donc utiliser le même intervalle. La plupart des vérificateurs acceptent l’intervalle précédent ou suivant, ce qui laisse environ une demi-minute de marge dans chaque direction. Vérifiez timedatectl sur ce serveur. Si System clock synchronized renvoie no, corrigez la synchronisation. Les codes fonctionneront de nouveau sans modifier le secret partagé.

Puis-je régler l’heure à l’intérieur d’un conteneur Docker ?

Non, et ce n’est pas nécessaire. Un conteneur partage le CLOCK_REALTIME de l’hôte, car les namespaces de temps de Linux virtualisent uniquement les horloges monotonic et boot-time. Un conteneur sans privilèges reçoit date: cannot set date: Operation not permitted. L’ajout de CAP_SYS_TIME lui permettrait de modifier l’horloge de l’hôte, au lieu de lui fournir sa propre horloge. Synchronisez plutôt l’hôte. Une heure locale différente dans un conteneur correspond à un réglage de fuseau horaire. Définissez donc TZ dans l’environnement du conteneur.

Un serveur doit-il utiliser UTC ou l’heure locale ?

Utilisez UTC et appliquez l’heure locale au moment où une personne lit la sortie. UTC ne change pas lors du passage à l’heure d’été. Une tâche quotidienne s’exécute donc une fois par jour toute l’année, et les horodatages de plusieurs serveurs correspondent sans conversion. Définissez UTC avec sudo timedatectl set-timezone UTC. Pour afficher l’heure locale, il est possible de préfixer une seule commande, par exemple TZ=America/New_York date. Cela ne modifie pas l’horloge système.