SSD Nodes Learn Hosting plans →
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-08-28

วิธีแก้ปัญหานาฬิกา VPS ไม่ตรงและตั้งค่าเวลาให้แม่นยำ

สาเหตุที่นาฬิกาบน VPS คลาดเคลื่อนจนทำให้ระบบยืนยันตัวตน TOTP ล้มเหลว เรียนรู้วิธีตรวจสอบค่าผ่านคำสั่ง chronyc และ timedatectl เพื่อซิงค์เวลาให้ตรงกับมาตรฐานสากลอีกครั้ง

เหตุใดนาฬิกาของ VPS จึงคลาดเคลื่อน

นาฬิกาของ VPS คลาดเคลื่อนเนื่องจากไม่มีกระบวนการปรับเทียบเวลา Kernel จะนับเวลาจากตัวนับฮาร์ดแวร์ซึ่งทำงานเร็วหรือช้ากว่าปกติเล็กน้อย และเมื่อไม่มีไคลเอนต์สำหรับซิงค์เวลาทำงานอยู่ ข้อผิดพลาดเล็กน้อยนั้นจะสะสมเพิ่มขึ้นทุกชั่วโมง ภายในเครื่องเสมือน (virtual machine) ยังมีสาเหตุประการที่สองคือ Guest ของคุณต้องใช้ CPU ร่วมกับ Guest อื่นๆ ดังนั้นช่วงเวลาที่ Guest ไม่ถูกจัดตารางการทำงาน (scheduled) จึงเป็นช่วงเวลาที่มันไม่สามารถนับเวลาได้

บน KVM guest ในปัจจุบัน ตัวนับเวลาเองมักไม่ใช่ปัญหาหลัก แหล่งข้อมูล kvm-clock แบบ paravirtual จะอ่านค่าที่ Host เป็นผู้ดูแล ดังนั้น Guest ที่ทำงานปกติจะติดตามเวลาของ Host ได้อย่างใกล้ชิด นาฬิกาที่แสดงเวลาผิดพลาดอย่างเห็นได้ชัดมักเกิดจากสาเหตุที่เรียบง่ายกว่านั้น เช่น ไม่มี daemon สำหรับซิงค์เวลาทำงานอยู่, มี daemon สองตัวทำงานทับซ้อนกัน หรือพอร์ต UDP 123 สำหรับขาออกถูกบล็อกไม่ให้ออกจากเครือข่ายของผู้ให้บริการ Guest จะรับการควบคุมเวลาจาก Host หรือจาก NTP (network time protocol) ไม่ใช่จาก oscillator ของตัวมันเอง

ผลกระทบที่แท้จริงเมื่อนาฬิกาของระบบไม่ตรง

  • รหัสผ่านชั้นที่สองแบบ TOTP (time-based one-time password) จะไม่ตรงกัน ทำให้คุณไม่สามารถเข้าสู่เซิร์ฟเวอร์ได้แม้ว่ารหัสผ่านและคีย์จะถูกต้องก็ตาม
  • ใบรับรองที่เพิ่งออกเมื่อนาทีก่อนหน้าจะถูกปฏิเสธ และ curl จะแสดงข้อความ SSL certificate problem: certificate is not yet valid
  • apt update จะปฏิเสธ repository ด้วยข้อความ E: Release file for ... is not valid yet (invalid for another 1d 2h 3min 4s)
  • งานที่ตั้งเวลาไว้จะทำงานผิดเวลา และนาฬิกาที่กระโดดอาจทำให้งานหนึ่งรันซ้ำสองครั้งในขณะที่อีกงานถูกข้ามไป
  • log จากเซิร์ฟเวอร์สองเครื่องไม่สามารถนำมาเรียงลำดับกันได้ ทำให้การสร้างไทม์ไลน์ของเหตุการณ์ต้องอาศัยการคาดเดา

ค่าความคลาดเคลื่อนที่ยอมรับได้นั้นน้อยกว่าที่คนส่วนใหญ่คาดคิด ตัวเลขด้านล่างนี้เป็นค่าเริ่มต้นตามเอกสาร ไม่ใช่ค่าที่ได้จากการทดสอบ

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 โดยถูกเก็บไว้ในหน่วยความจำและถูกอ่านโดยทุกกระบวนการที่ต้องการประทับเวลา ไม่ว่าจะเป็นบรรทัดใน log, การตรวจสอบ certificate, รหัส TOTP หรือเวลาแก้ไขไฟล์ ทั้งหมดล้วนอ้างอิงจากนาฬิกานี้ เมื่อมีคนกล่าวว่าเวลาของเซิร์ฟเวอร์ไม่ถูกต้อง นี่คือนาฬิกาที่พวกเขาหมายถึง

Hardware clock หรือที่เรียกว่า RTC (real time clock) คือตัวนับแยกต่างหากที่ยังคงทำงานอยู่แม้ในขณะที่เครื่องปิดอยู่ ในเครื่องเซิร์ฟเวอร์จริง มันคือชิปที่มีแบตเตอรี่สำรอง ในขณะที่เครื่องเสมือน (guest) มันจะถูกจำลองโดย hypervisor จึงถือเป็นส่วนประกอบของโฮสต์เป็นหลัก Linux จะอ่านค่าจากส่วนนี้เพียงครั้งเดียวตอนบูตเพื่อใช้เป็นค่าเริ่มต้น จากนั้นจะนับเวลาด้วยตัวเอง timedatectl จะแสดงค่านี้ในบรรทัด RTC time อย่าใช้บรรทัดนี้ในการดีบั๊กบน VPS เพราะมันบอกถึงเวลาในมุมมองของโฮสต์ ไม่ใช่สถานะการซิงค์ของ system clock ของคุณ ส่วนใน container มักจะไม่มี /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 client ก็ยังคงรักษาเวลาได้ค่อนข้างแม่นยำในระยะหนึ่ง ส่วน tsc คือตัวนับของ CPU เอง สำหรับ Xen guest จะรายงานเป็น xen และ Hyper-V guest จะรายงานเป็นแหล่งที่มา hyperv อย่าแก้ไขการตั้งค่านี้เว้นแต่คุณจะมีเหตุผลที่วัดผลได้ เพราะเคอร์เนลได้เลือกแหล่งที่มาที่ดีที่สุดที่เชื่อถือได้สำหรับฮาร์ดแวร์นั้นๆ ไว้แล้ว

โฮสต์บางแห่งอาจส่งอุปกรณ์ PTP (precision time protocol) มาให้ guest ซึ่งช่วยให้ chrony สามารถอ่านเวลาจากโฮสต์ได้โดยตรงแทนที่จะผ่านเครือข่าย ควรตรวจสอบดู ซึ่งมักจะไม่สามารถใช้งานได้บน VPS แบบแชร์:

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

หาก modprobe ล้มเหลวหรือไม่พบอุปกรณ์ แสดงว่าโฮสต์ของคุณไม่มีบริการนี้ และการใช้ NTP ผ่านเครือข่ายคือคำตอบของคุณ หาก clock_name ระบุว่าเป็น KVM virtual clock คุณสามารถให้ chrony ใช้งานได้โดยเพิ่มบรรทัด refclock PHC /dev/ptp0 poll 2 ลงในไฟล์ config ของมัน

การอ่านสถานะเวลาบนเครื่องของคุณ

เริ่มต้นด้วยคำสั่งเดียว คำสั่งนี้จะตอบคำถามว่า "มีสิ่งใดคอยปรับเวลาให้ถูกต้องอยู่หรือไม่" ได้ภายในหน้าจอเดียว

timedatectl

ให้อ่านบรรทัดเหล่านี้แทนการเชื่อตัวเลขที่คุณจำได้:

  • Local time และ Universal time คือช่วงเวลาเดียวกันที่แสดงในเขตเวลาของคุณและในรูปแบบ UTC หากทั้งสองค่าเหมือนกัน แสดงว่าเครื่องตั้งค่าเป็น UTC อยู่แล้ว
  • RTC time คือนาฬิกาฮาร์ดแวร์ที่อธิบายไว้ข้างต้น สำหรับ VPS ให้ละเว้นค่านี้
  • Time zone คือสิ่งที่ระบบใช้สำหรับจัดรูปแบบเวลาท้องถิ่น
  • System clock synchronized คือแฟล็กของเคอร์เนลเอง โดย 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 คือค่าความคลาดเคลื่อนปัจจุบันจากเวลา NTP ตามด้วยคำว่า fast หรือ slow Last offset คือขนาดของการแก้ไขล่าสุด Frequency คืออัตราความผิดพลาดที่ chrony วัดได้จากนาฬิกาของคุณและกำลังชดเชยให้อยู่ Leap status ควรแสดงค่า Normal หากแสดงค่า Not synchronised และ Reference ID เป็น 00000000 () แสดงว่า chrony ยังไม่ได้เลือกแหล่งข้อมูลเวลาที่แน่นอน

chronyc sources -v จะพิมพ์คำอธิบายสัญลักษณ์ไว้เหนือรายการ เพื่อที่คุณจะได้ไม่ต้องจำสัญลักษณ์เหล่านั้น สองคอลัมน์แรกมีความหมายสำคัญที่สุด ตัวอักษรสถานะที่จุดเริ่มต้นของแต่ละบรรทัดคือวิธีที่ chrony ประเมินแหล่งข้อมูลนั้น โดย * ระบุแหล่งข้อมูลที่กำลังใช้งานอยู่ และ ? ในทุกบรรทัดหมายความว่าไม่มีการตอบกลับ Reach คือประวัติการตอบกลับของการสำรวจ 8 ครั้งล่าสุดในรูปแบบเลขฐานแปด: 377 หมายความว่าตอบกลับครบทั้ง 8 ครั้ง และ 0 หมายความว่าไม่มีการตอบกลับเลย

หาก systemd-timesyncd เป็นผู้ดูแลแทน:

timedatectl timesync-status
timedatectl show-timesync --all

timesync-status จะแสดงเซิร์ฟเวอร์ที่กำลังติดต่ออยู่ ช่วงเวลาการสำรวจ และค่า Offset หากคำสั่งส่งคืนข้อผิดพลาดเกี่ยวกับ service แทนที่จะแสดงสถานะ แสดงว่า timesyncd ไม่ใช่ daemon ที่ดูแลเครื่องนี้ ซึ่งนั่นก็เป็นคำตอบสำหรับคำถามของคุณแล้ว

สำหรับการตรวจสอบคร่าวๆ กับโลกภายนอกโดยไม่ต้องใช้เครื่องมือเพิ่มเติม ให้เปรียบเทียบนาฬิกาของคุณกับ HTTP Date header สาธารณะ ซึ่งจะแสดงผลในรูปแบบ GMT ที่มีความละเอียดระดับหนึ่งวินาที:

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

ความแตกต่างระดับหนึ่งหรือสองวินาทีในกรณีนี้ถือเป็นเรื่องปกติและไม่มีนัยสำคัญ แต่หากแตกต่างกันถึงหนึ่งนาที แสดงว่านั่นคือบั๊กของคุณ

การเลือกใช้ chrony หรือ systemd-timesyncd บน VPS

Ubuntu และ Debian ติดตั้ง systemd-timesyncd มาให้เป็นค่าเริ่มต้น ซึ่งเป็นไคลเอนต์ SNTP (simple network time protocol) ที่จะสอบถามเซิร์ฟเวอร์ทีละแห่งและปรับเวลาให้ตรงกัน สำหรับเครื่องที่ออนไลน์อยู่ตลอดและมีเวลาเริ่มต้นที่ค่อนข้างแม่นยำอยู่แล้ว วิธีนี้ถือว่าเพียงพอและใช้ทรัพยากรน้อยมาก

chrony เป็นการใช้งาน NTP แบบเต็มรูปแบบและเป็นตัวเลือกเริ่มต้นที่ดีกว่าสำหรับเครื่องเสมือน (VM) เนื่องจากเหตุผลที่คุณสามารถสังเกตได้จากผลลัพธ์การทำงานของมัน chrony จะสอบถามแหล่งเวลาหลายแห่งพร้อมกันและคัดแหล่งที่ให้ข้อมูลไม่ตรงกันออกไป นอกจากนี้ยังวัดค่าความคลาดเคลื่อนของนาฬิกาและบันทึกลงในไฟล์ drift ทำให้สามารถแก้ไขแนวโน้มความคลาดเคลื่อนของนาฬิกาได้โดยตรงแทนที่จะคอยไล่ปรับตามค่าที่ได้รับมาทีละครั้ง chrony ยังสามารถฟื้นตัวได้อย่างรวดเร็วจากเหตุการณ์สองอย่างที่ VM มักพบเจอแต่เครื่องเซิร์ฟเวอร์จริงไม่พบ คือการถูกหยุดการทำงาน (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 จะลบ 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 ค่าเริ่มต้นที่มากับ distribution นั้นเหมาะสมสำหรับ VPS อยู่แล้ว จึงควรเปลี่ยนก็ต่อเมื่อมีความจำเป็นเท่านั้น มีคำสั่งสองประเภทที่ควรทำความเข้าใจ:

  • บรรทัด pool และ server ใช้ระบุแหล่งที่มาของเวลา การเพิ่ม iburst จะสั่งให้ chrony ส่งสัญญาณ burst อย่างรวดเร็วเมื่อเริ่มทำงาน เพื่อให้การซิงค์ครั้งแรกเกิดขึ้นภายในไม่กี่วินาทีแทนที่จะเป็นนาที
  • makestep เป็นตัวกำหนดว่าเมื่อใดที่ chrony จะทำการกระโดดเวลา (jump) แทนการค่อยๆ ปรับ (slew) ตรวจสอบค่าของคุณด้วย grep -n makestep /etc/chrony/chrony.conf ค่าเริ่มต้นของ Debian และ Ubuntu คือ makestep 1 3 ซึ่งหมายความว่า: ในช่วงการอัปเดต 3 ครั้งแรกหลังจาก chronyd เริ่มทำงาน หากเวลาคลาดเคลื่อนเกิน 1 วินาที ให้ทำการปรับเวลาทันที (step) และหลังจากนั้นให้ใช้วิธีค่อยๆ ปรับ (slew) เท่านั้น

หากคุณต้องการให้ทราฟฟิกของเวลาได้รับการยืนยันความถูกต้องเพื่อป้องกันการแก้ไขระหว่างทาง chrony เวอร์ชัน 4 ขึ้นไปรองรับ NTS (network time security) ให้ตรวจสอบเวอร์ชันของคุณด้วย chronyd -v ก่อน และโปรดทราบว่า NTS จำเป็นต้องเปิดพอร์ต TCP ขาออกหมายเลข 4460 นอกเหนือจาก UDP 123:

server time.cloudflare.com iburst nts

รีสตาร์ทและตรวจสอบสถานะก่อนที่จะใช้งานจริง คอนฟิกูเรชันที่อ่านค่าไม่ผ่านจะทำให้คุณไม่มี time daemon ทำงานเลย และนาฬิกาจะไม่แจ้งเตือนคุณเกี่ยวกับเรื่องนี้

sudo systemctl restart chrony
chronyc sources -v
chronyc tracking

เหตุใดนาฬิกาที่เวลาคลาดเคลื่อนไปหลายนาทีจึงยังคงไม่ตรง

Time daemon มีสองวิธีในการแก้ไขเวลาที่คลาดเคลื่อน วิธี Slewing คือการเร่งหรือหน่วงเวลาของนาฬิกาจนกว่าค่าความคลาดเคลื่อนจะหมดไป ซึ่งช่วยให้เวลาเดินไปข้างหน้าอย่างต่อเนื่องโดยไม่มีการซ้ำหรือข้าม timestamp ส่วนวิธี Stepping คือการปรับเวลาให้ตรงทันที ซึ่งทำได้รวดเร็วแต่อาจทำให้เวลาถอยหลังได้ การที่เวลาถอยหลังเป็นอันตรายต่อกระบวนการใดก็ตามที่วัดระยะเวลาจากนาฬิกาจริง (wall clock) ดังนั้น daemon ทั้งสองประเภทจึงนิยมใช้วิธี slewing มากกว่า

ความนิยมในวิธีนี้เป็นเหตุผลว่าทำไมนาฬิกาที่เวลาผิดเพี้ยนไปมากจึงยังคงไม่ตรงเป็นเวลานาน chrony จะทำการ step เวลาเฉพาะในช่วงที่ makestep อนุญาตเท่านั้น ซึ่งโดยปกติจะเป็นช่วงการอัปเดตไม่กี่ครั้งแรกหลังจาก daemon เริ่มทำงาน หาก chronyd ทำงานมาแล้วหนึ่งสัปดาห์แล้วพบว่าเวลาคลาดเคลื่อนไป 40 วินาที มันจะใช้วิธี slewing ซึ่งการ slewing เวลา 40 วินาทีนั้นใช้เวลานานกว่าที่คุณต้องการรอ คุณควรบังคับให้มันปรับเวลาด้วยตนเองในช่วงเวลาที่มีการใช้งานน้อย:

sudo chronyc makestep
chronyc tracking

ตอนนี้ chronyc tracking ควรรายงานค่า System time ที่ใกล้ศูนย์ และ Last offset ควรแสดงขนาดของเวลาที่เพิ่งแก้ไขไป โปรดพิจารณาให้รอบคอบก่อนดำเนินการนี้บนโฮสต์ฐานข้อมูลที่มีการใช้งานสูง เพราะนาฬิกาที่กระโดดถอยหลังอาจทำให้ซอฟต์แวร์ที่ตั้งสมมติฐานว่าเวลาเดินไปข้างหน้าเพียงอย่างเดียวเกิดความสับสนได้ การรีสตาร์ท daemon เป็นวิธีแก้ไขที่นุ่มนวลกว่า เนื่องจากหน้าต่างเวลา makestep จะเปิดใช้งานอีกครั้งเมื่อเริ่มทำงานใหม่

คอนเทนเนอร์ใช้เวลาจากนาฬิกาของโฮสต์ร่วมกัน

คอนเทนเนอร์ไม่มีนาฬิกาเป็นของตัวเอง จึงไม่มีสิ่งใดให้ซิงค์ภายในนั้น Linux time namespaces ทำหน้าที่จำลองเฉพาะนาฬิกาแบบ monotonic และ boot-time เท่านั้น ส่วน CLOCK_REALTIME ไม่ได้ถูกจำลองขึ้นมา ซึ่งหมายความว่าคอนเทนเนอร์จะอ่านค่าจากนาฬิกาของระบบตัวเดียวกับโฮสต์ที่มันทำงานอยู่ หากแก้ไขเวลาบนโฮสต์ คอนเทนเนอร์ทุกตัวบนโฮสต์นั้นก็จะได้รับการแก้ไขเวลาไปพร้อมกันในทันที

ผลที่ตามมามีอยู่สองสามประการ อย่าติดตั้ง chrony หรือ ntpd ลงในอิมเมจ เพราะอย่างดีที่สุดมันก็ไม่ทำงานอะไรเลย การตั้งค่าวันที่ภายในคอนเทนเนอร์ที่ไม่มีสิทธิ์ (unprivileged container) จะล้มเหลวด้วย date: cannot set date: Operation not permitted เนื่องจากเคอร์เนลต้องการสิทธิ์ CAP_SYS_TIME สำหรับการเรียกใช้งานดังกล่าว การให้สิทธิ์ CAP_SYS_TIME ไม่ได้ทำให้คอนเทนเนอร์มีนาฬิกาส่วนตัว แต่เป็นการให้ความสามารถแก่คอนเทนเนอร์ในการเปลี่ยนนาฬิกาของโฮสต์ ซึ่งส่งผลให้นาฬิกาของคอนเทนเนอร์ตัวอื่นทั้งหมดเปลี่ยนตามไปด้วย

การมีเขตเวลา (time zone) ที่แตกต่างกันภายในคอนเทนเนอร์ไม่ใช่ปัญหาเรื่องนาฬิกา อิมเมจที่มีไฟล์ /etc/localtime ของตัวเองจะแสดงเวลาขณะเดียวกันในรูปแบบของเขตเวลาอื่น ดังนั้น date จึงดูเหมือนผิดทั้งที่นาฬิกาถูกต้องแล้ว ให้ตั้งค่า TZ=UTC ในสภาพแวดล้อมของคอนเทนเนอร์แล้วความสับสนจะหมดไป รันไทม์ที่คุณเลือกไม่ได้เปลี่ยนแปลงสิ่งนี้ และ การเปรียบเทียบ Podman และ Docker แบบ rootless จะครอบคลุมถึงสิ่งที่รันไทม์เหล่านั้นเปลี่ยนแปลงจริง

เขตเวลา: UTC บนเซิร์ฟเวอร์ เวลาท้องถิ่นสำหรับผู้ใช้งาน

ตั้งค่าเครื่องให้เป็น UTC และคงไว้เช่นนั้น

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

UTC ไม่มีเรื่องการปรับเวลาตามฤดูกาล (daylight saving) และนั่นคือเหตุผลสำคัญทั้งหมด งานที่ตั้งเวลาไว้ตอน 02:30 ในเขตเวลาที่มีการปรับเวลาตามฤดูกาลจะทำงานสองครั้งในวันที่นาฬิกาหมุนถอยหลัง และจะไม่ทำงานเลยในวันที่นาฬิกาหมุนไปข้างหน้า man 8 cron ได้ระบุถึงการจัดการพิเศษสำหรับการปรับเวลาที่น้อยกว่า 3 ชั่วโมงไว้ว่า งานที่ถูกข้ามไปจากการปรับเวลาไปข้างหน้าจะถูกเรียกทำงานทันทีหลังจากนั้น และงานที่อยู่ในช่วงเวลาที่ซ้ำกันจากการปรับเวลาถอยหลังจะไม่ถูกเรียกทำงานซ้ำ พฤติกรรมดังกล่าวถือว่าสมเหตุสมผล แต่ก็ยังเป็นสิ่งที่คุณไม่ควรต้องมานั่งกังวลในช่วงเวลา 03:00 น. ภายใต้ UTC งานจะทำงานวันละครั้ง ทุกวันตลอดทั้งปี หากงานของคุณหายไปเลยแทนที่จะทำงานในเวลาที่ผิดปกติ สาเหตุที่ cron job ไม่ทำงานโดยไม่มีการแจ้งเตือน คือคำอธิบายที่เป็นไปได้มากกว่า

เหตุผลเดียวกันนี้ใช้กับการอ่าน log เช่นกัน journalctl จะจัดรูปแบบ timestamp ตามเขตเวลาของระบบ และ journalctl --utc จะบังคับให้เป็น UTC เซิร์ฟเวอร์สองเครื่องที่อยู่คนละเขตเวลาจะทำให้ทุกเหตุการณ์กลายเป็นการแปลงเวลา และการแปลงเวลาภายใต้สถานการณ์กดดันคือสาเหตุที่ทำให้คนอ่านลำดับเวลาผิดพลาด ให้คงระบบไว้ที่ UTC จัดเก็บ timestamp เป็น UTC และแปลงเวลาเพียงครั้งเดียวที่จุดที่มนุษย์อ่านข้อมูล หากใครต้องการอ่านเวลาท้องถิ่นสำหรับคำสั่งใดคำสั่งหนึ่ง ก็สามารถเรียกดูได้โดยไม่ต้องเปลี่ยนการตั้งค่าของเครื่อง:

TZ=Europe/Berlin date

อีกหนึ่งบรรทัดในผลลัพธ์ของ timedatectl ที่เกี่ยวข้องกับส่วนนี้ RTC in local TZ ควรแสดงค่าเป็น no การตั้งค่าเป็น yes เป็นวิธีแก้ปัญหาชั่วคราวสำหรับการทำ dual-boot Windows บนแล็ปท็อป แต่บนเซิร์ฟเวอร์มันจะเพิ่มค่า offset ที่อาจทำให้เกิดปัญหาในภายหลัง เมื่อตั้งค่านี้ไว้ timedatectl จะแสดงคำเตือนว่าระบบถูกกำหนดค่าให้อ่านเวลา RTC ตามเขตเวลาท้องถิ่น

การแก้ไขปัญหาตามอาการ

รหัสยืนยันตัวตนสองชั้น (2FA) ถูกปฏิเสธบนเซิร์ฟเวอร์ ให้ตรวจสอบเวลาของระบบก่อนเริ่มดำเนินการอื่นใด รหัสนี้มาจากตัวนับที่เปลี่ยนทุก 30 วินาที ดังนั้นหากเซิร์ฟเวอร์เวลาช้าไป 90 วินาที ระบบจะคำนวณรหัสจากช่วงเวลาที่โทรศัพท์ของคุณผ่านไปแล้ว timedatectl จะแสดง System clock synchronized: no หรือ chronyc tracking จะรายงานค่า System time offset ที่สูง ความผิดพลาดนี้ต่างจากการที่คีย์ถูกปฏิเสธโดยตรง ซึ่งจะมีข้อความแจ้งเตือนเฉพาะและครอบคลุมอยู่ใน คู่มือการแก้ไขปัญหาการยืนยันตัวตนด้วย publickey

apt update แจ้งว่าไฟล์ Release ยังไม่ถูกต้อง ข้อความเต็มจะระบุชื่อ repository และระยะเวลาที่ไฟล์จะยังคงไม่ถูกต้อง เช่น is not valid yet (invalid for another 1d 2h 3min 4s) แสดงว่าเวลาของระบบคุณช้ากว่าวันที่ระบุไว้ในไฟล์ Release ของ repository นั้น และระยะเวลาที่แจ้งคือค่าที่วัดได้ว่าเวลาของคุณช้าไปเท่าใด ให้แก้ไขเวลาของระบบ ห้ามปิดการตรวจสอบวันที่ของ apt เพื่อข้ามปัญหานี้ เพราะการตรวจสอบดังกล่าวมีไว้เพื่อป้องกันไม่ให้ผู้อื่นส่งดัชนีแพ็กเกจที่ล้าสมัยมาให้คุณ

ทุกบรรทัดของ source แสดงสถานะ unreachable และ Reach เป็น 0 เนื่องจากไม่มีการตอบกลับ ให้ตรวจสอบการรับส่งข้อมูลขาออก (egress) แทนการตรวจสอบไฟล์ config ของคุณ NTP ใช้พอร์ต UDP 123 ขาออก ซึ่งบางเครือข่ายอาจมีการกรองหรือเปลี่ยนเส้นทาง sudo chronyc ntpdata จะแสดงตัวนับแยกตามแหล่งที่มา รวมถึง Total TX และ Total RX หากค่า TX เพิ่มขึ้นในขณะที่ RX ยังคงเป็นศูนย์ แสดงว่าแพ็กเกจของคุณถูกส่งออกไปแต่ไม่มีการตอบกลับ ซึ่งบ่งชี้ว่ามี firewall กั้นอยู่ระหว่างคุณกับแหล่งที่มา

เวลาเคยถูกต้องแต่เกิดการกระโดด เหตุการณ์บนโฮสต์มักเป็นสาเหตุนี้ เช่น การกู้คืน snapshot, การหยุดพัก guest หรือการย้าย guest แบบ live migration ไปยังโฮสต์อื่น อาจทำให้เวลาของ guest ล้าหลังกว่าความเป็นจริง chrony จะตรวจพบในการ poll ครั้งถัดไปและแก้ไขให้ถูกต้อง ส่วน systemd-timesyncd อาจรอจนกว่าจะครบช่วงเวลา poll ที่ยาวนาน ตรวจสอบให้แน่ใจว่า daemon เริ่มทำงานตอนบูตด้วย systemctl is-enabled chrony เพราะ daemon ที่เริ่มทำงานด้วยตนเองจะหายไปหลังจากการรีบูตครั้งถัดไป

ค่า offset มีขนาดเล็กแต่ไม่เคยคงที่ ให้ตรวจสอบ CPU steal หาก guest ไม่ได้รับการจัดสรรเวลาประมวลผลในขณะที่ timer interrupt ทำงาน ตัวอย่างข้อมูลจะเกิดความล่าช้า ทำให้ค่า offset แกว่งไปมาแทนที่จะเข้าสู่จุดสมดุล top จะแสดงค่านี้เป็นตัวเลข st ในบรรทัด CPU การอ่านค่า CPU steal time บนโฮสต์ที่ใช้งานร่วมกัน อธิบายความหมายของตัวเลขนี้และสิ่งที่คุณสามารถทำได้

ใบรับรองที่เพิ่งออกให้ถูกปฏิเสธว่ายังไม่ถึงเวลาใช้งาน curl จะแสดง SSL certificate problem: certificate is not yet valid และเบราว์เซอร์จะแสดงข้อความในลักษณะเดียวกัน ใบรับรองนั้นถูกต้อง แต่เวลาของเครื่องที่ตรวจสอบนั้นช้าเกินไป ปัญหานี้อาจเกิดจากเครื่องใดเครื่องหนึ่ง ดังนั้นให้ตรวจสอบทั้งฝั่ง client และ server หากเซิร์ฟเวอร์ที่ออกใบรับรองเป็นเครื่องที่มีเวลาไม่ถูกต้อง คู่มือการใช้ certbot และ nginx สำหรับใบรับรอง จะครอบคลุมด้านการต่ออายุของระบบดังกล่าว

เพิ่มรายการนี้เข้าไปในการตรวจสอบที่คุณทำอยู่เป็นประจำ

การซิงค์เวลาเป็นค่าที่ตั้งไว้ตอนบูตเครื่องซึ่งอาจล้มเหลวโดยไม่มีการแจ้งเตือนหลังจากผ่านไปหลายเดือน นี่คือสิ่งที่การตรวจสอบตามรอบจะช่วยตรวจพบได้ แต่ความจำของคุณอาจมองข้ามไป timedatectl และ chronyc tracking ใช้เวลาอ่านรวมกันเพียงสองวินาทีเท่านั้น ให้รันคำสั่งเหล่านี้เป็นส่วนหนึ่งของ สิบนาทีแรกบน VPS ใหม่ และรันอีกครั้งเมื่อคุณดำเนินการตาม รายการตรวจสอบการบำรุงรักษาเซิร์ฟเวอร์ Linux ตามปกติ หากคุณต้องการให้การตรวจสอบนี้ทำงานด้วยตัวเองและแจ้งเตือนเมื่อค่าความคลาดเคลื่อนเพิ่มขึ้น การเขียน systemd service และ timer จะครอบคลุมรูปแบบของ unit ขนาดเล็กที่รายงานผลตามกำหนดเวลา การตรวจสอบลักษณะนี้เป็นเพียงสคริปต์สั้นๆ ไม่ใช่ daemon จึงควรใช้ Type=oneshot แทนค่าเริ่มต้น และ สรุปประเภทของ systemd service จะอธิบายว่าเหตุใดการเลือกประเภทผิดจึงทำให้คุณได้ unit ที่รายงานว่าสำเร็จทั้งที่งานนั้นไม่เคยถูกดำเนินการจริง

FAQ

ฉันจะตรวจสอบได้อย่างไรว่านาฬิกาของ VPS ตรงกันหรือไม่?

ให้รันคำสั่ง timedatectl แล้วอ่านบรรทัด System clock synchronized ซึ่งเป็นแฟล็กของเคอร์เนลที่กำหนดโดย daemon ที่ทำหน้าที่ควบคุมเวลา ดังนั้นการเห็น yes ควบคู่ไปกับ NTP service: n/a จึงเป็นสถานะปกติและถูกต้องสำหรับเครื่องที่ใช้ chrony หากต้องการทราบขนาดของความคลาดเคลื่อน ให้รัน chronyc tracking แล้วอ่านค่า System time หรือรัน timedatectl timesync-status แล้วอ่านค่า Offset หากใช้ systemd-timesyncd อยู่ สำหรับการตรวจสอบเทียบกับแหล่งภายนอก ให้เปรียบเทียบ 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 ให้แก้ไขการซิงค์เวลา แล้วรหัสจะกลับมาใช้งานได้โดยไม่ต้องเปลี่ยน shared secret

ฉันสามารถตั้งเวลาภายใน Docker container ได้หรือไม่?

ไม่ได้ และไม่จำเป็นต้องทำเช่นนั้น คอนเทนเนอร์จะใช้ CLOCK_REALTIME ร่วมกับโฮสต์ เนื่องจาก Linux time namespace จะจำลองเฉพาะนาฬิกาแบบ monotonic และ boot-time เท่านั้น คอนเทนเนอร์ที่ไม่มีสิทธิ์พิเศษจะได้รับ date: cannot set date: Operation not permitted และการเพิ่ม CAP_SYS_TIME จะทำให้คอนเทนเนอร์เปลี่ยนเวลาของโฮสต์ได้แทนที่จะมีนาฬิกาเป็นของตัวเอง ให้ซิงค์เวลาที่โฮสต์แทน หากต้องการเวลาท้องถิ่นที่แตกต่างกันภายในคอนเทนเนอร์ ให้ตั้งค่า TZ ในสภาพแวดล้อมของคอนเทนเนอร์นั้น

เซิร์ฟเวอร์ควรใช้เวลาแบบ UTC หรือเวลาท้องถิ่น?

ควรใช้ UTC และให้แสดงผลเป็นเวลาท้องถิ่นเฉพาะตอนที่ผู้ใช้เรียกดูเท่านั้น UTC ไม่มีการปรับเวลาตามฤดูกาล (daylight saving) ทำให้งานที่ตั้งเวลาไว้ทำงานได้สม่ำเสมอตลอดทั้งปี และ timestamp จากเซิร์ฟเวอร์หลายเครื่องสามารถนำมาเรียงลำดับกันได้โดยไม่ต้องแปลงค่า ให้ตั้งค่าด้วย sudo timedatectl set-timezone UTC หากใครต้องการดูเวลาท้องถิ่น สามารถใช้คำสั่งนำหน้าได้ เช่น TZ=America/New_York date ซึ่งจะไม่ส่งผลกระทบใดๆ ต่อนาฬิกาของระบบ