SSD Nodes Learn 🎉 VPS từ $5.50/tháng
Hướng dẫn Matt ConnorBởi Matt Connor

Vì sao đồng hồ VPS bị trôi và cách sửa

Đồng hồ VPS trôi làm TOTP lỗi và certificate hết hạn sai. Xem 3 clock, đọc chronyc, timedatectl và mở UDP 123 để khôi phục sync.

Vì sao đồng hồ VPS bị trôi

Đồng hồ VPS bị trôi vì không có gì hiệu chỉnh nó. Kernel tính thời gian từ một bộ đếm phần cứng chạy nhanh hoặc chậm hơn một chút. Nếu không có client đồng bộ thời gian chạy, sai số nhỏ đó sẽ tăng lên sau mỗi giờ. Trong máy ảo còn có một nguyên nhân khác: guest dùng chung CPU vật lý với các guest khác, nên trong những khoảng thời gian không được scheduler cấp CPU, nó không thể tiếp tục đếm thời gian.

Trên guest KVM hiện nay, bản thân bộ đếm hiếm khi là nguyên nhân thực sự. Nguồn kvm-clock paravirtual đọc một giá trị do host duy trì, nên guest khỏe mạnh thường bám sát thời gian của host. Đồng hồ sai rõ rệt thường sai vì những nguyên nhân đơn giản hơn. Không có sync daemon nào đang chạy, hoặc có hai daemon chạy đồng thời và xung đột, hoặc lưu lượng UDP outbound trên port 123 không thể rời khỏi network của nhà cung cấp. Guest lấy cơ chế hiệu chỉnh thời gian từ host hoặc từ NTP (network time protocol), không phải từ bộ dao động riêng của nó.

Những lỗi thực tế do đồng hồ sai

  • Mã xác thực hai yếu tố TOTP (mật khẩu dùng một lần dựa trên thời gian) không còn khớp, khiến bạn bị khóa khỏi server dù password và key đều chính xác.
  • Certificate vừa được cấp một phút trước bị từ chối, và curl in ra SSL certificate problem: certificate is not yet valid.
  • apt update từ chối repository với E: Release file for ... is not valid yet (invalid for another 1d 2h 3min 4s).
  • Tác vụ được lập lịch chạy sai thời điểm. Đồng hồ nhảy giờ có thể khiến một job chạy hai lần trong khi job khác bị bỏ qua.
  • Không thể căn chỉnh log từ hai server, nên phải dựng timeline của sự cố bằng cách phỏng đoán.

Dung sai nhỏ hơn nhiều so với dự đoán của hầu hết mọi người. Các con số dưới đây là giá trị mặc định được tài liệu ghi rõ, không phải số đo từ một bài kiểm thử.

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

Mã TOTP được tính từ một counter tăng sau mỗi 30 giây, và hầu hết verifier chấp nhận lệch một bước ở mỗi phía. Sai lệch nửa phút theo mỗi hướng là toàn bộ khoảng dung sai. Kerberos dễ chấp nhận sai lệch hơn nhiều, với mức dung sai mặc định là 300 giây. Certificate hoàn toàn không có dung sai: hệ thống kiểm tra certificate dựa trên các thời điểm cố định với khoảng ân hạn 0 giây, nên đồng hồ chạy sớm một giây cũng khiến certificate hoàn toàn hợp lệ bị từ chối.

Ba đồng hồ và đồng hồ nào quan trọng

Đồng hồ hệ thống là đồng hồ quan trọng. Đây là CLOCK_REALTIME của kernel: số giây tính từ ngày 1 tháng 1 năm 1970 UTC, được giữ trong bộ nhớ và được mọi thành phần ghi timestamp đọc. Các dòng log, lần kiểm tra certificate, mã TOTP và thời gian sửa đổi file đều lấy từ đồng hồ này. Khi ai đó nói thời gian của server bị sai, họ đang nói đến đồng hồ này.

Đồng hồ phần cứng, còn gọi là RTC (real time clock), là một bộ đếm riêng vẫn chạy khi máy đã tắt. Trên máy vật lý, đây là chip được cấp nguồn bằng pin. Bên trong guest, hypervisor mô phỏng nó, nên phần lớn đây là thông tin do host cung cấp. Linux đọc đồng hồ này một lần khi boot để lấy giá trị ban đầu, sau đó tự duy trì bộ đếm riêng. timedatectl in giá trị này trên dòng RTC time. Không dùng dòng này để debug trên VPS, vì nó cho biết nhận thức về thời gian của host chứ không cho biết trạng thái đồng bộ của đồng hồ hệ thống. Trong container thường không có /dev/rtc, nên hwclock --show sẽ fail với hwclock: Cannot access the Hardware Clock via any known method.

Clocksource là nguồn mà kernel dùng để đếm thời gian giữa các lần đọc đó. Hãy hỏi kernel đang chọn nguồn nào:

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

Trên KVM, bạn thường sẽ thấy kvm-clock. Nó đọc giá trị do host duy trì. Vì vậy, guest KVM không chạy NTP client vẫn giữ thời gian tương đối chính xác trong một khoảng thời gian. tsc là bộ đếm riêng của CPU. Guest Xen báo cáo xen, còn guest Hyper-V báo cáo nguồn hyperv. Không thay đổi setting này nếu chưa có lý do đo được rõ ràng, vì kernel đã tự chọn nguồn tốt nhất mà nó tin cậy trên phần cứng đó.

Một số host cũng cung cấp thiết bị PTP (precision time protocol) cho guest. Nhờ đó, chrony có thể đọc trực tiếp đồng hồ của host thay vì đọc qua network. Bạn nên kiểm tra, nhưng tính năng này thường không có trên VPS dùng chung:

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

Nếu modprobe fail hoặc không xuất hiện thiết bị nào, host của bạn không cung cấp tính năng này và network NTP là lựa chọn duy nhất. Nếu clock_name cho biết clock ảo KVM, chrony có thể dùng nó với dòng refclock PHC /dev/ptp0 poll 2 trong file cấu hình.

Tự kiểm tra trạng thái thời gian trên máy

Bắt đầu bằng một lệnh. Lệnh này trả lời câu hỏi “có gì đang giữ cho đồng hồ này chạy đúng không” trên một màn hình.

timedatectl

Đọc các dòng này thay vì dựa vào một con số bạn nhớ:

  • Local timeUniversal time là cùng một thời điểm, được hiển thị theo múi giờ của bạn và theo UTC. Nếu chúng giống hệt nhau, máy đã dùng UTC.
  • RTC time là hardware clock được mô tả ở trên. Trên VPS, hãy bỏ qua nó.
  • Time zone là giá trị hệ thống dùng để định dạng giờ địa phương.
  • System clock synchronized là cờ riêng của kernel. Time daemon đặt cờ này sau khi tin tưởng các nguồn thời gian của nó, nên no có nghĩa là chưa có tiến trình nào hiệu chỉnh đồng hồ này kể từ khi boot.
  • NTP service báo cáo riêng về systemd-timesyncd. n/a là trạng thái bình thường trên máy chạy chrony, vì timesyncd không được cài đặt trên máy đó. System clock synchronized: yes cùng với NTP service: n/a có nghĩa là chrony đang xử lý việc đồng bộ và kernel đồng ý với trạng thái đó.

Tiếp theo, hãy kiểm tra đồng hồ của bạn lệch bao xa. Đừng ước lượng bằng cách so với điện thoại. Nếu chrony đang chạy:

chronyc tracking
chronyc sources -v

chronyc tracking in ra các giá trị trả lời câu hỏi này. System time là độ lệch hiện tại so với giờ NTP, theo sau là từ fast hoặc slow. Last offset là kích thước của lần hiệu chỉnh gần đây nhất. Frequency là sai số tốc độ mà chrony đo được trên đồng hồ và đang bù trừ. Leap status phải hiển thị Normal. Nếu hiển thị Not synchronisedReference ID00000000 (), chrony vẫn chưa chọn được một nguồn ổn định.

chronyc sources -v in chú giải phía trên danh sách, vì vậy bạn không cần nhớ các ký hiệu. Hai cột chứa phần lớn thông tin quan trọng. Ký tự trạng thái ở đầu mỗi dòng cho biết chrony đánh giá nguồn đó thế nào; * đánh dấu nguồn hiện đang được sử dụng, còn ? trên mọi dòng có nghĩa là không nguồn nào phản hồi. Reach là lịch sử phản hồi của 8 lần thăm dò gần nhất, được in theo hệ bát phân: 377 có nghĩa là cả 8 lần đều nhận được phản hồi, còn 0 có nghĩa là không lần nào nhận được phản hồi.

Nếu systemd-timesyncd đang quản lý việc đồng bộ:

timedatectl timesync-status
timedatectl show-timesync --all

timesync-status in ra server mà máy đang kết nối, khoảng thời gian thăm dò và giá trị Offset. Nếu lệnh trả về lỗi liên quan đến service thay vì in trạng thái, timesyncd không phải daemon đang quản lý thời gian trên máy này. Đó cũng chính là câu trả lời cho câu hỏi của bạn.

Để kiểm tra sơ bộ với bên ngoài mà không cần thêm công cụ, hãy so sánh đồng hồ của bạn với header HTTP công khai Date. Header này được trả về theo GMT với độ phân giải 1 giây:

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

Chênh lệch 1 hoặc 2 giây ở đây là bình thường và không có ý nghĩa. Chênh lệch 1 phút là lỗi của bạn.

chrony hoặc systemd-timesyncd trên VPS

Ubuntu và Debian cài sẵn systemd-timesyncd. Đây là client SNTP (simple network time protocol): nó truy vấn từng server một và điều chỉnh clock về phía server đó. Với máy luôn online và có thời gian ban đầu tương đối chính xác, như vậy là đủ và gần như không tốn tài nguyên.

chrony là một bản triển khai NTP đầy đủ và là lựa chọn mặc định tốt hơn trên máy ảo, vì những lý do có thể thấy ngay trong output của nó. Nó poll nhiều nguồn cùng lúc và loại bỏ các nguồn có giá trị sai lệch. Nó đo sai số tốc độ của clock rồi ghi vào drift file, nhờ đó sửa xu hướng lệch của clock thay vì chạy theo từng mẫu đo. chrony cũng khôi phục nhanh sau hai tình huống mà VM có thể gặp nhưng máy vật lý thường không gặp: VM có thể bị host tạm dừng và có thể được chuyển sang host khác khi đang chạy. Khi host cung cấp thiết bị PTP, chrony là thành phần đọc thiết bị đó.

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

Theo dõi output của apt trong lúc lệnh chạy. Trên Debian và Ubuntu, cả package chrony và systemd-timesyncd đều cung cấp time-daemon, nên apt sẽ gỡ timesyncd khi cài chrony. Đây là hành vi đúng và được mong muốn. Không bao giờ chạy cả hai, vì hai daemon cùng chỉnh một clock sẽ xung đột; khi đó không thể tin offset mà chúng báo cáo. Trên Rocky và AlmaLinux, cài bằng sudo dnf install -y chrony. Ở đó unit có tên chronyd thay vì chrony.

File cấu hình là /etc/chrony/chrony.conf trên Debian và Ubuntu, và /etc/chrony.conf trên Rocky và Alma. Cấu hình mặc định của distribution đã phù hợp cho VPS, vì vậy chỉ thay đổi khi có lý do cụ thể. Có hai directive cần hiểu:

  • Các dòng poolserver khai báo nguồn thời gian. Thêm iburst sẽ yêu cầu chrony gửi một burst nhanh khi khởi động, để lần đồng bộ đầu tiên hoàn tất trong vài giây thay vì vài phút.
  • makestep quyết định khi nào chrony nhảy clock thay vì điều chỉnh dần. Kiểm tra giá trị hiện tại bằng grep -n makestep /etc/chrony/chrony.conf. Giá trị mặc định trên Debian và Ubuntu, makestep 1 3, có nghĩa là: trong 3 lần update đầu tiên sau khi chronyd khởi động, clock sẽ được step nếu lệch hơn 1 giây; sau đó chỉ sửa bằng cách slewing.

Nếu muốn xác thực lưu lượng thời gian để chống sửa đổi trên đường truyền, chrony 4 trở lên hỗ trợ NTS (network time security). Trước tiên hãy xác nhận phiên bản bằng chronyd -v. Lưu ý rằng NTS cần mở TCP port 4460 bên cạnh UDP 123:

server time.cloudflare.com iburst nts

Hãy restart và verify trước khi tin tưởng cấu hình. Nếu config không parse được, bạn sẽ không còn time daemon nào chạy, và clock sẽ không báo cho bạn biết điều đó.

sudo systemctl restart chrony
chronyc sources -v
chronyc tracking

Vì sao đồng hồ lệch vài phút vẫn tiếp tục lệch

Một time daemon có hai cách sửa độ lệch. Slew tăng hoặc giảm tốc độ chạy của đồng hồ cho đến khi hết sai số. Cách này giữ cho thời gian luôn tiến về phía trước, không lặp lại hoặc bỏ qua timestamp. Step nhảy thẳng đến giá trị đúng. Cách này nhanh nhưng có thể làm đồng hồ chạy lùi. Chạy lùi rất nguy hiểm đối với mọi thành phần đo thời gian đã trôi qua dựa trên wall clock, vì vậy cả hai daemon đều ưu tiên slew.

Đó là lý do đồng hồ lệch nhiều có thể tiếp tục sai trong thời gian dài. chrony chỉ step trong khoảng thời gian mà makestep cho phép. Theo mặc định, khoảng này là vài lần update đầu tiên sau khi daemon khởi động. Nếu chronyd đã chạy một tuần rồi phát hiện đồng hồ lệch bốn mươi giây, nó sẽ slew độ lệch đó. Việc slew bốn mươi giây mất lâu hơn nhiều so với thời gian bạn muốn chờ. Hãy chủ động force một lần vào lúc hệ thống ít hoạt động:

sudo chronyc makestep
chronyc tracking

chronyc tracking hiện phải báo cáo một offset System time gần bằng 0. Last offset phải hiển thị kích thước phần vừa được sửa. Hãy cân nhắc trước khi chạy lệnh này trên database host đang bận, vì đồng hồ chạy lùi có thể làm rối các phần mềm giả định rằng thời gian chỉ tiến về phía trước. Restart daemon là cách nhẹ nhàng hơn để thực hiện cùng việc sửa này, vì khoảng thời gian makestep được mở lại khi daemon khởi động.

Container dùng chung clock của host

Container không có wall clock riêng, nên không có gì để đồng bộ bên trong nó. Linux time namespace chỉ virtualise clock monotonic và clock thời điểm boot. CLOCK_REALTIME không được virtualise, nên container đọc cùng system clock với host đang chạy nó. Sửa clock trên host thì mọi container trên host đó cũng được sửa tại cùng thời điểm.

Điều này dẫn đến một số hệ quả. Không cài chrony hoặc ntpd vào image, vì trong trường hợp tốt nhất việc đó cũng không có tác dụng. Đặt ngày giờ bên trong một container không có đặc quyền sẽ fail với date: cannot set date: Operation not permitted, vì kernel yêu cầu CAP_SYS_TIME cho system call đó. Cấp CAP_SYS_TIME không tạo clock riêng cho container. Nó cho container quyền thay đổi clock của host, và do đó thay đổi clock của mọi container khác.

Time zone khác bên trong container không phải là vấn đề về clock. Image có /etc/localtime riêng sẽ hiển thị cùng một thời điểm, nhưng format theo zone khác. Vì vậy date có thể trông sai dù clock vẫn đúng. Đặt TZ=UTC trong environment của container sẽ loại bỏ nhầm lẫn này. Runtime bạn chọn không thay đổi điều gì ở đây. Bài so sánh Podman và Docker rootless giải thích những điểm mà runtime đó thực sự thay đổi.

Múi giờ: UTC trên server, giờ địa phương cho người dùng

Đặt máy dùng UTC và giữ nguyên như vậy.

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

UTC không có giờ mùa hè, và đó là lý do chính. Một job chạy hằng ngày lúc 02:30 trong múi giờ có áp dụng giờ mùa hè sẽ chạy 2 lần vào ngày đồng hồ lùi, và không chạy lần nào vào ngày đồng hồ tiến. man 8 cron mô tả cách xử lý đặc biệt đối với thay đổi dưới 3 giờ: các job bị bỏ qua do đồng hồ tiến sẽ chạy ngay sau khi thay đổi, còn các job rơi vào giờ bị lặp do đồng hồ lùi sẽ không chạy lần thứ hai. Cách xử lý đó hợp lý, nhưng bạn vẫn không nên phải suy luận về nó lúc 03:00. Với UTC, job chạy 1 lần mỗi ngày, mọi ngày trong năm. Nếu job của bạn hoàn toàn không chạy thay vì chạy vào giờ bất thường, các lý do khiến cron job âm thầm không bao giờ chạy có khả năng là nguyên nhân hơn.

Lập luận tương tự cũng áp dụng khi đọc log. journalctl định dạng timestamp theo múi giờ của system, còn journalctl --utc buộc dùng UTC. 2 server ở 2 múi giờ khác nhau biến mọi sự cố thành bài toán quy đổi, và việc quy đổi trong lúc chịu áp lực là nguyên nhân khiến người ta đọc sai timeline. Giữ các system dùng UTC, lưu timestamp ở UTC, và chỉ chuyển đổi tại nơi con người đọc chúng. Ai cần xem theo giờ địa phương cho 1 command có thể yêu cầu mà không cần đổi múi giờ của máy:

TZ=Europe/Berlin date

Một dòng nữa trong output của timedatectl thuộc phần này. RTC in local TZ phải hiển thị là no. Đặt thành yes là cách xử lý tạm thời cho việc dual-boot Windows trên laptop; trên server, nó chỉ thêm một offset để sau này có người vô tình gặp lỗi. Khi được đặt như vậy, timedatectl in ra cảnh báo rằng system được cấu hình để đọc thời gian RTC theo múi giờ địa phương.

Khắc phục sự cố theo triệu chứng

Mã xác thực hai yếu tố bị từ chối trên một máy chủ. Kiểm tra đồng hồ trước khi kiểm tra bất kỳ thứ gì khác. Mã được tạo từ một bộ đếm tăng sau mỗi 30 giây, vì vậy máy chủ chậm 90 giây sẽ tính mã dựa trên một bước mà điện thoại của bạn đã qua. timedatectl sẽ hiển thị System clock synchronized: no hoặc chronyc tracking sẽ báo độ lệch System time rất lớn. Đây là lỗi khác với trường hợp key bị từ chối hoàn toàn, vốn sẽ in thông báo riêng và được đề cập trong hướng dẫn về lỗi xác thực bằng public key.

apt update báo rằng tệp Release chưa hợp lệ. Thông báo đầy đủ nêu tên repository và khoảng thời gian tệp vẫn chưa hợp lệ, ví dụ is not valid yet (invalid for another 1d 2h 3min 4s). Đồng hồ của bạn chậm hơn thời gian ghi trong tệp Release của repository, và khoảng thời gian đó đo trực tiếp mức độ chậm. Hãy sửa đồng hồ. Không vô hiệu hóa kiểm tra ngày của apt để bỏ qua lỗi này, vì chính kiểm tra đó ngăn người khác cung cấp cho bạn một package index cũ.

Mọi dòng source đều hiển thị trạng thái không thể truy cập và Reach bằng 0. Không có gì phản hồi, vì vậy hãy kiểm tra lưu lượng đi ra thay vì kiểm tra cấu hình. NTP sử dụng UDP port 123 cho lưu lượng đi ra, và một số mạng lọc hoặc chuyển hướng lưu lượng này. sudo chronyc ntpdata in các bộ đếm theo từng source, bao gồm Total TXTotal RX. Nếu bộ đếm TX tăng trong khi RX vẫn bằng 0, các packet của bạn đã rời máy nhưng không có dữ liệu quay về. Điều này cho thấy có firewall nằm giữa bạn và source.

Đồng hồ đúng, sau đó nhảy lệch. Các sự kiện trên host có thể gây ra tình trạng này. Việc khôi phục snapshot, guest bị tạm dừng hoặc live migration sang host khác có thể khiến thời gian mà guest nhận biết bị chậm hơn thời gian thực. chrony phát hiện vấn đề ở lần poll tiếp theo và hiệu chỉnh; systemd-timesyncd có thể chờ hết một poll interval dài trước khi hiệu chỉnh. Xác nhận daemon khởi động cùng hệ thống bằng systemctl is-enabled chrony, vì daemon được khởi động thủ công sẽ biến mất sau lần reboot tiếp theo.

Độ lệch nhỏ nhưng không bao giờ ổn định. Kiểm tra CPU steal. Guest không được lên lịch khi đến thời điểm timer interrupt sẽ nhận mẫu bị trễ, nên độ lệch dao động thay vì hội tụ. top hiển thị giá trị này dưới dạng chỉ số st trên dòng CPU. Cách đọc thời gian CPU steal trên shared host giải thích ý nghĩa của con số đó và các biện pháp xử lý.

Certificate vừa cấp bị từ chối vì chưa có hiệu lực. curl in SSL certificate problem: certificate is not yet valid và trình duyệt cũng báo lỗi tương tự. Certificate không có vấn đề; đồng hồ dùng để kiểm tra certificate đang bị chậm. Máy client hoặc máy server đều có thể là nguyên nhân, vì vậy hãy kiểm tra cả hai. Nếu máy chủ cấp certificate là máy có đồng hồ sai, hướng dẫn về certificate của certbot và nginx trình bày phần gia hạn trong cùng cấu hình đó.

Đưa vào các bước kiểm tra bạn đã thực hiện

Đồng bộ thời gian là một thiết lập lúc boot có thể âm thầm lỗi sau vài tháng. Đây chính xác là loại vấn đề mà một quy trình định kỳ sẽ phát hiện, còn trí nhớ thì không. timedatectlchronyc tracking chỉ mất hai giây để đọc cùng nhau. Hãy chạy chúng trong mười phút đầu tiên khi thiết lập một VPS mới, rồi chạy lại khi thực hiện checklist bảo trì server Linux định kỳ. Nếu muốn tự động chạy bước kiểm tra và cảnh báo khi offset tăng, viết service và timer systemd trình bày mẫu cho một unit nhỏ báo cáo theo lịch.

FAQ

Làm thế nào để kiểm tra đồng hồ VPS có được đồng bộ không?

Chạy timedatectl rồi đọc dòng System clock synchronized. Đây là cờ của chính kernel, được daemon đang điều chỉnh đồng hồ đặt lại. Vì vậy, yes cùng với NTP service: n/a là trạng thái bình thường và tốt trên máy chạy chrony. Để xem độ lệch, chạy chronyc tracking rồi đọc System time. Nếu systemd-timesyncd đang đảm nhiệm việc này, chạy timedatectl timesync-status rồi đọc Offset. Để kiểm tra với nguồn bên ngoài máy, so sánh date -u với header Date do bất kỳ trang HTTPS nào trả về.

Nên dùng chrony hay systemd-timesyncd trên VPS?

Hãy dùng chrony cho mọi máy quan trọng. systemd-timesyncd là một SNTP client chỉ theo dõi một server. Nó phù hợp với máy luôn online và ban đầu đã gần đúng giờ. chrony thăm dò nhiều nguồn, loại bỏ các nguồn có thời gian lệch, học tốc độ sai lệch của đồng hồ và khôi phục nhanh sau khi host tạm dừng hoặc live migration. Cài chrony trên Debian hoặc Ubuntu sẽ tự động gỡ systemd-timesyncd vì cả hai package đều cung cấp time-daemon. Không bao giờ chạy đồng thời hai time daemon.

Vì sao mã TOTP lỗi trên một server nhưng hoạt động ở mọi nơi khác?

Vì mã TOTP phụ thuộc vào thời gian hiện tại. Mã được tạo từ một counter tăng sau mỗi 30 giây. Vì vậy, server và điện thoại của bạn phải thống nhất đang ở bước nào. Hầu hết verifier chấp nhận lệch một bước theo cả hai hướng, nên có khoảng đệm khoảng nửa phút ở mỗi hướng. Kiểm tra timedatectl trên server đó. Nếu System clock synchronized đọc là no, hãy sửa lỗi đồng bộ. Mã sẽ khớp lại mà không cần thay đổi shared secret.

Có thể đặt thời gian bên trong Docker container không?

Không, và bạn cũng không cần làm vậy. Container dùng chung CLOCK_REALTIME của host vì Linux time namespace chỉ ảo hóa đồng hồ monotonic và đồng hồ boot-time. Container không có đặc quyền sẽ nhận date: cannot set date: Operation not permitted. Thêm CAP_SYS_TIME cho phép container thay đổi đồng hồ của host, thay vì cấp cho nó một đồng hồ riêng. Hãy đồng bộ host. Nếu muốn dùng giờ địa phương khác bên trong container, đó là thiết lập múi giờ. Hãy đặt TZ trong môi trường của container.

Server nên dùng UTC hay giờ địa phương?

Dùng UTC và chỉ áp dụng giờ địa phương tại nơi người dùng đọc output. UTC không thay đổi theo daylight saving, nên một job hằng ngày chạy một lần mỗi ngày trong cả năm. Timestamp từ các server khác nhau cũng khớp nhau mà không cần chuyển đổi. Đặt UTC bằng sudo timedatectl set-timezone UTC. Nếu cần xem theo giờ địa phương, có thể thêm tiền tố vào một lệnh, chẳng hạn TZ=America/New_York date. Cách này không thay đổi system clock.