Chrony Basics

Page 10 — Time synchronisation, why it matters, and how to check it.

What Chrony is

Chrony is a time synchronisation service. It keeps the system clock accurate by syncing with NTP servers. The daemon is called chronyd.

Why time matters

A surprising number of things break silently when system time is wrong:

Tip: Before debugging any Kerberos or TLS problem, always verify that time is correct first.

Main config file

/etc/chrony.conf

Basic config example

server time.example.com iburst
driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync

iburst sends a burst of packets on first contact for faster initial sync. makestep 1.0 3 allows stepping the clock in the first 3 updates if offset exceeds 1 second. rtcsync syncs the hardware clock.

Useful commands

chronyc tracking

chronyc tracking

Shows current synchronisation status and time offset. Use it to verify the machine is actually synced to a time source.

chronyc sources -v

chronyc sources -v

Shows configured time sources and their quality/state. Look for a source with * (currently selected) and low stratum/offset values.

chronyc sourcestats

chronyc sourcestats

Shows statistics about each time source — useful for checking source stability over time.

timedatectl

timedatectl

Shows general system time settings including whether NTP is active. Quick first check for time-related issues.

Service checks

systemctl status chronyd
systemctl restart chronyd
journalctl -u chronyd -n 50

What to check

chronyc waitsync

chronyc waitsync blocks until chrony achieves time synchronization (within a specified offset). This is useful in scripts and Ansible playbooks that need the clock to be accurate before proceeding — for example, before enrolling in FreeIPA or generating Kerberos tickets.

# Wait until sync is achieved (blocks indefinitely)
chronyc waitsync

# Wait with max offset of 0.1 seconds and max 30 polls
# Format: chronyc waitsync [max-tries [max-correction [max-skew [interval]]]]
chronyc waitsync 30 0.1 0 1
#                 ^   ^    ^ ^
#                 |   |    | poll interval (seconds)
#                 |   |    max clock skew (0 = ignore)
#                 |   max offset to consider "synced" (seconds)
#                 max number of polls before giving up

Typical use in an Ansible playbook after system boot:

- name: Wait for NTP synchronisation
  ansible.builtin.command: chronyc waitsync 30 0.1 0 1
  changed_when: false
  when: ansible_service_mgr == "systemd"

Without this step, playbooks that run immediately after boot may encounter Kerberos authentication failures (KRB5KRB_AP_ERR_SKEW) because the clock skew exceeds the 5-minute Kerberos tolerance.

Serving NTP to a LAN

In isolated environments (air-gapped, on-prem without external internet access) you can configure one host to sync to an authoritative source and serve NTP to all other hosts on the LAN using chrony.

NTP server configuration

# /etc/chrony.conf on the NTP server

# Sync from an authoritative upstream source (or GPS/hardware clock)
pool ntp1.upstream.example.com iburst
pool ntp2.upstream.example.com iburst

# Allow LAN hosts to use this server as a time source
allow 10.0.0.0/8           # your internal network range
allow 192.168.0.0/24

# local stratum 10: if upstream becomes unreachable,
# continue serving time to clients using the local clock
# Stratum 10 indicates it is a local clock (not an internet source)
local stratum 10

driftfile /var/lib/chrony/drift
# Open the NTP port on the firewall
firewall-cmd --permanent --add-service=ntp
firewall-cmd --reload

# Restart chrony
systemctl restart chronyd

# Verify clients can reach the server
chronyc clients    # shows which hosts are querying this server

Client configuration

# /etc/chrony.conf on client hosts — point to the internal NTP server
server ntp-server.internal.example.com iburst
driftfile /var/lib/chrony/drift

systemd-timesyncd vs chrony

On Debian/Ubuntu systems, systemd-timesyncd is the default NTP client. It is lightweight but limited — it cannot serve NTP, cannot handle complex source configurations, and is not as accurate as chrony. Understanding which is active avoids confusion when chrony commands return no output.

Featuresystemd-timesyncdchrony
Default on Debian/UbuntuYesNo (must install)
Default on RHEL/CentOSNoYes
Can serve NTP to other hostsNoYes
Supports multiple sourcesLimitedYes
Suitable for serversAcceptableRecommended
AccuracyGoodBetter

Checking which service is active

# Check if timesyncd is running
systemctl status systemd-timesyncd

# Check if chrony is running
systemctl status chronyd

# Show current sync status (timesyncd)
timedatectl show-timesync

# Show current sync status (chrony)
chronyc tracking

Switching from timesyncd to chrony on Debian/Ubuntu

# Install chrony (automatically disables timesyncd via conflict)
apt install chrony

# Verify timesyncd is stopped
systemctl status systemd-timesyncd   # should be inactive

# Verify chrony is running
systemctl status chronyd
chronyc tracking

On RHEL/CentOS, chrony is the default and timesyncd is not used. On Debian/Ubuntu, installing chrony is the correct approach for any server that needs accurate time, serves NTP to other hosts, or must satisfy Kerberos time requirements.