Chrony Basics
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:
- Kerberos authentication — fails if clock skew exceeds 5 minutes
- TLS certificates — appear invalid if time is outside the validity window
- Log correlation — timestamps become meaningless across systems
- Distributed systems — ordering and consistency depend on accurate time
- Token validation — time-based tokens (TOTP, JWT) expire or fail
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
- Service is running
- Correct NTP servers configured in
/etc/chrony.conf - Firewall/network reachability to NTP servers (UDP port 123)
- Time offset shown by
chronyc tracking - Source state in
chronyc sources -v— look for*next to an active source
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.
| Feature | systemd-timesyncd | chrony |
|---|---|---|
| Default on Debian/Ubuntu | Yes | No (must install) |
| Default on RHEL/CentOS | No | Yes |
| Can serve NTP to other hosts | No | Yes |
| Supports multiple sources | Limited | Yes |
| Suitable for servers | Acceptable | Recommended |
| Accuracy | Good | Better |
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.