The most surprising thing about NTP is that it doesn’t actually synchronize clocks to zero; it synchronizes them to each other, and the "zero" is an abstract, idealized clock.
Let’s watch it in action. Imagine you have a server, ntp-server.example.com, and a client machine, client.example.com.
On client.example.com, you’d typically install an NTP client package, often ntpd or chronyd. Let’s assume chronyd for this example.
First, configure chronyd to point to your NTP server. In /etc/chrony.conf (or /etc/chrony/chrony.conf), you’d have lines like:
server ntp-server.example.com iburst
makestep 10 3
The server line tells chrony which server to talk to. iburst is a special option that sends a burst of initial packets to speed up the initial synchronization, especially useful on high-latency networks. The makestep 10 3 line is crucial: it means if the clock is more than 10 seconds off, chrony will "step" the clock (jump it directly) rather than slowly "slewing" it (gradually adjusting it). It will do this for the first 3 synchronization attempts. This prevents makestep from constantly interfering once the clock is close.
Now, start the chronyd service:
systemctl start chronyd
systemctl enable chronyd
To see what’s happening, you’d use the chronyc command:
chronyc sources
This might show output like:
210 Number of sources = 1
MS Name/IP address Stratum Poll LastRx/Tx Offset Skew Freq
==============================================================================
^* ntp-server.example.com 2 6 16 +2567ns 1234ps +0.123456789
Let’s break that down:
*: This indicates thatntp-server.example.comis the currently selected synchronization source for your system clock.^: This means the source is "reachable."2: This is the stratum level of the server. Stratum 0 are reference clocks (like atomic clocks or GPS receivers). Stratum 1 servers synchronize directly to stratum 0. Stratum 2 servers synchronize to stratum 1, and so on. The lower the stratum, the closer the server is to a true time source.6: This is the polling interval in base 2 logarithm of seconds. So, 2^6 = 64 seconds.chronywill query this server roughly every 64 seconds.16: This is the age of the last received update in seconds.16here means the last packet from the server was received 16 seconds ago.+2567ns: This is the estimated offset between your client clock and the server clock in nanoseconds. A positive value means your client clock is ahead of the server.1234ps: This is the estimated root mean square error (skew) of your clock relative to the reference clock, in picoseconds. It’s a measure of how much your clock is drifting.+0.123456789: This is the estimated frequency error of your clock. A positive value means your clock is running slightly too fast.
The core problem NTP solves is that computers, by themselves, are terrible at keeping time. Their internal oscillators drift. Without synchronization, two machines might have clocks that diverge by seconds or even minutes per day, making distributed systems, logging, and security protocols (like Kerberos) unreliable or impossible.
NTP works by exchanging packets between a client and one or more servers. The client sends a packet asking for the time, recording its departure time (T1). The server receives this packet, records its arrival time (T2), adds its own timestamp before sending the reply (T3), and the client receives the reply, recording its arrival time (T4).
The magic happens in calculating the round-trip delay and the offset.
- Round-trip delay (
d) =(T4 - T1) - (T3 - T2) - One-way delay (
d/2if symmetrical) =d / 2 - Offset (
theta) =(T2 - T4) + (T3 - T1) / 2
NTP is designed to be robust against network latency variations. It uses a sophisticated algorithm to select the best time source from multiple servers, discarding "sick" ones that provide inconsistent or wildly different times. It’s not just about getting a time; it’s about getting the best possible time from a hierarchy of trusted sources.
The one thing most people don’t realize is how NTP actively fights against clock drift. It doesn’t just set the clock periodically. When the offset is small (typically less than 128ms for ntpd or a configurable value for chrony), the NTP daemon will slew the clock. This means it gradually speeds up or slows down your system clock until it matches the server’s time. If your clock is running fast, it will be slowed down infinitesimally; if it’s running slow, it will be sped up. This gentle adjustment avoids the sudden jumps that could disrupt time-sensitive applications or cause issues with file timestamps. makestep is for when the drift is too large to slew effectively within a reasonable time.
Once your chronyc sources shows a stable, selected source (*) with a small offset and skew, your system clock is synchronized. The next problem you’ll encounter is dealing with the security implications of NTP, particularly NTP spoofing attacks and the use of Network Time Security (NTS).