Chrony and NTP Time Sync on Linux Servers (Complete Guide)

chrony ntp time sync linux servers custom-chrony-featured.png

Clock drift causes failures that are genuinely confusing to debug: TLS certificate errors (certificates have exact validity windows),
Kerberos rejecting requests outside a tight time skew, cluster quorum software such as corosync — the technology behind Proxmox clustering —
behaving erratically, and log timestamps that do not line up across servers during an incident.

chrony is the modern NTP client and server that current Linux distributions ship by default, replacing the older ntpd.
This guide checks and fixes time sync on a single server, explains what the output actually means, and then builds a local time server so machines on an isolated
network or a Proxmox HA cluster can stay in sync without internet access.

Quick answer: run timedatectl then chronyc tracking. If the offset is milliseconds, you are fine. If not, jump to the
troubleshooting table.

Related guides: chrony not syncing? troubleshooting, set up a LAN NTP server, and timedatectl, hwclock and timezone commands.

Step 1: Why Accurate Time Matters Enough to Check

Time errors rarely announce themselves as “clock is wrong.” They show up as expired-certificate warnings, Kerberos failures, cluster nodes disagreeing, and unreadable log correlation. Check the clock first whenever a failure looks bizarre.

bashquick check
timedatectl
date -u
NoteLook for System clock synchronized: yes. no means nothing is disciplining the clock right now.
Why clock accuracy matters
Wrong time breaks things far from the clock

Step 2: Know Which Time Daemon You Have

Linux has three common options. chrony is the recommended choice for servers and VMs. systemd-timesyncd is a minimal SNTP client that ships with some Ubuntu/Debian installs. ntpd is the legacy daemon. Run exactly one.

bashsee what is running
systemctl is-active chronyd chrony systemd-timesyncd ntpd 2>/dev/null
chrony vs timesyncd vs ntpd
Pick exactly one time daemon

Step 3: Install and Enable chrony

Install chrony, disable the other daemons so they do not fight over the clock, then enable the service. The unit is chronyd on RHEL-family and chrony on Debian/Ubuntu.

bashDebian / Ubuntu
sudo apt install -y chrony
sudo systemctl disable --now systemd-timesyncd
sudo systemctl enable --now chrony
bashAlmaLinux / Rocky / RHEL
sudo dnf install -y chrony
sudo systemctl enable --now chronyd
Installing chrony
One daemon only

Step 4: Understand chrony.conf

The default file works for most servers. Knowing what each line does lets you change it safely. The file lives at /etc/chrony/chrony.conf (Debian/Ubuntu) or /etc/chrony.conf (RHEL-family).

inichrony.conf
# /etc/chrony/chrony.conf  (RHEL-family: /etc/chrony.conf)
pool 2.pool.ntp.org iburst        # several servers from the public pool
# server time.cloudflare.com iburst nts   # optional: authenticated NTP (chrony 4.0+)

makestep 1.0 3      # step the clock if off by >1s during the first 3 updates
rtcsync             # let the kernel keep the hardware clock in sync
driftfile /var/lib/chrony/chrony.drift   # remembers the clock's natural drift
# allow 192.168.1.0/24   # only on a server that should serve time to clients
Tipiburst sends a quick burst of requests at start-up so the first sync takes seconds instead of minutes.
chrony.conf anatomy
Sources, step rules, drift, serving

Step 5: Choose Your Time Sources

Public pool entries are fine for internet-connected servers. Add specific servers for regional preference, and use NTS-capable servers (chrony 4.0 or newer) when you want the time source authenticated. Prefer three or more sources so chrony can detect a bad one.

bashapply the change
sudo systemctl restart chrony    # chronyd on RHEL-family
chronyc sources
Choosing NTP sources
Pool, specific servers, NTS

Step 6: Force an Initial Sync and Read chronyc tracking

After setup, or on a server whose clock is far off, chronyc makestep steps the clock immediately. In normal operation chrony corrects gradually on purpose, because sudden time jumps can upset running applications. Then read the tracking output.

bashstep once, then inspect
sudo chronyc makestep
chronyc tracking
textexample output
Reference ID    : A29FC801 (time.example.net)
Stratum         : 3
System time     : 0.000012893 seconds slow of NTP time
Last offset     : -0.000008101 seconds
RMS offset      : 0.000021450 seconds
Frequency       : 12.304 ppm slow
Skew            : 0.185 ppm
Root delay      : 0.021438 seconds
Leap status     : Normal
NoteSystem time is how far the local clock is from NTP time. Frequency and Skew describe the clock’s natural drift and how certain chrony is about it. Leap status: Normal means healthy.
chronyc tracking explained
Offset, frequency, leap status

Step 7: Verify Sources and Open UDP 123

chronyc sources lists every source. ^* is the source in use, ^+ is a good alternate, ^? is unreachable or unmeasured, ^x is a source chrony believes is wrong. Reach is an octal history of the last eight polls: 377 means all succeeded. NTP uses UDP port 123, so it must be allowed outbound (and inbound on a time server).

textexample output
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^* time.example.net              2   6   377    34   -12us[  -20us] +/-  11ms
^+ ntp2.example.org              2   6   377    35   +31us[  +23us] +/-  15ms
^? 10.0.0.99                     0   6     0     -     +0ns[   +0ns] +/-    0ns
bashallow NTP on a server (UFW)
sudo ufw allow 123/udp
TipSee our UFW guide or nftables guide for firewall basics.
chronyc sources output
Selected, combined, unreachable

Step 8: Run a Local chrony Server for a Cluster or Isolated Network

Designate one host that syncs from the internet (or a GPS/hardware clock) and serves time internally. On isolated networks, local stratum 10 lets it keep serving a consistent time even if its upstream is briefly lost. Point every other node at it.

iniserver: /etc/chrony/chrony.conf
pool 2.pool.ntp.org iburst
allow 192.168.1.0/24
local stratum 10
iniclients: /etc/chrony/chrony.conf
server 192.168.1.10 iburst
makestep 1.0 3
rtcsync
bashon the server: who is syncing from me?
sudo chronyc clients
Local chrony time server
Upstream, server, clients

Troubleshooting chrony

Symptom Likely cause What to do
Not synchronised in chronyc tracking No reachable source Check chronyc sources; allow outbound UDP 123
Offset of whole seconds Big initial drift or VM resume sudo chronyc makestep, then re-check
Source stuck on ^?, Reach 0 Firewall or wrong address Test with chronyc sources -v; verify DNS and routing
Clock keeps jumping Two daemons running Disable systemd-timesyncd / ntpd; keep only chronyd
Clients cannot sync from your server Missing allow or firewall Add allow <subnet>; open UDP 123 on the server
Time correct but timezone wrong Timezone is separate from sync sudo timedatectl set-timezone Region/City

Time Sync on Virtual Machines and Proxmox

Virtual machines can pause, migrate and resume, which makes their clocks jump. Run chrony inside each guest rather than trusting the host alone, and keep the
hypervisors themselves synchronised. Time-sensitive clusters (Ceph, corosync) will tell you loudly when nodes disagree; see our
Proxmox cluster guide and HA cluster guide.

Frequently Asked Questions

Is chrony better than ntpd?

For most servers, yes. chrony synchronises faster after boot, copes better with unstable networks and virtual machines, and is the default in current RHEL-family and many Debian/Ubuntu installs. ntpd is legacy for new deployments.

How do I check whether my Linux server is time-synced?

Run timedatectl and look for System clock synchronized: yes, then chronyc tracking for the actual offset. A System time offset of a few milliseconds is healthy.

What does the ^* symbol in chronyc sources mean?

^* marks the source chrony is currently synchronised to. ^+ marks acceptable sources combined with it, and ^? means the source is unreachable or has not been measured yet.

Why is chrony not syncing?

The usual causes are outbound UDP port 123 blocked by a firewall, another time daemon (systemd-timesyncd or ntpd) still running, no reachable sources, or a very large initial offset that needs chronyc makestep.

Should I use makestep in production?

Use it once after setup or when a server has drifted badly. The makestep 1.0 3 line in chrony.conf already lets chrony step the clock during the first three updates after start; afterwards chrony corrects gradually so applications do not see sudden time jumps.

Do I need a local NTP server for a Proxmox cluster?

Not strictly, but on isolated networks it keeps every node tightly synchronised to the others even when the internet is unreachable, which matters for corosync-based clustering.

Command Reference

  • timedatectl — quick sync status
  • chronyc tracking — offset and clock quality
  • chronyc sources -v — sources with legend
  • chronyc sourcestats — per-source statistics
  • sudo chronyc makestep — step the clock now
  • sudo chronyc clients — clients of your time server

Related tutorials

Diagrams are original illustrations by Gnome IT Solutions. Tutorial text © Gnome IT Solutions.