$linuxjunkies
>

chrony and Secure Time on Linux

Configure chrony with NTS (authenticated NTP over TLS) on Linux to prevent clock-skew attacks and protect Kerberos, TLS, and TOTP authentication.

IntermediateUbuntuDebianFedoraArch9 min readUpdated June 7, 2026

Before you start

  • Root or sudo access on the target system
  • Outbound access to UDP 123 and TCP 4460 from the host
  • chrony 4.0 or later for NTS support (check with chronyd --version)
  • DNS resolution working before chronyd starts (NTS validates server hostnames)

Accurate system time is not a cosmetic concern. Kerberos tickets expire within five minutes of clock skew. TLS certificate validation fails when clocks diverge. Log correlation across hosts becomes useless when timestamps drift. chrony is the NTP implementation recommended by most major distributions today — it converges faster than the classic ntpd, handles intermittent connectivity gracefully, and since version 4.0 supports Network Time Security (NTS), which authenticates time sources over TLS so you cannot be tricked into accepting spoofed time.

Why Time Matters for Security

Three specific failure modes justify treating time synchronization as a security control rather than a housekeeping task:

  • Kerberos / GSSAPI authentication — The protocol rejects tickets whose timestamps differ from the server by more than the clockskew tolerance, typically 300 seconds. A drifting clock locks users out of SSH, NFS, and any Kerberos-backed service.
  • TLS/X.509 certificate validation — Both notBefore and notAfter fields are checked against local time. A clock that is weeks behind will reject recently-issued certificates; one that runs ahead will accept already-expired ones.
  • TOTP / OATH one-time passwords — Google Authenticator, FreeOTP, and hardware tokens generate codes against the current epoch. More than 30–90 seconds of drift causes authentication failures.

Plain NTP (UDP/123) has no authentication of the time source itself. An on-path attacker or a compromised public server can shift your clock arbitrarily. NTS wraps NTP inside a TLS 1.3 handshake so the server's identity is verified before any time data is trusted.

Install chrony

Most distributions ship chrony as the default NTP daemon; verify before installing.

Debian / Ubuntu

sudo apt update
sudo apt install -y chrony

Fedora / RHEL 8+ / Rocky / AlmaLinux

sudo dnf install -y chrony

Arch Linux

sudo pacman -S --noconfirm chrony

Check whether systemd-timesyncd is running — it conflicts with chrony:

sudo systemctl disable --now systemd-timesyncd

Configure NTS (Authenticated Time)

The main configuration file is /etc/chrony.conf (or /etc/chrony/chrony.conf on Debian-family systems). Open it and replace or supplement the existing server/pool directives.

Locate the config file

sudo find /etc -name 'chrony.conf' 2>/dev/null

Replace pool/server lines with NTS-enabled sources

The following public servers support NTS. Using three gives chrony enough sources to detect and discard a falseticker.

sudo tee /etc/chrony.conf <<'EOF'
# NTS-enabled sources (TLS-authenticated NTP)
server time.cloudflare.com iburst nts
server nts.netnod.se       iburst nts
server ptbtime1.ptb.de     iburst nts

# Fall back to unauthenticated if NTS fails (remove if strict auth required)
# pool pool.ntp.org iburst

# Store NTS keys/cookies between restarts
ntsserverkey  /etc/chrony/nts.key
ntsservercert /etc/chrony/nts.crt

# Record drift for faster convergence after reboot
driftfile /var/lib/chrony/drift

# Step the clock on the first four updates only;
# slew afterwards to avoid disrupting running services
makestep 1.0 3

# Log tracking, measurements, and statistics
logdir /var/log/chrony
log tracking measurements statistics

# Allow chronyc queries only from localhost
bindcmdaddress 127.0.0.1
bindcmdaddress ::1
cmdallow 127.0.0.1

# Harden: deny all NTP client queries (this host is not a server)
denyntp all
EOF

Note: The ntsserverkey / ntsservercert lines are only needed if this host will serve time to other hosts over NTS. For a pure client, remove those two lines. Also remove denyntp all if you intend to serve time on your LAN.

Enable and Start chrony

sudo systemctl enable --now chronyd

On Debian/Ubuntu the unit is also called chronyd; confirm with systemctl status chronyd. Give it 30–60 seconds to perform the initial NTS handshake and take its first measurements.

Verify NTS Authentication and Sync Status

Check source activity

chronyc sources -v

You will see output similar to (will vary):

# Realistic abbreviated example — your offsets and reach will differ
MS Name/IP address        Stratum Poll Reach LastRx Last sample
^* time.cloudflare.com         3   6   377    42   +0.8ms[+1.1ms] +/-  12ms
^+ nts.netnod.se               1   6   377    43   +1.2ms[+1.4ms] +/-  28ms
^+ ptbtime1.ptb.de             1   6   377    44   -0.5ms[-0.3ms] +/-  19ms

The ^* prefix means the source is selected. Reach of 377 (octal) means all eight recent polls succeeded.

Confirm NTS is active

chronyc authdata

Each NTS-authenticated source shows NTS in the Mode column and a non-zero key ID. A blank or - means authentication is not in use for that source — recheck your config or firewall (NTS uses TCP/4460 for the key exchange).

Inspect tracking statistics

chronyc tracking

Key fields to read: System time (current offset from best source), RMS offset (rolling average), and Frequency (clock drift rate in ppm). A healthy desktop or server typically shows system time offset under 10 ms and drift under ±50 ppm.

Monitor Drift Over Time

chrony writes a drift file so it can pre-correct the clock on next boot. You can also read ongoing statistics from the log files you enabled:

sudo tail -f /var/log/chrony/tracking.log

For systemd-integrated alerting, query the offset programmatically:

chronyc tracking | awk '/System time/ {print $4, $5}'

Wrap this in a cron job or a Prometheus textfile collector if you want drift alerts. A threshold of ±500 ms is a reasonable warning; ±1000 ms should page someone.

Firewall — open NTS key-exchange port

NTS performs its TLS handshake on TCP 4460. Regular NTP time exchange still uses UDP 123. Ensure outbound access on both:

# firewalld (Fedora/RHEL)
sudo firewall-cmd --permanent --add-service=ntp
sudo firewall-cmd --permanent --add-port=4460/tcp
sudo firewall-cmd --reload
# ufw (Ubuntu/Debian)
sudo ufw allow out 123/udp
sudo ufw allow out 4460/tcp

Hardening Checklist

  • Use at least three NTS sources from different operators so a single compromised server cannot skew your clock.
  • Set makestep 1.0 3 (step only on first three adjustments) to prevent large sudden jumps on long-running systems.
  • Remove or comment out any unauthenticated pool lines if your threat model requires guaranteed authentication.
  • Restrict chronyc access to localhost with bindcmdaddress and cmdallow — the control socket can be used to force a time step.
  • On servers that act as internal NTP sources, serve time to LAN clients over NTS by generating a TLS certificate (e.g., via Let's Encrypt or an internal CA) and pointing ntsserverkey/ntsservercert at it.

Troubleshooting

chronyc authdata shows no NTS

TCP 4460 is likely blocked outbound. Verify with sudo ss -tnp | grep chronyd and check your firewall. Also confirm the server hostname resolves — NTS validation depends on matching the TLS certificate to the DNS name.

Sources show low Reach values or question marks

Run journalctl -u chronyd -n 50 to see resolver or TLS errors. Transient DNS failures at startup are common; give chrony two to three minutes after boot before diagnosing further.

Large initial offset causes step rejection

If the clock is more than makestep's threshold off and you have exhausted the initial step count, force a one-time step as root:

sudo chronyc makestep

Conflict with systemd-timesyncd

Both daemons bind UDP 123. If chrony fails to start, confirm timesyncd is fully stopped: systemctl status systemd-timesyncd. On Ubuntu, timedatectl set-ntp false also disables it cleanly.

tested on:Ubuntu 24.04Debian 12Fedora 40Rocky 9

Frequently asked questions

What is the difference between NTP and NTS?
NTP (UDP 123) synchronizes the clock but has no built-in authentication of the time server. NTS wraps NTP inside a TLS 1.3 handshake so the server's identity is cryptographically verified before any time data is accepted.
Can I keep a fallback unauthenticated pool alongside NTS sources?
Yes, chrony will prefer authenticated sources. However, if your security policy requires guaranteed NTS authentication, remove unauthenticated pool lines entirely to prevent silent fallback.
Does chrony replace or conflict with systemd-timesyncd?
Both bind UDP 123, so they cannot run simultaneously. Disable systemd-timesyncd before starting chrony. On Ubuntu, 'timedatectl set-ntp false' handles this cleanly.
How much clock skew will break Kerberos authentication?
The default Kerberos clockskew tolerance is 300 seconds (5 minutes). Exceeding it causes KRB5KRB_AP_ERR_SKEW errors and failed authentication for SSH, NFS, and any GSSAPI service.
How do I serve authenticated time to other hosts on my LAN?
Point ntsserverkey and ntsservercert at a valid TLS certificate for your server's hostname, remove 'denyntp all', and allow inbound TCP 4460 and UDP 123. LAN clients then use 'server yourhost iburst nts' in their chrony.conf.

Related guides