Configure Linux system time synchronization with chrony and NTP hardening

Intermediate 25 min Apr 03, 2026 16 views
Ubuntu 24.04 Ubuntu 22.04 Debian 12 AlmaLinux 9 Rocky Linux 9 Fedora 41

Set up reliable time synchronization with chrony NTP client, configure secure time servers, and implement monitoring to prevent time drift on production servers.

Prerequisites

  • Root or sudo access
  • Internet connectivity for NTP synchronization
  • Basic familiarity with systemd services

What this solves

Accurate system time is critical for security protocols, log correlation, database transactions, and distributed systems. This tutorial configures chrony as your NTP client with hardened security settings, multiple time sources for redundancy, and monitoring to detect time drift before it impacts your applications.

Step-by-step installation

Update system packages

Start by updating your package manager to ensure you get the latest versions and security patches.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Install chrony NTP client

Chrony is a modern NTP implementation that handles intermittent network connections better than traditional ntpd. It's the default time synchronization service on most modern Linux distributions.

sudo apt install -y chrony
sudo dnf install -y chrony

Stop and disable conflicting time services

Remove systemd-timesyncd and ntp if they're running to prevent conflicts with chrony. Only one time synchronization service should be active.

sudo systemctl stop systemd-timesyncd ntp 2>/dev/null || true
sudo systemctl disable systemd-timesyncd ntp 2>/dev/null || true
sudo systemctl mask systemd-timesyncd

Configure chrony with secure NTP pools

Create a hardened chrony configuration with multiple time sources and security settings. This configuration uses geographically distributed NTP pools for better accuracy and redundancy.

# Use multiple NTP pool sources for redundancy
pool 0.pool.ntp.org iburst maxsources 4
pool 1.pool.ntp.org iburst maxsources 4
pool 2.pool.ntp.org iburst maxsources 4
pool 3.pool.ntp.org iburst maxsources 4

Add public time servers as backup

server time.cloudflare.com iburst server time.google.com iburst

Record the rate at which the system clock gains/losses time

driftfile /var/lib/chrony/drift

Allow the system clock to be stepped in the first three updates

if its offset is larger than 1 second

makestep 1.0 3

Enable kernel synchronization of the real-time clock (RTC)

rtcsync

Enable hardware timestamping on all interfaces that support it

#hwtimestamp *

Increase the minimum number of selectable sources required to adjust

the system clock

minsources 2

Allow NTP client access from local network only

Uncomment and modify for your network if this server will serve time

#allow 192.168.1.0/24

Serve time even if not synchronized to a time source

#local stratum 10

Specify file containing keys for NTP authentication

#keyfile /etc/chrony/chrony.keys

Save NTP measurements and estimates

logdir /var/log/chrony

Select which information is logged

log measurements statistics tracking

Disable command port for security (uncomment for production)

cmdport 0

Step the system clock instead of slewing it if the adjustment is larger than

one second, but only in the first clockupdate

maxupdateskew 100.0

Ignore leap second for virtual machines

leapsectz right/UTC

Set correct file permissions

Secure the chrony configuration file to prevent unauthorized modifications. Only root should be able to modify time synchronization settings.

sudo chown root:root /etc/chrony/chrony.conf
sudo chmod 644 /etc/chrony/chrony.conf
sudo chown -R _chrony:_chrony /var/lib/chrony 2>/dev/null || sudo chown -R chrony:chrony /var/lib/chrony

Configure hardware clock synchronization

Ensure the hardware clock (RTC) stays synchronized with the system clock. This prevents time drift when the system reboots.

sudo hwclock --systohc
sudo timedatectl set-local-rtc 0

Enable and start chrony service

Enable chrony to start automatically at boot and start it immediately. The service will begin synchronizing time with the configured NTP servers.

sudo systemctl enable chrony
sudo systemctl start chrony
sudo systemctl status chrony

Configure timezone settings

Set your system timezone and verify that automatic time synchronization is enabled through timedatectl.

sudo timedatectl set-timezone UTC
sudo timedatectl set-ntp true
timedatectl status
Note: Replace UTC with your preferred timezone like America/New_York or Europe/London. Use timedatectl list-timezones to see available options.

Create chrony monitoring script

Set up automated monitoring to detect time synchronization issues and excessive drift before they impact your applications.

#!/bin/bash

Chrony monitoring script

Checks time synchronization status and drift

LOG_FILE="/var/log/chrony-monitor.log" MAX_OFFSET_MS=100 MAX_DRIFT_PPM=10

Function to log messages

log_message() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | sudo tee -a "$LOG_FILE" }

Check if chrony is running

if ! systemctl is-active --quiet chrony; then log_message "ERROR: Chrony service is not running" exit 1 fi

Get chrony tracking information

TRACKING=$(chronyc tracking 2>/dev/null) if [ $? -ne 0 ]; then log_message "ERROR: Unable to get chrony tracking information" exit 1 fi

Extract values

SYSTEM_TIME=$(echo "$TRACKING" | grep "System time" | awk '{print $4}') LAST_OFFSET=$(echo "$TRACKING" | grep "Last offset" | awk '{print $3}' | tr -d 's') FREQ_OFFSET=$(echo "$TRACKING" | grep "Frequency" | awk '{print $2}' | tr -d 'ppm')

Convert offset to milliseconds for comparison

OFFSET_MS=$(echo "$LAST_OFFSET * 1000" | bc 2>/dev/null || echo "0") OFFSET_ABS=$(echo "$OFFSET_MS" | sed 's/-//')

Check offset threshold

if (( $(echo "$OFFSET_ABS > $MAX_OFFSET_MS" | bc -l) )); then log_message "WARNING: Time offset is ${OFFSET_MS}ms (threshold: ${MAX_OFFSET_MS}ms)" fi

Check frequency drift threshold

DRIFT_ABS=$(echo "$FREQ_OFFSET" | sed 's/-//') if (( $(echo "$DRIFT_ABS > $MAX_DRIFT_PPM" | bc -l) )); then log_message "WARNING: Frequency drift is ${FREQ_OFFSET}ppm (threshold: ${MAX_DRIFT_PPM}ppm)" fi

Check source availability

SOURCES=$(chronyc sources 2>/dev/null | grep -c "^\^\*") if [ "$SOURCES" -eq 0 ]; then log_message "WARNING: No active time sources available" fi log_message "INFO: Offset: ${OFFSET_MS}ms, Drift: ${FREQ_OFFSET}ppm, Active sources: $SOURCES"

Make monitoring script executable and create systemd timer

Set up the monitoring script to run automatically every 15 minutes using systemd timers.

sudo chmod 755 /usr/local/bin/chrony-monitor.sh
sudo chown root:root /usr/local/bin/chrony-monitor.sh
[Unit]
Description=Chrony Time Synchronization Monitor
After=chrony.service
Requires=chrony.service

[Service]
Type=oneshot
User=root
ExecStart=/usr/local/bin/chrony-monitor.sh
StandardOutput=journal
StandardError=journal
[Unit]
Description=Run Chrony Monitor every 15 minutes
Requires=chrony-monitor.service

[Timer]
OnBootSec=5min
OnUnitActiveSec=15min
Persistent=true

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable chrony-monitor.timer
sudo systemctl start chrony-monitor.timer

Configure log rotation for chrony logs

Set up log rotation to prevent chrony logs from consuming excessive disk space over time.

/var/log/chrony/*.log {
    daily
    missingok
    rotate 52
    compress
    delaycompress
    sharedscripts
    create 640 _chrony _chrony
    postrotate
        /bin/kill -HUP cat /var/run/chrony/chronyd.pid 2>/dev/null 2>/dev/null || true
    endscript
}

/var/log/chrony-monitor.log {
    weekly
    missingok
    rotate 12
    compress
    delaycompress
    create 640 root root
}

Advanced security hardening

Disable chrony command port for production

For maximum security on production servers, disable the chrony command port to prevent unauthorized time adjustments.

sudo sed -i '/^#cmdport 0/s/^#//' /etc/chrony/chrony.conf
sudo systemctl restart chrony
Warning: After disabling cmdport, you won't be able to use chronyc commands. Only do this on production servers where remote management isn't needed.

Configure firewall rules for NTP

If your server needs to serve time to other systems, configure firewall rules to allow NTP traffic securely.

# Allow outgoing NTP traffic (client mode)
sudo ufw allow out 123/udp comment 'NTP client'

Allow incoming NTP from local network only (server mode)

Uncomment and modify for your network if serving time

sudo ufw allow from 192.168.1.0/24 to any port 123 comment 'NTP server local'

Verify your setup

Check that chrony is working correctly and synchronizing time with multiple sources.

sudo systemctl status chrony
chronyc tracking
chronyc sources -v
chronyc sourcestats
timedatectl status
sudo journalctl -u chrony --no-pager -n 20

Run the monitoring script manually to test it:

sudo /usr/local/bin/chrony-monitor.sh
sudo tail -f /var/log/chrony-monitor.log

The output should show your system is synchronized with multiple NTP sources. Look for an asterisk (*) next to the currently selected source in the sources output.

Monitor time synchronization health

Key metrics to monitor

Monitor these chrony metrics to ensure healthy time synchronization in production environments.

MetricCommandGood Value
Time offsetchronyc tracking | grep "Last offset"< 100ms
Frequency driftchronyc tracking | grep "Frequency"< 10ppm
Active sourceschronyc sources | grep "^\^\*">= 1
Stratum levelchronyc tracking | grep "Stratum"2-4

Set up email alerts for time issues

Configure the monitoring script to send email alerts when time synchronization problems are detected.

sudo apt install -y mailutils

Add email alerting to the monitoring script:

sudo sed -i '/log_message "ERROR:/a\n    echo "$1" | mail -s "Chrony Alert on $(hostname)" admin@example.com' /usr/local/bin/chrony-monitor.sh
sudo sed -i '/log_message "WARNING:/a\n    echo "$1" | mail -s "Chrony Warning on $(hostname)" admin@example.com' /usr/local/bin/chrony-monitor.sh

Common issues

SymptomCauseFix
chronyc commands failCommand port disabledRemove cmdport 0 from config or use systemctl status chrony
No sources availableFirewall blocking NTPsudo ufw allow out 123/udp
Time not synchronizingLarge initial offsetsudo chrony -q then restart service
High frequency driftFailing hardware clockCheck hardware, increase maxupdateskew
Service fails to startConfiguration syntax errorsudo chronyd -n -d to debug
Permission denied on logsWrong log directory ownershipsudo chown -R _chrony:_chrony /var/log/chrony

Next steps

Automated install script

Run this to automate the entire setup

#chrony #ntp #time synchronization #system clock #hardware clock #time drift

Need help?

Don't want to manage this yourself?

We handle infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.

Talk to an engineer