Last updated: 2026-02-11
Chrony NTS Configuration Guide
This guide provides recommended Network Time Security (NTS) settings for chrony. NTS is a cryptographic extension to NTP that authenticates time synchronization using TLS, preventing man-in-the-middle attacks on time data. Chrony has supported NTS since version 4.0.
Prerequisites
- Chrony 4.0 or later (4.1+ recommended; see version notes below). RHEL 8.0--8.3 ships chrony 3.5 (no NTS); upgrade to RHEL 8.4+ for chrony 4.x. SLES 15 SP1--SP3 also ships chrony 3.x.
- GnuTLS or OpenSSL library (chrony's NTS-KE uses TLS 1.3)
- A valid TLS certificate and private key (for server mode)
- Network access to port 4460 (NTS-KE) and port 123 (NTP)
Path note: This guide uses RHEL/CentOS paths (
/etc/chrony.conf). On Debian/Ubuntu, the config file is/etc/chrony/chrony.confand the chrony user/group is_chrony(with underscore) instead ofchrony.
NTS Overview
NTS works in two phases:
- NTS-KE (Key Establishment) -- A TLS 1.3 handshake on port 4460 authenticates the server and establishes shared keys
- NTP with cookies -- Subsequent NTP packets on port 123 carry encrypted cookies and authentication extensions derived from the NTS-KE session
Client Configuration
Basic NTS Client
Enable NTS for upstream time servers by adding the nts keyword:
# /etc/chrony.conf
server time.cloudflare.com iburst nts
server nts.netnod.se iburst nts
server ptbtime1.ptb.de iburst nts
server ntppool1.time.nl iburst nts
NTS-KE Port
If a server uses a non-standard NTS-KE port:
server nts.example.com iburst nts ntsport 4461
Certificate Trust Store
Chrony uses the system trust store by default. To specify a custom CA bundle:
# RHEL/CentOS:
ntstrustedcerts /etc/pki/tls/certs/ca-bundle.crt
# Debian/Ubuntu: /etc/ssl/certs/ca-certificates.crt
# SLES: /etc/ssl/ca-bundle.pem
NTS Cookie Storage
Persist NTS cookies across restarts to avoid repeated NTS-KE handshakes:
ntsdumpdir /var/lib/chrony
Rate Limiting NTS-KE
Limit how often chrony retries NTS-KE on failure:
ntsrefresh 86400
Version note:
ntsrefreshrequires chrony 4.1+. On chrony 4.0 (Debian 11), omit this directive.
This sets the maximum interval (in seconds) between NTS-KE requests to a server.
Server Configuration
NTS-KE Server
Configure chrony as an NTS-capable NTP server:
# /etc/chrony.conf
# NTS-KE server settings
ntsserverkey /etc/chrony/ssl/privkey.pem
ntsservercert /etc/chrony/ssl/fullchain.pem
The certificate must be valid for the server's hostname. Let's Encrypt certificates work well.
NTS-KE Port
By default, chrony listens on port 4460 for NTS-KE. To change it:
ntsport 4460
Key Rotation
NTS uses server cookies encrypted with a key that chrony rotates automatically. Persist the keys across restarts:
ntsdumpdir /var/lib/chrony
Chrony generates new cookie keys automatically and retains old keys long enough for clients to transition.
NTS Process Separation
For security, run the NTS-KE helper as a separate unprivileged process:
ntsprocesses 1
Version note:
ntsprocessesrequires chrony 4.1+. On chrony 4.0 (Debian 11), omit this directive — NTS-KE will run in the main process instead.
Complete Client Configuration
# /etc/chrony.conf
# NTS-authenticated time sources
server time.cloudflare.com iburst nts
server nts.netnod.se iburst nts
server ptbtime1.ptb.de iburst nts
server ntppool1.time.nl iburst nts
# Fallback (unauthenticated) sources
pool pool.ntp.org iburst maxsources 2
# NTS cookie storage
ntsdumpdir /var/lib/chrony
# Allow system clock to be stepped on first sync
makestep 1.0 3
# Record tracking data
driftfile /var/lib/chrony/drift
# RTC synchronization
rtcsync
# Logging
logdir /var/log/chrony
log measurements statistics tracking
Complete Server Configuration
# /etc/chrony.conf
# Upstream NTS sources
server time.cloudflare.com iburst nts
server nts.netnod.se iburst nts
# NTS server settings
ntsserverkey /etc/chrony/ssl/privkey.pem
ntsservercert /etc/chrony/ssl/fullchain.pem
ntsprocesses 1
ntsdumpdir /var/lib/chrony
# Serve time to clients
allow 10.0.0.0/8
allow 172.16.0.0/12
allow 192.168.0.0/16
# Serve as stratum 2 if upstream sources are lost
local stratum 2
# System clock
makestep 1.0 3
driftfile /var/lib/chrony/drift
rtcsync
# Rate limiting
ratelimit interval 1 burst 16
# Logging
logdir /var/log/chrony
log measurements statistics tracking
Certificate Management
Using Let's Encrypt with Certbot
certbot certonly --standalone -d ntp.example.com
Configure chrony to use the certificates:
ntsserverkey /etc/letsencrypt/live/ntp.example.com/privkey.pem
ntsservercert /etc/letsencrypt/live/ntp.example.com/fullchain.pem
Chrony automatically detects certificate file changes and reloads them without restart, which works well with certbot's automatic renewal.
File Permissions
Ensure chrony can read the private key:
chown root:chrony /etc/chrony/ssl/privkey.pem # Debian/Ubuntu: chown root:_chrony
chmod 640 /etc/chrony/ssl/privkey.pem
Firewall
Open the required ports:
# NTS-KE (TLS 1.3 key establishment)
firewall-cmd --permanent --add-port=4460/tcp
# NTP (time synchronization)
firewall-cmd --permanent --add-service=ntp
firewall-cmd --reload
Verification
Check NTS status for all sources:
chronyc -N authdata
You should see NTS in the Mode column and a non-zero cookie count:
Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen
================================================================
time.cloudflare> NTS 1 15 256 33m 0 0 8 100
nts.netnod.se NTS 1 15 256 33m 0 0 8 100
Check NTS-KE connection details:
chronyc ntpdata time.cloudflare.com
Verify the NTS-KE handshake uses TLS 1.3:
gnutls-cli --port 4460 time.cloudflare.com < /dev/null
Check overall time synchronization:
chronyc tracking
chronyc sources -v