SSD Nodes Learn 🎉 VPS از $5.50/ماه
راهنماها Matt Connorتوسط Matt Connor

علت عقب ماندن ساعت VPS و روش تنظیم دقیق زمان

ساعت سرور مجازی به دلیل عدم همگام‌سازی یا تداخل دیمون‌ها دچار انحراف می‌شود. با بررسی دستورات chronyc و timedatectl مشکل عدم تطابق زمان که باعث خطای 2FA می‌شود را رفع کنید.

چرا ساعت VPS شما دچار انحراف می‌شود

ساعت یک VPS به این دلیل دچار انحراف می‌شود که هیچ عاملی آن را اصلاح نمی‌کند. هسته سیستم‌عامل (kernel)، زمان را بر اساس یک شمارنده سخت‌افزاری محاسبه می‌کند که ممکن است کمی سریع‌تر یا کندتر از حد معمول کار کند؛ در نبود یک کلاینت همگام‌سازی زمان، این خطای کوچک در هر ساعت افزایش می‌یابد. در داخل یک ماشین مجازی، دلیل دومی نیز وجود دارد: سیستم‌عامل مهمان (guest) شما از یک CPU فیزیکی به‌صورت اشتراکی با سایر مهمان‌ها استفاده می‌کند، بنابراین لحظاتی که سیستم‌عامل شما برای پردازش زمان‌بندی (schedule) نمی‌شود، لحظاتی است که نمی‌تواند زمان را بشمارد.

در یک مهمان KVM امروزی، خودِ شمارنده به‌ندرت مشکل اصلی است. منبع kvm-clock پارا-مجازی (paravirtual)، مقداری را می‌خواند که میزبان (host) نگهداری می‌کند، بنابراین یک مهمان سالم زمان را با دقت بالایی نسبت به میزبان خود دنبال می‌کند. ساعت‌هایی که به‌طور مشهودی اشتباه هستند، معمولاً به دلایل ساده‌تری دچار خطا می‌شوند. یا هیچ دیمون همگام‌سازی در حال اجرا نیست، یا دو دیمون همزمان در حال اجرا هستند و با یکدیگر تداخل دارند، یا ترافیک خروجی پورت 123 (UDP) هرگز از شبکه ارائه‌دهنده شما خارج نمی‌شود. یک سیستم‌عامل مهمان، نظم زمانی خود را از میزبان یا از پروتکل NTP (پروتکل زمان شبکه) می‌گیرد، نه از نوسان‌ساز (oscillator) داخلی خودش.

پیامدهای واقعی تنظیم نبودن ساعت سیستم

  • کدهای احراز هویت دو مرحله‌ای TOTP (رمز یک‌بارمصرف مبتنی بر زمان) دیگر مطابقت ندارند؛ در نتیجه، حتی با داشتن رمز عبور و کلید صحیح، دسترسی شما به سرور مسدود می‌شود.
  • گواهی‌ای که همین یک دقیقه پیش صادر شده است رد می‌شود و 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 ثانیه‌ای بررسی می‌شوند؛ بنابراین ساعتی که حتی یک ثانیه جلوتر باشد، گواهی‌ای را که کاملاً معتبر است، رد می‌کند.

سه ساعت و اهمیت هر کدام

ساعت سیستم (system clock) همان ساعتی است که اهمیت دارد. این ساعت، CLOCK_REALTIME هسته است: شمارش ثانیه‌ها از 1 ژانویه 1970 به وقت UTC که در حافظه نگهداری می‌شود و توسط هر چیزی که برچسب زمانی می‌زند، خوانده می‌شود. خطوط لاگ، بررسی گواهی‌ها، کدهای TOTP و زمان تغییر فایل‌ها همگی از این ساعت می‌آیند. وقتی کسی می‌گوید زمان سرور اشتباه است، منظورش همین ساعت است.

ساعت سخت‌افزاری (hardware clock) که به آن RTC (ساعت زمان واقعی) نیز می‌گویند، یک شمارنده مجزا است که هنگام خاموش بودن دستگاه نیز به کار خود ادامه می‌دهد. در یک ماشین فیزیکی، این یک تراشه با پشتیبانی باتری است. در داخل یک guest، این ساعت توسط هایپروایزر شبیه‌سازی می‌شود، بنابراین تا حد زیادی یک مصنوع (artefact) از سمت میزبان (host) است. لینوکس این ساعت را یک بار در زمان بوت می‌خواند تا مقدار اولیه را به دست آورد و سپس شمارش خود را ادامه می‌دهد. دستور timedatectl آن را در خط RTC time چاپ می‌کند. برای عیب‌یابی در یک VPS از آن خط استفاده نکنید، زیرا به شما درباره تصور میزبان از زمان می‌گوید، نه درباره وضعیت همگام‌سازی ساعت سیستم شما. در یک کانتینر معمولاً اصلاً /dev/rtc وجود ندارد، بنابراین hwclock --show با خطای hwclock: Cannot access the Hardware Clock via any known method. مواجه می‌شود.

منبع ساعت (clocksource) چیزی است که هسته با آن فواصل بین آن خواندن‌ها را می‌شمارد. از هسته خود بپرسید کدام یک را انتخاب کرده است:

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

در KVM معمولاً kvm-clock را خواهید دید. این منبع مقداری را می‌خواند که توسط میزبان نگهداری می‌شود و به همین دلیل است که یک guest در KVM حتی بدون کلاینت NTP، همچنان تا مدتی تقریباً دقیق باقی می‌ماند. tsc شمارنده خودِ CPU است. guestهای Xen مقدار xen و guestهای Hyper-V منبع hyperv را گزارش می‌دهند. این تنظیمات را تغییر ندهید مگر اینکه دلیل اندازه‌گیری‌شده‌ای برای آن داشته باشید، زیرا هسته از قبل بهترین منبعی را که به آن اعتماد دارد، روی آن سخت‌افزار انتخاب کرده است.

برخی از میزبان‌ها یک دستگاه PTP (پروتکل زمان دقیق) را نیز در اختیار guest قرار می‌دهند که به 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 پرچم (flag) خودِ کرنل است. یک دیمون زمان (time daemon) زمانی این پرچم را تنظیم می‌کند که به منابع خود اعتماد داشته باشد، بنابراین 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 آفست (offset) فعلی از زمان NTP است که با کلمهٔ fast یا slow دنبال می‌شود. Last offset اندازهٔ آخرین اصلاح انجام‌شده است. Frequency خطای نرخ (rate error) است که chrony در ساعت شما اندازه‌گیری کرده و در حال جبران آن است. Leap status باید Normal را نشان دهد. اگر Not synchronised را نشان می‌دهد و Reference ID برابر با 00000000 () است، یعنی chrony هنوز منبعی را برای همگام‌سازی انتخاب نکرده است.

chronyc sources -v راهنمای علائم را بالای لیست چاپ می‌کند تا نیازی به حفظ کردن آن‌ها نداشته باشید. دو ستون بیشترین معنا را در بر دارند. کاراکتر وضعیت در ابتدای هر خط نشان می‌دهد که chrony چگونه آن منبع را ارزیابی می‌کند؛ جایی که * منبعی را که در حال حاضر استفاده می‌شود مشخص می‌کند و ? در هر خط به این معنی است که هیچ پاسخی دریافت نمی‌شود. Reach تاریخچهٔ پاسخ‌های هشت پرس‌وجوی (poll) آخر است که به صورت اکتال چاپ می‌شود: 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 است و به دلایلی که در خروجی آن مشاهده می‌کنید، گزینه پیش‌فرض بهتری برای ماشین‌های مجازی (VM) محسوب می‌شود. این ابزار هم‌زمان از چندین منبع پرس‌وجو می‌کند و منابعی که با بقیه همخوانی ندارند را کنار می‌گذارد. chrony خطای نرخ ساعت شما را اندازه‌گیری کرده و آن را در یک فایل drift می‌نویسد؛ بنابراین به‌جای دنبال کردن تک‌تک نمونه‌ها، تمایل ذاتی ساعت به خطا را اصلاح می‌کند. این ابزار همچنین به‌سرعت با دو وضعیتی که ماشین‌های مجازی تجربه می‌کنند اما سرورهای فیزیکی خیر، سازگار می‌شود: ماشین مجازی ممکن است توسط میزبان (host) متوقف (pause) شود یا در حین اجرا به یک میزبان دیگر منتقل شود. وقتی یک دستگاه 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 هنگام نصب chrony، ابزار timesyncd را حذف می‌کند. این رفتار صحیح و مورد انتظار است. هرگز هر دو را هم‌زمان اجرا نکنید، زیرا دو daemon که سعی در تنظیم یک ساعت واحد دارند با هم تداخل پیدا می‌کنند و در این حالت، هیچ‌کدام از offsetهای گزارش‌شده قابل اعتماد نیستند. در Rocky و AlmaLinux، نصب را با sudo dnf install -y chrony انجام دهید، که در آن نام unit به‌جای chrony، برابر با chronyd است.

فایل پیکربندی در Debian و Ubuntu برابر با /etc/chrony/chrony.conf و در Rocky و Alma برابر با /etc/chrony.conf است. تنظیمات پیش‌فرض توزیع برای یک VPS کاملاً معقول است، بنابراین تنها در صورت نیاز آن را تغییر دهید. درک دو دستورالعمل زیر مفید است:

  • خطوط pool و server نام منابع زمانی را مشخص می‌کنند. افزودن iburst به chrony دستور می‌دهد که در هنگام راه‌اندازی یک burst سریع ارسال کند تا اولین همگام‌سازی به‌جای چند دقیقه، در چند ثانیه انجام شود.
  • دستور makestep تعیین می‌کند که chrony چه زمانی ساعت را به‌جای اصلاح تدریجی، یکباره پرش دهد (step). با دستور grep -n makestep /etc/chrony/chrony.conf بررسی کنید تنظیمات شما چیست. مقدار پیش‌فرض در Debian و Ubuntu یعنی makestep 1 3 به این معناست: در طول سه به‌روزرسانی اول پس از شروع chronyd، اگر اختلاف ساعت بیش از یک ثانیه باشد، ساعت را یکباره تنظیم کن (step) و پس از آن، فقط از طریق اصلاح تدریجی (slew) عمل کن.

اگر می‌خواهید ترافیک زمانی در برابر دستکاری در مسیر احراز هویت شود، chrony نسخه 4 و بالاتر از NTS (امنیت زمان شبکه) پشتیبانی می‌کند. ابتدا نسخه خود را با chronyd -v تأیید کنید و توجه داشته باشید که NTS علاوه بر پورت UDP 123، به باز بودن پورت خروجی TCP 4460 نیز نیاز دارد:

server time.cloudflare.com iburst nts

پیش از اعتماد به آن، سرویس را restart کرده و وضعیت را بررسی کنید. پیکربندی که در تجزیه (parse) دچار خطا شود، شما را بدون هیچ daemon زمانی رها می‌کند و ساعت سیستم نیز این موضوع را به شما اطلاع نخواهد داد.

sudo systemctl restart chrony
chronyc sources -v
chronyc tracking

چرا ساعتی که دقایقی عقب یا جلو است، همان‌طور باقی می‌ماند

یک دیمون زمان (time daemon) برای اصلاح اختلاف زمان، دو روش دارد. روش Slewing سرعت ساعت را کم یا زیاد می‌کند تا خطا به‌تدریج برطرف شود؛ در این حالت زمان همواره رو به جلو حرکت می‌کند و هیچ timestamp تکراری یا حذف‌شده‌ای ایجاد نمی‌شود. روش Stepping مستقیماً به مقدار صحیح می‌پرد که سریع است اما می‌تواند ساعت را به عقب برگرداند. عقب کشیدن ساعت برای هر فرآیندی که زمان سپری‌شده را بر اساس ساعت دیواری (wall clock) اندازه‌گیری می‌کند خطرناک است، بنابراین هر دو دیمون ترجیح می‌دهند از روش Slewing استفاده کنند.

همین اولویت باعث می‌شود ساعتی که خطای زیادی دارد، برای مدتی طولانی نادرست باقی بماند. برنامه chrony فقط در بازه زمانی که makestep اجازه می‌دهد، از روش Stepping استفاده می‌کند که به‌طور پیش‌فرض شامل چند به‌روزرسانی اول پس از شروع به کار دیمون است. اگر chronyd یک هفته در حال اجرا باشد و سپس متوجه خطای چهل ثانیه‌ای شود، آن را با Slewing اصلاح می‌کند و اصلاح چهل ثانیه با این روش، بسیار طولانی‌تر از آن است که بخواهید منتظر بمانید. آن را یک‌بار، آگاهانه و در لحظه‌ای خلوت، به‌صورت دستی اعمال کنید:

sudo chronyc makestep
chronyc tracking

اکنون chronyc tracking باید یک System time با اختلاف نزدیک به صفر گزارش کند و Last offset باید اندازه مقداری که به‌تازگی اصلاح شده است را نشان دهد. پیش از اجرای این دستور روی یک میزبان دیتابیس پرمشغله فکر کنید، زیرا ساعتی که به عقب می‌پرد می‌تواند نرم‌افزارهایی را که فرض کرده‌اند زمان فقط رو به جلو حرکت می‌کند، دچار اختلال کند. راه‌اندازی مجدد (Restart) دیمون، نسخه ملایم‌تری از همین اصلاح است، زیرا بازه زمانی makestep دوباره در لحظه شروع به کار باز می‌شود.

کانتینرها از ساعت میزبان استفاده می‌کنند

یک کانتینر ساعت دیواری مستقل ندارد، بنابراین چیزی برای همگام‌سازی در داخل آن وجود ندارد. فضای نام زمان (time namespaces) در لینوکس فقط ساعت‌های monotonic و boot-time را مجازی‌سازی می‌کند. CLOCK_REALTIME مجازی‌سازی نمی‌شود، به این معنی که کانتینر همان ساعت سیستمی را می‌خواند که میزبانِ در حال اجرای آن استفاده می‌کند. ساعت را روی میزبان اصلاح کنید تا تمام کانتینرهای موجود روی آن میزبان در همان لحظه اصلاح شوند.

این موضوع پیامدهایی به همراه دارد. از نصب chrony یا ntpd در یک image خودداری کنید، زیرا در بهترین حالت هیچ کاری انجام نمی‌دهند. تنظیم تاریخ در یک کانتینر بدون امتیاز (unprivileged) با خطای date: cannot set date: Operation not permitted مواجه می‌شود، زیرا هسته برای این فراخوانی به CAP_SYS_TIME نیاز دارد. اعطای CAP_SYS_TIME به کانتینر یک ساعت اختصاصی نمی‌دهد، بلکه به کانتینر توانایی تغییر ساعت میزبان و در نتیجه تغییر ساعت تمام کانتینرهای دیگر را می‌دهد.

تفاوت منطقه زمانی (time zone) در داخل کانتینر یک مشکل مربوط به ساعت نیست. یک image که /etc/localtime خاص خود را دارد، همان لحظه را با فرمت منطقه دیگری نمایش می‌دهد، بنابراین date اشتباه به نظر می‌رسد در حالی که ساعت درست است. متغیر TZ=UTC را در محیط کانتینر تنظیم کنید تا این ابهام برطرف شود. runtime انتخابی شما در اینجا تغییری ایجاد نمی‌کند و مقایسه Podman و Docker بدون دسترسی root مواردی را که تغییر می‌دهد، پوشش می‌دهد.

مناطق زمانی: UTC روی سرور، زمان محلی برای کاربران

ماشین را روی UTC تنظیم کنید و آن را تغییر ندهید.

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

زمان UTC تغییر ساعت تابستانی (daylight saving) ندارد و همین موضوع، کل استدلال برای استفاده از آن است. یک وظیفه روزانه در ساعت 02:30 در منطقه‌ای که ساعت تابستانی را رعایت می‌کند، در روزی که ساعت‌ها به عقب کشیده می‌شوند دو بار اجرا می‌شود و در روزی که ساعت‌ها به جلو کشیده می‌شوند، اصلاً اجرا نمی‌شود. man 8 cron نحوه مدیریت ویژه برای تغییرات کمتر از سه ساعت را مستند کرده است: وظایفی که به دلیل پرش به جلو نادیده گرفته شده‌اند، بلافاصله پس از تغییر اجرا می‌شوند و وظایفی که در یک ساعت تکراری ناشی از پرش به عقب قرار می‌گیرند، برای بار دوم اجرا نمی‌شوند. این رفتار منطقی است، اما همچنان رفتاری است که نباید در ساعت 03:00 نگران آن باشید. تحت UTC، وظیفه شما در هر روز از سال، دقیقاً یک بار اجرا می‌شود. اگر وظیفه شما به جای اجرا در یک ساعت عجیب، به‌طور کامل اجرا نمی‌شود، دلایل اجرا نشدن بی‌سروصدای یک cron job توضیح محتمل‌تری است.

همین استدلال برای خواندن لاگ‌ها نیز صدق می‌کند. journalctl مُهرهای زمانی (timestamps) را در منطقه زمانی سیستم فرمت می‌کند و journalctl --utc آن را مجبور به استفاده از UTC می‌کند. وجود دو سرور در دو منطقه زمانی مختلف، هر حادثه را به یک تمرین تبدیل واحد تبدیل می‌کند و تبدیل‌هایی که تحت فشار انجام می‌شوند، همان جایی هستند که افراد خط زمانی را اشتباه می‌خوانند. سیستم‌ها را روی UTC نگه دارید، مُهرهای زمانی را در UTC ذخیره کنید و تبدیل را فقط در نقطه‌ای انجام دهید که یک انسان آن‌ها را می‌خواند. هر کسی که برای یک دستور خاص نیاز به خواندن زمان محلی دارد، می‌تواند بدون تغییر دادن تنظیمات ماشین، آن را درخواست کند:

TZ=Europe/Berlin date

یک خط دیگر در خروجی timedatectl به این بخش مربوط می‌شود. RTC in local TZ باید no باشد. تنظیم آن روی yes یک راهکار موقت برای سیستم‌های dual-boot با ویندوز روی لپ‌تاپ است و روی سرور، فقط یک اختلاف زمانی (offset) اضافه می‌کند که بعداً باعث دردسر می‌شود. وقتی این گزینه تنظیم شده باشد، timedatectl هشداری چاپ می‌کند مبنی بر اینکه سیستم برای خواندن زمان RTC در منطقه زمانی محلی پیکربندی شده است.

عیب‌یابی بر اساس علائم

کد احراز هویت دو مرحله‌ای شما در یک سرور رد می‌شود. پیش از هر اقدامی، ساعت سیستم را بررسی کنید. این کد از شمارنده‌ای تولید می‌شود که هر 30 ثانیه تغییر می‌کند؛ بنابراین اگر ساعت سرور 90 ثانیه عقب باشد، کدی را محاسبه می‌کند که گوشی شما قبلاً از آن عبور کرده است. timedatectl مقدار System clock synchronized: no را نشان می‌دهد یا chronyc tracking یک System time بزرگ را گزارش می‌کند. این خطا با رد شدن کلید (key) که پیام خاص خود را دارد و در راهنمای خطاهای احراز هویت publickey پوشش داده شده، متفاوت است.

apt update می‌گوید فایل Release هنوز معتبر نیست. پیام کامل، نام مخزن و مدت زمانی که تا معتبر شدن باقی مانده را ذکر می‌کند، برای مثال is not valid yet (invalid for another 1d 2h 3min 4s). ساعت شما از تاریخی که در فایل Release مخزن درج شده عقب‌تر است و آن مدت زمان، دقیقاً نشان‌دهنده میزان عقب بودن ساعت است. ساعت را اصلاح کنید. بررسی تاریخ در apt را غیرفعال نکنید، زیرا این بررسی مانع از آن می‌شود که شخصی فهرست بسته‌های قدیمی (stale) را به شما ارائه دهد.

تمام خطوط منبع وضعیت unreachable را نشان می‌دهند و Reach برابر 0 است. هیچ پاسخی دریافت نمی‌شود، بنابراین به‌جای پیکربندی، ترافیک خروجی (egress) را بررسی کنید. NTP از پورت UDP 123 برای خروجی استفاده می‌کند و برخی شبکه‌ها آن را فیلتر یا هدایت مجدد می‌کنند. sudo chronyc ntpdata شمارنده‌های هر منبع از جمله Total TX و Total RX را چاپ می‌کند. افزایش تعداد TX در حالی که RX روی صفر باقی مانده است، به این معنی است که بسته‌های شما خارج می‌شوند اما پاسخی دریافت نمی‌شود؛ این موضوع نشان‌دهنده وجود یک فایروال بین شما و منبع است.

ساعت درست بود، اما ناگهان تغییر کرد. رویدادهای میزبان (host) باعث این اتفاق می‌شوند. بازیابی یک snapshot، متوقف کردن یک guest یا مهاجرت زنده (live migration) به یک میزبان دیگر می‌تواند باعث عقب ماندن زمان guest از زمان واقعی شود. chrony در polling بعدی متوجه این موضوع شده و آن را اصلاح می‌کند؛ اما systemd-timesyncd ممکن است ابتدا منتظر بماند تا بازه طولانی polling تمام شود. با استفاده از systemctl is-enabled chrony تأیید کنید که دیمون در زمان بوت شروع می‌شود، زیرا دیمونی که به‌صورت دستی اجرا شده باشد، پس از reboot بعدی از بین می‌رود.

اختلاف زمان (offset) کم است اما هرگز ثابت نمی‌شود. CPU steal را بررسی کنید. guestای که در زمان سررسید وقفه تایمر (timer interrupt) زمان‌بندی نشده باشد، نمونه‌برداری‌هایش با تأخیر مواجه می‌شود و در نتیجه، offset به‌جای همگرا شدن، نوسان می‌کند. top این مورد را به عنوان مقدار st در خط CPU نشان می‌دهد. خواندن زمان CPU steal در یک میزبان اشتراکی توضیح می‌دهد که این عدد به چه معناست و چه کاری می‌توانید در مورد آن انجام دهید.

گواهی‌نامه‌ای که به‌تازگی صادر کرده‌اید به دلیل معتبر نبودن رد می‌شود. curl مقدار SSL certificate problem: certificate is not yet valid را چاپ می‌کند و مرورگرها نیز پیام مشابهی می‌دهند. گواهی‌نامه مشکلی ندارد؛ ساعتی که آن را بررسی می‌کند عقب است. هر کدام از دو دستگاه می‌توانند مقصر باشند، بنابراین هم کلاینت و هم سرور را بررسی کنید. اگر سروری که گواهی را صادر کرده ساعت اشتباهی دارد، راهنمای گواهی‌نامه certbot و nginx بخش تمدید در همین تنظیمات را پوشش می‌دهد.

آن را به بررسی‌های جاری خود اضافه کنید

همگام‌سازی زمان، تنظیمی مربوط به زمان بوت است که ممکن است ماه‌ها بعد بدون هیچ هشداری از کار بیفتد؛ این دقیقاً همان موردی است که یک روال بررسی (routine) آن را شناسایی می‌کند، اما حافظه انسان از آن غافل می‌ماند. خواندن timedatectl و chronyc tracking با هم، تنها دو ثانیه زمان می‌برد. آن‌ها را به عنوان بخشی از ده دقیقه اول کار با یک VPS جدید اجرا کنید و هنگام انجام چک‌لیست منظم نگهداری سرور لینوکس نیز دوباره آن‌ها را به کار بگیرید. اگر ترجیح می‌دهید این بررسی به‌صورت خودکار انجام شود و در صورت افزایش اختلاف زمانی (offset) به شما هشدار دهد، نوشتن یک سرویس و تایمر systemd الگوی لازم برای ایجاد یک واحد کوچک جهت گزارش‌دهی زمان‌بندی‌شده را توضیح می‌دهد.

FAQ

چگونه بررسی کنم که ساعت VPS من همگام است؟

دستور timedatectl را اجرا کنید و خط System clock synchronized را بخوانید. این خط نشان‌دهنده پرچم داخلی کرنل است که توسط دیمونی که وظیفه تنظیم ساعت را بر عهده دارد، مقداردهی می‌شود؛ بنابراین مشاهده yes در کنار NTP service: n/a در سیستمی که از chrony استفاده می‌کند، عادی و نشانه سلامت است. برای مشاهده میزان خطا، دستور chronyc tracking را اجرا کرده و System time را بررسی کنید، یا اگر systemd-timesyncd مسئولیت زمان را بر عهده دارد، دستور timedatectl timesync-status را اجرا کرده و Offset را بخوانید. برای بررسی ساعت در مقایسه با یک منبع خارجی، مقدار date -u را با هدر Date که از هر سایت HTTPS دریافت می‌شود، مقایسه کنید.

آیا باید از chrony استفاده کنم یا systemd-timesyncd روی VPS؟

برای هر سرور مهمی از chrony استفاده کنید. ابزار systemd-timesyncd یک کلاینت SNTP است که تنها از یک سرور پیروی می‌کند و برای ماشینی که همیشه آنلاین است و از ابتدا زمان نسبتاً دقیقی دارد، مناسب است. ابزار chrony چندین منبع را بررسی می‌کند، منابع نامعتبر را حذف می‌کند، خطای نرخ ساعت شما را یاد می‌گیرد و پس از توقف میزبان (host pause) یا مهاجرت زنده (live migration) به‌سرعت بازیابی می‌شود. نصب chrony روی Debian یا Ubuntu به‌طور خودکار systemd-timesyncd را حذف می‌کند، زیرا هر دو بسته time-daemon را ارائه می‌دهند. هرگز دو دیمون زمان را هم‌زمان اجرا نکنید.

چرا کدهای TOTP من روی یک سرور کار نمی‌کنند اما در جاهای دیگر درست هستند؟

زیرا کد TOTP تابعی از زمان فعلی است. این کد از شمارنده‌ای می‌آید که هر 30 ثانیه تغییر می‌کند، بنابراین سرور و گوشی شما باید روی گام زمانی فعلی توافق داشته باشند. اکثر تأییدکننده‌ها یک گام اختلاف را در هر دو جهت می‌پذیرند که حدود نیم دقیقه فرصت خطا می‌دهد. دستور timedatectl را روی آن سرور بررسی کنید. اگر System clock synchronized مقدار no را نشان می‌دهد، همگام‌سازی را اصلاح کنید تا کدها بدون نیاز به تغییر در کلید مشترک (shared secret)، دوباره مطابقت پیدا کنند.

آیا می‌توانم زمان را داخل یک کانتینر Docker تنظیم کنم؟

خیر، و نیازی هم به این کار ندارید. کانتینر از CLOCK_REALTIME میزبان استفاده می‌کند، زیرا فضاهای نام زمانی (time namespaces) در لینوکس فقط ساعت‌های monotonic و boot-time را مجازی‌سازی می‌کنند. یک کانتینر بدون امتیاز (unprivileged) مقدار date: cannot set date: Operation not permitted را دریافت می‌کند و افزودن CAP_SYS_TIME به آن اجازه می‌دهد ساعت میزبان را تغییر دهد، نه اینکه ساعت مستقلی داشته باشد. میزبان را همگام‌سازی کنید. تفاوت زمان محلی داخل کانتینر مربوط به تنظیمات منطقه زمانی است، بنابراین TZ را در محیط کانتینر تنظیم کنید.

آیا سرور باید از UTC استفاده کند یا زمان محلی؟

از UTC استفاده کنید و زمان محلی را تنها در لحظه خواندن خروجی توسط کاربر اعمال کنید. UTC هرگز برای تغییرات ساعت تابستانی (daylight saving) تغییر نمی‌کند، بنابراین یک وظیفه روزانه (daily job) در تمام طول سال دقیقاً یک بار در روز اجرا می‌شود و برچسب‌های زمانی (timestamps) از سرورهای مختلف بدون نیاز به تبدیل، با هم هماهنگ هستند. آن را با sudo timedatectl set-timezone UTC تنظیم کنید. هر کسی که نیاز به مشاهده زمان محلی دارد می‌تواند یک دستور ساده مانند TZ=America/New_York date را پیش از دستور اصلی قرار دهد که هیچ تغییری در ساعت سیستم ایجاد نمی‌کند.