SSD Nodes Learn Hosting plans →
Посібники Matt ConnorВід Matt Connor · Оновлено 2026-08-28

Чому відстає годинник VPS і як його синхронізувати

Дізнайтеся, як знайти зсув часу VPS, читати вивід chronyc і timedatectl та відновити синхронізацію, через яку перестав працювати вхід 2FA.

Чому годинник VPS відстає

Годинник VPS відстає, якщо його ніхто не коригує. Ядро відлічує час за апаратним лічильником, який працює трохи швидше або трохи повільніше. Якщо клієнт синхронізації часу не запущений, ця невелика похибка щогодини зростає. У віртуальній машині є ще одна причина: гостьова система спільно використовує фізичний CPU з іншими гостями, тому в моменти, коли їй не виділено процесорний час, вона не може відлічувати час.

У сучасному KVM guest сам лічильник рідко є справжньою проблемою. Паравіртуальне джерело kvm-clock зчитує значення, яке підтримує host, тому справний guest майже точно синхронізований із host. Помітно неправильний час зазвичай має простішу причину. Демон синхронізації не запущений, або запущено два демони, які конфліктують між собою, або вихідний UDP port 123 не виходить за межі мережі вашого провайдера. Guest синхронізує час із host або через NTP (network time protocol), а не за власним осцилятором.

Що насправді ламає неправильний час

  • Коди двофакторної автентифікації TOTP (time-based one-time password) перестають збігатися, тому ви втрачаєте доступ до сервера, навіть якщо пароль і ключ правильні.
  • Сертифікат, виданий хвилину тому, відхиляється, а curl виводить SSL certificate problem: certificate is not yet valid.
  • apt update відхиляє репозиторій із повідомленням E: Release file for ... is not valid yet (invalid for another 1d 2h 3min 4s).
  • Заплановані завдання запускаються в неправильний момент, а стрибок системного часу може спричинити повторний запуск одного завдання та пропуск іншого.
  • Журнали з двох серверів неможливо зіставити, тому часову шкалу інциденту доводиться відновлювати приблизно.

Допустиме відхилення менше, ніж зазвичай очікують. Наведені нижче значення є задокументованими типовими значеннями, а не результатами вимірювань під час тесту.

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"
  }
]

Код TOTP обчислюється на основі лічильника, який збільшується кожні 30 секунд, і більшість засобів перевірки приймають також один сусідній інтервал. Тридцять секунд похибки в кожному напрямку — це весь допустимий запас. Kerberos значно менш чутливий до відхилення: типовий допустимий зсув становить 300 секунд. Сертифікат не має такого запасу: його перевіряють у фіксовані моменти з допуском 0 секунд, тому годинник, який відстає на одну секунду, відхиляє сертифікат, що насправді є чинним.

Три годинники і який із них має значення

Системний годинник — це годинник, який має значення. Це CLOCK_REALTIME ядра: кількість секунд від 1 січня 1970 року за UTC, що зберігається в пам’яті та зчитується всім, що додає мітки часу. Із нього беруться рядки журналів, перевірки сертифікатів, коди TOTP і час модифікації файлів. Коли хтось каже, що час на сервері неправильний, мається на увазі саме цей годинник.

Апаратний годинник, також відомий як RTC (real time clock), — це окремий лічильник, який продовжує працювати, коли машину вимкнено. На фізичній машині це мікросхема з батарейним живленням. Усередині гостьової системи його емулює гіпервізор, тому здебільшого це артефакт хоста. Linux зчитує його один раз під час завантаження, щоб отримати початкове значення, а потім веде власний відлік. timedatectl виводить його в рядку RTC time. Не діагностуйте проблеми за цим рядком на VPS, оскільки він показує уявлення хоста про час, а не стан синхронізації системного годинника. У контейнері зазвичай взагалі немає /dev/rtc, тому hwclock --show завершується з помилкою hwclock: Cannot access the Hardware Clock via any known method.

Джерело часу — це механізм, за допомогою якого ядро веде відлік між цими зчитуваннями. Запитайте в ядра, яке джерело воно вибрало:

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

У KVM ви зазвичай побачите kvm-clock. Воно зчитує значення, яке підтримує хост, тому гостьова система KVM без NTP-клієнта все одно певний час зберігає приблизно правильний час. tsc — це власний лічильник процесора. Гостьові системи Xen повідомляють про xen, а гостьові системи Hyper-V — про джерело hyperv. Не змінюйте це налаштування без виміряної причини, оскільки ядро вже вибирає найкраще джерело, якому довіряє на цьому обладнанні.

Деякі хости також передають гостьовій системі пристрій PTP (precision time protocol), що дає змогу chrony зчитувати годинник хоста безпосередньо, а не через мережу. Це варто перевірити, але на спільному VPS такий пристрій часто недоступний:

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

Якщо modprobe завершується з помилкою або пристрій не з’являється, ваш хост його не надає, і для вас залишається мережевий NTP. Якщо clock_name називає віртуальний годинник KVM, chrony може використовувати його з рядком refclock PHC /dev/ptp0 poll 2 у своїй конфігурації.

Перевірте стан часу на власній машині

Почніть з однієї команди. Вона виводить на одному екрані відповідь на запитання «чи підтримує щось правильний час на цьому годиннику».

timedatectl

Читайте ці рядки, а не покладайтеся на число, яке пам’ятаєте:

  • Local time і Universal time — це той самий момент часу, надрукований у вашому часовому поясі та в UTC. Якщо вони однакові, машина вже працює в UTC.
  • RTC time — це описаний вище апаратний годинник. На VPS ігноруйте його.
  • Time zone — це значення, яке система використовує для форматування місцевого часу.
  • System clock synchronized — власний прапорець ядра. Демон синхронізації часу встановлює його після того, як починає довіряти своїм джерелам, тому no означає, що після завантаження жоден процес не коригував цей годинник.
  • NTP service показує стан саме systemd-timesyncd. n/a є нормальним значенням на машині, де працює chrony, оскільки timesyncd там не встановлено. System clock synchronized: yes разом із NTP service: n/a означає, що роботу виконує chrony і ядро це підтверджує.

Далі перевірте величину відхилення. Не оцінюйте її на око за часом на телефоні. Якщо chrony працює:

chronyc tracking
chronyc sources -v

chronyc tracking виводить числа, які відповідають на це запитання. System time — поточне зміщення відносно часу NTP, після нього виводиться слово fast або slow. Last offset — величина останньої корекції. Frequency — похибка частоти, яку chrony виміряв для вашого годинника та вже компенсує. Leap status має містити значення Normal. Якщо виводиться Not synchronised, а Reference ID має значення 00000000 (), chrony ще не вибрав джерело.

chronyc sources -v виводить легенду над списком, тому вам не потрібно запам’ятовувати символи. Основне значення мають два стовпці. Символ стану на початку кожного рядка показує оцінку chrony для цього джерела: * позначає джерело, яке використовується зараз, а ? у кожному рядку означає, що жодне джерело не відповідає. Reach — це історія відповідей на останні вісім опитувань, надрукована у вісімковій системі: 377 означає, що отримано всі вісім відповідей, а 0 — що не отримано жодної.

Якщо за синхронізацію відповідає systemd-timesyncd:

timedatectl timesync-status
timedatectl show-timesync --all

timesync-status виводить сервер, з яким встановлено зв’язок, інтервал опитування та значення Offset. Якщо команда повертає помилку про сервіс замість стану, timesyncd не є активним демоном на цій машині. Це і є відповідь на ваше запитання.

Для приблизної перевірки за зовнішнім джерелом без додаткових інструментів порівняйте час на машині з заголовком HTTP Date від публічного сервера. Він передається в GMT з точністю до однієї секунди:

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

Різниця в одну-дві секунди є нормальною та нічого не означає. Різниця в одну хвилину — це помилка у вашій конфігурації.

chrony чи systemd-timesyncd на VPS

Ubuntu і Debian за замовчуванням постачають systemd-timesyncd. Це клієнт SNTP (простого протоколу мережевого часу): він опитує один сервер за раз і наближає до нього системний час. На машині, яка постійно підключена до мережі й спочатку має приблизно правильний час, цього достатньо. Цей сервіс майже не споживає ресурсів.

chrony — це повна реалізація NTP і кращий варіант за замовчуванням для віртуальної машини. Причини цього видно з його власного виводу. Він одночасно опитує кілька джерел і відкидає ті, що дають розбіжні результати. Він вимірює похибку ходу системного годинника й записує її у drift-файл, тому виправляє сталу похибку годинника, а не реагує на кожне окреме вимірювання. chrony також швидко відновлює час після двох подій, характерних для VM, але не для фізичного сервера: хост може призупинити VM, а VM може бути перенесена на інший хост під час роботи. Якщо хост надає PTP-пристрій, саме chrony зчитує час із нього.

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

Читайте вивід apt під час виконання. У Debian і Ubuntu пакети chrony та systemd-timesyncd обидва надають time-daemon, тому apt видаляє timesyncd під час встановлення chrony. Це правильна й очікувана поведінка. Не запускайте обидва сервіси одночасно: два daemon-и, які встановлюють один і той самий системний час, конфліктуватимуть, і поки це триває, не можна буде довіряти значенню offset, яке повідомляє жоден із них. У Rocky та AlmaLinux встановлюйте пакет за допомогою sudo dnf install -y chrony. Там unit називається chronyd, а не chrony.

Файл конфігурації має назву /etc/chrony/chrony.conf у Debian і Ubuntu та /etc/chrony.conf у Rocky і Alma. Значення за замовчуванням у дистрибутиві вже підходять для VPS, тому змінюйте їх лише за конкретної потреби. Варто розуміти два типи директив:

  • Рядки pool і server задають джерела часу. Додавання iburst вказує chrony надіслати швидку серію запитів під час запуску, щоб перша синхронізація відбулася за секунди, а не за хвилини.
  • makestep визначає, коли chrony встановлює час стрибком, а не поступово коригує його. Перевірте поточне значення за допомогою grep -n makestep /etc/chrony/chrony.conf. Значення за замовчуванням у Debian і Ubuntu, makestep 1 3, означає таке: під час перших трьох оновлень після запуску chronyd встановити час стрибком, якщо похибка перевищує одну секунду, а після цього виконувати коригування лише поступовою зміною швидкості годинника.

Якщо потрібно автентифікувати мережевий трафік часу для захисту від підміни на шляху передавання, chrony 4 і новіші версії підтримують NTS (мережеву безпеку часу). Спочатку перевірте версію за допомогою chronyd -v і врахуйте, що для NTS, крім UDP-порту 123, має бути відкритий вихідний TCP-порт 4460:

server time.cloudflare.com iburst nts

Перезапустіть сервіс і перевірте його стан, перш ніж покладатися на нього. Якщо конфігурацію не вдасться розібрати, time daemon взагалі не запуститься, а системний годинник не повідомить вам про цю проблему.

sudo systemctl restart chrony
chronyc sources -v
chronyc tracking

Чому годинник, який відстає на кілька хвилин, продовжує відставати

Демон синхронізації часу має два способи виправити зміщення. Плавна корекція прискорює або сповільнює годинник, доки помилка не зникне. Час при цьому продовжує рухатися вперед, а мітки часу не повторюються й не пропускаються. Стрибкова корекція одразу встановлює правильне значення. Це швидко, але годинник може переміститися назад. Зворотний рух небезпечний для всього, що вимірює тривалість за системним часом. Тому обидва демони надають перевагу плавній корекції.

Саме тому годинник із великою похибкою може залишатися неточним протягом тривалого часу. chrony виконує стрибкову корекцію лише в межах вікна, яке дозволяє makestep. За замовчуванням це перші кілька оновлень після запуску демона. Якщо chronyd працює вже тиждень і виявляє похибку в сорок секунд, він виправляє її плавно. На таку плавну корекцію сорока секунд потрібно значно більше часу, ніж ви готові чекати. Виконайте одноразову примусову корекцію в спокійний момент:

sudo chronyc makestep
chronyc tracking

Тепер chronyc tracking має показувати зміщення System time, близьке до нуля, а Last offset — розмір щойно виправленої похибки. Перш ніж виконувати це на зайнятому сервері бази даних, врахуйте, що зворотний стрибок системного часу може порушити роботу програм, які припускають, що час рухається лише вперед. Перезапуск демона є обережнішим варіантом тієї самої корекції, оскільки під час запуску вікно makestep відкривається знову.

Контейнери використовують годинник хоста

Контейнер не має власного системного годинника, тому синхронізувати в ньому нічого. Простори імен часу Linux віртуалізують лише монотонний годинник і годинник часу завантаження. CLOCK_REALTIME не віртуалізується, тому контейнер читає той самий системний час, що й хост, на якому він працює. Виправте час на хості — і час у кожному контейнері цього хоста буде виправлено одночасно.

Це має кілька наслідків. Не встановлюйте chrony або ntpd в image, оскільки в найкращому разі це нічого не дасть. Спроба встановити дату в непривілейованому контейнері завершується помилкою date: cannot set date: Operation not permitted, оскільки ядро вимагає CAP_SYS_TIME для цього виклику. Надання CAP_SYS_TIME не створює для контейнера приватного годинника. Воно дає контейнеру змогу змінювати годинник хоста, а отже, і годинник усіх інших контейнерів.

Інший часовий пояс у контейнері — це не проблема годинника. image із власним /etc/localtime виводить той самий момент часу, але форматує його для іншого часового поясу, тому date виглядає неправильно, хоча годинник працює правильно. Установіть TZ=UTC у середовищі контейнера, і проблема зникне. Обраний runtime нічого тут не змінює, а в порівнянні rootless Podman і Docker описано, що саме він змінює.

Часові пояси: UTC на сервері, місцевий час для користувачів

Налаштуйте машину на UTC і більше не змінюйте це налаштування.

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

UTC не використовує літній час, і цього достатньо як аргументу. Щоденне завдання, заплановане на 02:30 у часовому поясі з переходом на літній час, виконується двічі в день переведення годинника назад і не виконується зовсім у день переведення годинника вперед. man 8 cron описує спеціальну обробку переходів тривалістю менше трьох годин: завдання, пропущені через перехід уперед, виконуються невдовзі після зміни, а завдання, що припали на повторену годину під час переходу назад, вдруге не виконуються. Така поведінка є розумною, але вам не доведеться аналізувати її о 03:00. У UTC завдання виконується раз на день, щодня протягом року. Якщо ваше завдання взагалі не запускається, а не виконується в незвичний час, найімовірніше, причина описана в причинах, через які cron job непомітно не запускається.

Цей самий аргумент стосується читання журналів. journalctl форматує часові мітки в системному часовому поясі, а journalctl --utc примусово використовує UTC. Два сервери у двох часових поясах перетворюють кожен інцидент на задачу з конвертації часу, а конвертації під тиском часто призводять до неправильного прочитання часової послідовності. Залишайте системи в UTC, зберігайте часові мітки в UTC і виконуйте конвертацію лише в момент, коли їх читає людина. Якщо для однієї команди потрібен місцевий час, його можна отримати без зміни налаштування машини:

TZ=Europe/Berlin date

У виводі timedatectl є ще один рядок, який стосується цього розділу. RTC in local TZ має містити значення no. Значення yes потрібне як обхідне рішення для подвійного завантаження Windows на ноутбуці, але на сервері воно лише додає зміщення, яке згодом може спричинити помилку. Якщо це значення встановлено, timedatectl виводить попередження про те, що систему налаштовано на читання часу RTC у місцевому часовому поясі.

Усунення несправностей за симптомами

Код двофакторної автентифікації відхиляється на одному сервері. Перш ніж перевіряти щось інше, перевірте годинник. Код обчислюється на основі лічильника, який збільшується кожні 30 секунд. Тому сервер, годинник якого відстає на 90 секунд, обчислює код для інтервалу, який телефон уже минув. timedatectl покаже System clock synchronized: no, або chronyc tracking повідомить про значне зміщення System time. Це інша проблема, ніж безпосереднє відхилення ключа. У такому разі виводиться окреме повідомлення, а проблему описано в посібнику з помилок автентифікації за publickey.

apt update повідомляє, що файл Release ще недійсний. Повне повідомлення містить назву репозиторію та час, протягом якого файл залишатиметься недійсним, наприклад is not valid yet (invalid for another 1d 2h 3min 4s). Годинник відстає від дати у файлі Release репозиторію. Зазначений проміжок часу безпосередньо показує величину відставання. Виправте час. Не вимикайте перевірку дати в apt, щоб обійти цю помилку, оскільки саме ця перевірка не дає зловмиснику передати вам застарілий індекс пакетів.

У кожному рядку джерела показано стан недоступності, а Reach дорівнює 0. Ніхто не відповідає, тому перевіряйте вихідний мережевий трафік, а не конфігурацію. NTP використовує вихідний UDP-порт 123, і деякі мережі фільтрують або перенаправляють цей трафік. sudo chronyc ntpdata виводить лічильники для кожного джерела, зокрема Total TX і Total RX. Якщо лічильник TX зростає, а RX залишається нульовим, це означає, що пакети залишають сервер, але відповіді не повертаються. Ймовірно, між сервером і джерелом працює firewall.

Годинник показував правильний час, а потім змістився. Це може бути наслідком подій на хості. Відновлення snapshot, призупинення гостьової системи або live migration на інший хост можуть спричинити відставання часу в гостьовій системі від фактичного часу. chrony помітить проблему під час наступного опитування та виправить її. systemd-timesyncd може спочатку чекати завершення тривалого інтервалу опитування. Переконайтеся, що daemon запускається під час завантаження, за допомогою systemctl is-enabled chrony, оскільки daemon, запущений вручну, не працюватиме після наступного перезавантаження.

Зміщення невелике, але ніколи не стабілізується. Перевірте CPU steal. Якщо гостьова система не отримує процесорний час у момент, коли має відбутися переривання таймера, її вимірювання затримуються. Через це зміщення коливається замість того, щоб зменшуватися. top показує це як значення st у рядку CPU. У матеріалі Як читати CPU steal time на спільному хості пояснено значення цього показника та способи усунення проблеми.

Сертифікат, який ви щойно випустили, відхиляється як ще недійсний. curl виводить SSL certificate problem: certificate is not yet valid, а браузери показують подібне повідомлення. Сертифікат справний. Відстає годинник системи, яка його перевіряє. Проблемною може бути будь-яка з машин, тому перевірте і клієнт, і сервер. Якщо неправильний час встановлено на сервері, який випустив сертифікат, посібник із сертифікатів certbot і nginx описує поновлення в цій самій конфігурації.

Додайте це до перевірок, які ви вже виконуєте

Синхронізація часу — це параметр, заданий під час завантаження, який може непомітно перестати працювати через кілька місяців. Саме такі проблеми виявляє регулярна перевірка, тоді як пам’ять про них підводить. timedatectl і chronyc tracking разом займають для перевірки дві секунди. Виконуйте їх у межах перших десяти хвилин роботи на новому VPS, а також під час регулярної перевірки стану Linux-сервера. Якщо ви хочете, щоб перевірка запускалася автоматично й повідомляла, коли зміщення стає надто великим, у матеріалі про створення service і timer для systemd описано шаблон невеликого unit, який формує звіти за розкладом. Така перевірка є коротким скриптом, а не daemon, тому для неї потрібен Type=oneshot замість значення за замовчуванням. У матеріалі про типи service в systemd пояснено, чому неправильний тип залишає unit, який повідомляє про успішне виконання, хоча насправді його не досягнуто.

FAQ

Як перевірити, чи синхронізований час на моєму VPS?

Виконайте timedatectl і перегляньте рядок System clock synchronized. Це власний прапорець ядра, який встановлює daemon, що синхронізує системний час. Тому на сервері з chrony одночасна наявність yes і NTP service: n/a є нормальною та свідчить про справну синхронізацію. Щоб перевірити величину похибки, виконайте chronyc tracking і перегляньте System time. Якщо синхронізацією керує systemd-timesyncd, виконайте timedatectl timesync-status і перегляньте Offset. Для перевірки щодо зовнішнього джерела порівняйте date -u із заголовком Date, який повертає будь-який HTTPS-сайт.

Використовувати chrony чи systemd-timesyncd на VPS?

Для важливих систем використовуйте chrony. systemd-timesyncd — це SNTP-клієнт, який працює з одним сервером. Він підходить для машини, що постійно підключена до мережі та спочатку має майже правильний час. chrony опитує кілька джерел, відкидає джерела, показання яких відрізняються, визначає похибку ходу годинника та швидко відновлює синхронізацію після призупинення хоста або live migration. Встановлення chrony на Debian або Ubuntu автоматично видаляє systemd-timesyncd, оскільки обидва пакети надають time-daemon. Ніколи не запускайте два daemon синхронізації часу одночасно.

Чому коди TOTP не працюють на одному сервері, але працюють всюди в інших місцях?

Тому що код TOTP залежить від поточного часу. Код обчислюється на основі лічильника, який збільшується кожні 30 секунд. Тому сервер і телефон мають використовувати один і той самий часовий інтервал. Більшість засобів перевірки приймають також один сусідній інтервал у кожен бік. Це дає приблизно пів хвилини запасу в кожному напрямку. Перевірте timedatectl на цьому сервері. Якщо System clock synchronized має значення no, виправте синхронізацію. Після цього коди знову збігатимуться без зміни спільного секрету.

Чи можна встановити час усередині Docker-контейнера?

Ні, і потреби в цьому немає. Контейнер використовує CLOCK_REALTIME хоста, оскільки простори імен часу Linux віртуалізують лише монотонний годинник і годинник часу запуску. Непривілейований контейнер отримує date: cannot set date: Operation not permitted. Додавання CAP_SYS_TIME дає йому змогу змінювати годинник хоста, а не створює окремий годинник контейнера. Синхронізуйте час на хості. Інший локальний час усередині контейнера означає налаштування часового поясу. Тому встановіть TZ у середовищі контейнера.

Сервер має використовувати UTC чи місцевий час?

UTC. Місцевий час слід застосовувати лише під час перегляду результату людиною. UTC не змінюється через літній час. Тому щоденне завдання запускається один раз на добу протягом усього року, а часові позначки з різних серверів збігаються без конвертації. Встановіть UTC за допомогою sudo timedatectl set-timezone UTC. Щоб переглянути час у місцевому форматі, можна додати часовий пояс до окремої команди, наприклад TZ=America/New_York date. Це не змінює системний годинник.