Ubuntu is switching its default time synchronization tool. Three days ago, Canonical announced that ntpd-rs Linux NTP server — a Rust rewrite of the Network Time Protocol daemon — will replace chrony, linuxptp, and gpsd across Ubuntu releases starting with Ubuntu 26.10. Beyond that announcement, Canonical committed 40,000 euros per year to the Trifecta Tech Foundation, the non-profit behind ntpd-rs, to accelerate its development. This follows the same Rust-first strategy that already replaced classic sudo with sudo-rs on Ubuntu. For sysadmins, the practical questions are: what does ntpd-rs actually offer over chrony, how do you install and configure it today on any Linux distribution, and what does this change mean for your existing NTP setup? This post answers all three.

Why Ubuntu Is Replacing chrony with ntpd-rs
chrony is a solid, battle-tested NTP implementation that has served Linux well since Red Hat adopted it as the default on RHEL 8. So why replace it? The answer is memory safety. Because chrony is written in C, it carries the same class of memory vulnerability risk that has driven CVEs across the Linux stack for decades. ntpd-rs is written in Rust, which eliminates buffer overflows, use-after-free bugs, and data races at the language level — by construction, not by careful coding.
Since NTP is a network-facing service that runs as a privileged daemon on every server, memory safety matters more than it might for an offline utility. A vulnerability in a time daemon is a remote attack surface on every Linux host in your fleet. According to OMG Ubuntu’s announcement, Canonical VP of Engineering Jon Seager explicitly cited memory safety as the primary driver. The ntpd-rs adoption fits into the broader pattern of replacing C-based system daemons with Rust equivalents wherever practical.
Beyond memory safety, ntpd-rs also ships Network Time Security (NTS) support as a first-class feature. NTS is a TLS 1.3-based authentication layer for NTP that prevents spoofing and tampering. Without NTS, an attacker on the network can manipulate time synchronization to break Kerberos, invalidate TLS certificates, or corrupt distributed system logs. While chrony supports NTS since version 4.0, enabling it requires several manual configuration steps. In ntpd-rs, by contrast, NTS requires only a single line change in the config.
ntpd-rs vs chrony: Feature Comparison
Before deciding whether to migrate now or wait for Ubuntu 27.04, understanding what each tool offers helps frame the decision clearly:
| Feature | ntpd-rs | chrony |
|---|---|---|
| Language | Rust (memory safe) | C |
| NTS support | Built-in, one line | Available since v4.0, manual setup |
| Config format | TOML | Custom chrony.conf syntax |
| Prometheus metrics | Built-in on port 9975 | Requires separate chrony_exporter |
| Hardware refclock | Limited (GPS/PPS via SHM) | Full (GPS, PPS, PTP, NMEA) |
| VM clock recovery | Supported | Excellent (long track record) |
| Production maturity | v1.4 stable since 2024 | Very mature, 15+ years |
| Default on distros | Ubuntu 27.04 (planned) | RHEL 8+, Fedora, current Ubuntu |
The practical takeaway: ntpd-rs is the right choice for new deployments where memory safety and built-in observability matter most. For existing RHEL or AlmaLinux environments, chrony remains the supported default and there is no pressure to migrate immediately. For Ubuntu shops planning ahead, however, getting familiar with ntpd-rs now means the 27.04 transition is smooth rather than disruptive.

How to Install ntpd-rs on Linux Today
ntpd-rs is not yet in most distribution package managers by default, but you can install it now from the official GitHub releases. Since it ships as a self-contained binary, there is no dependency chain to manage.
Install on Ubuntu / Debian
# Get the latest version tag
NTPRS_VER=$(curl -s https://api.github.com/repos/pendulum-project/ntpd-rs/releases/latest \
| grep tag_name | cut -d'"' -f4)
echo 'Latest: '$NTPRS_VER
curl -fsSL \
https://github.com/pendulum-project/ntpd-rs/releases/download/${NTPRS_VER}/ntpd-rs_${NTPRS_VER#v}_amd64.deb \
-o /tmp/ntpd-rs.deb
dpkg -i /tmp/ntpd-rs.deb
ntpd-rs --version
# Stop chrony before starting ntpd-rs
systemctl stop chrony chronyd 2>/dev/null
systemctl disable chrony chronyd 2>/dev/null
Install on RHEL / AlmaLinux / Rocky
NTPRS_VER=$(curl -s https://api.github.com/repos/pendulum-project/ntpd-rs/releases/latest \
| grep tag_name | cut -d'"' -f4)
curl -fsSL \
https://github.com/pendulum-project/ntpd-rs/releases/download/${NTPRS_VER}/ntpd-rs-${NTPRS_VER#v}-1.x86_64.rpm \
-o /tmp/ntpd-rs.rpm
rpm -ivh /tmp/ntpd-rs.rpm
ntpd-rs --version
systemctl stop chronyd
systemctl disable chronyd
Install via Cargo (all distros)
# Requires Rust toolchain
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source $HOME/.cargo/env
cargo install ntpd-rs
ntpd-rs --version
Configure ntpd-rs as an NTP Client
ntpd-rs uses TOML for its configuration, which lives at /etc/ntpd-rs/ntp.toml. Here is a production-ready client configuration using NTS-authenticated time sources:
mkdir -p /etc/ntpd-rs
cat > /etc/ntpd-rs/ntp.toml << 'NTPEOF'
[synchronization]
single-step-panic-threshold = { forward = "1s", backward = "1s" }
# NTS-authenticated sources (TLS 1.3 protected)
[[source]]
mode = "nts"
address = "time.cloudflare.com"
[[source]]
mode = "nts"
address = "oregon.time.system76.com"
# Plain NTP fallback pool
[[source]]
mode = "pool"
address = "pool.ntp.org"
count = 4
# Built-in Prometheus metrics on port 9975
[observability]
prometheus-service-port = 9975
NTPEOF
systemctl enable --now ntpd-rs
systemctl status ntpd-rs
# Verify synchronization
ntp-ctl status
ntp-ctl sources

Configure ntpd-rs as an NTP Server
ntpd-rs can also serve time to other hosts on your internal network. This is useful for data centers where internal servers should not make direct outbound NTP queries. After configuring upstream NTS sources, add a server block to start listening:
cat > /etc/ntpd-rs/ntp.toml << 'SRVEOF'
[synchronization]
single-step-panic-threshold = { forward = "1s", backward = "1s" }
[[source]]
mode = "nts"
address = "time.cloudflare.com"
[[source]]
mode = "nts"
address = "ptbtime1.ptb.de"
[[source]]
mode = "pool"
address = "pool.ntp.org"
count = 4
# Listen on all interfaces and serve to local network
[[server]]
listen = "0.0.0.0:123"
[observability]
prometheus-service-port = 9975
SRVEOF
# Open firewall for NTP
firewall-cmd --permanent --add-service=ntp && firewall-cmd --reload
systemctl restart ntpd-rs
ss -ulnp | grep 123
ntp-ctl server-stats
Why NTS Changes the Security Equation
NTS is the most important feature ntpd-rs brings to the table, and it deserves more attention than it typically receives. Without NTS, plain NTP uses UDP with no authentication. Because of that, an attacker who can intercept traffic between your server and its time source can gradually shift your system clock in either direction. NTS closes that attack surface by requiring TLS-authenticated key exchange before any time data is trusted.
The practical consequences of a successful NTP attack are severe. Kerberos authentication rejects tickets when clock skew exceeds five minutes — so a gradual clock attack silently breaks authentication across an entire AD-integrated fleet. TLS certificates fail when system clocks drift outside validity windows. Distributed systems like Kafka, Cassandra, and etcd produce corrupted logs when clocks across nodes diverge significantly. Since ntpd-rs makes NTS trivially easy to enable, there is no longer a good reason to run unauthenticated NTP on production servers.
# Confirm NTS authentication is working after startup
ntp-ctl sources
# Protocol column shows 'nts' for authenticated sources
ntp-ctl sources -v 2>/dev/null | grep -E 'nts|NTS|auth'
# Check overall sync status
timedatectl status
# System clock synchronized: yes confirms ntpd-rs is managing the clock

Built-in Prometheus Monitoring
One of the most practical advantages ntpd-rs has over chrony is native observability. While chrony requires a separate chrony_exporter binary, ntpd-rs serves Prometheus metrics directly from a built-in HTTP endpoint. After enabling the observability block in your config, connect your scraper immediately:
# Confirm the metrics endpoint is live
curl -s http://localhost:9975/metrics | head -30
# Key metrics to monitor:
# ntpd_rs_system_poll_interval -- current poll interval in seconds
# ntpd_rs_system_accumulated_steps -- number of clock steps taken
# ntpd_rs_source_offset_seconds -- time offset per source
# ntpd_rs_source_uncertainty_seconds -- measurement uncertainty per source
# Prometheus scrape config entry:
# - job_name: ntpd-rs
# static_configs:
# - targets: ['localhost:9975']
# Check sync status via ntp-ctl directly
ntp-ctl status
ntp-ctl sources
ntp-ctl peers 2>/dev/null
Migrating from chrony to ntpd-rs
Because only one NTP service should manage the system clock at a time, migration requires stopping chrony before starting ntpd-rs. The process is clean and reversible at any point:
# Step 1: Document current chrony state before changing anything
chronyc tracking
chronyc sources -v
grep -E '^server|^pool' /etc/chrony.conf 2>/dev/null \
|| grep -E '^server|^pool' /etc/chrony/chrony.conf 2>/dev/null
# Step 2: Install ntpd-rs (see steps above)
# Step 3: Create ntpd-rs config using your existing NTP server addresses
# Replace the pool.ntp.org entries with your internal servers if applicable
# Step 4: Stop and disable chrony
systemctl stop chronyd chrony 2>/dev/null
systemctl disable chronyd chrony 2>/dev/null
# Step 5: Start ntpd-rs
systemctl enable --now ntpd-rs
# Step 6: Confirm synchronization is working
ntp-ctl status
timedatectl status
# System clock synchronized: yes means ntpd-rs is active
# To roll back at any point:
systemctl stop ntpd-rs
systemctl disable ntpd-rs
systemctl enable --now chronyd
Deploy ntpd-rs Fleet-Wide with Ansible
For teams managing multiple servers, use Ansible to roll out ntpd-rs consistently. Our Ansible automation guide covers the broader setup, but here is a focused playbook for ntpd-rs deployment:
---
- name: Deploy ntpd-rs NTP daemon
hosts: all
become: true
vars:
ntpd_rs_version: "v1.4.0"
nts_sources:
- "time.cloudflare.com"
- "oregon.time.system76.com"
tasks:
- name: Stop and disable chrony
systemd:
name: "{{ item }}"
state: stopped
enabled: false
loop: [chronyd, chrony]
ignore_errors: true
- name: Download ntpd-rs deb (Debian/Ubuntu)
get_url:
url: "https://github.com/pendulum-project/ntpd-rs/releases/download/{{ ntpd_rs_version }}/ntpd-rs_{{ ntpd_rs_version[1:] }}_amd64.deb"
dest: /tmp/ntpd-rs.deb
when: ansible_os_family == 'Debian'
- name: Install ntpd-rs (Debian/Ubuntu)
apt:
deb: /tmp/ntpd-rs.deb
when: ansible_os_family == 'Debian'
- name: Create config directory
file:
path: /etc/ntpd-rs
state: directory
mode: '0755'
- name: Deploy ntpd-rs config
template:
src: ntp.toml.j2
dest: /etc/ntpd-rs/ntp.toml
mode: '0644'
notify: restart ntpd-rs
- name: Enable and start ntpd-rs
systemd:
name: ntpd-rs
state: started
enabled: true
- name: Verify sync
command: ntp-ctl status
register: ntp_status
changed_when: false
- name: Report status
debug:
msg: "{{ inventory_hostname }}: {{ ntp_status.stdout_lines[0] }}"
handlers:
- name: restart ntpd-rs
systemd:
name: ntpd-rs
state: restarted

Why Time Synchronization Security Matters More Than Most Realize
NTP is one of those infrastructure components that runs invisibly until it breaks spectacularly. Because Kerberos authentication rejects tickets with a clock skew greater than five minutes, a successful NTP spoofing attack against an Active Directory-integrated Linux server can break all authentication silently and completely. Beyond that, SSL/TLS certificates fail when system clocks drift outside their validity windows, and distributed systems like Kafka, Cassandra, and etcd produce corrupted logs when node clocks diverge significantly.
Plain NTP without NTS is vulnerable to on-path attackers who can inject false time packets. Since NTP uses UDP with no authentication by default, an attacker who can intercept traffic between your server and its time source can gradually shift your system clock in either direction without triggering any alert. NTS closes that attack surface completely by requiring TLS-authenticated key exchange before any time data is accepted. Combined with Rust memory safety in ntpd-rs, this makes it a meaningfully more secure foundation than plain chrony without NTS. Our Linux server hardening checklist includes NTP authentication as a baseline configuration item — ntpd-rs with NTS is the cleanest way to satisfy that requirement.
Conclusion
ntpd-rs Linux NTP server is no longer just a promising Rust project. It is now Ubuntu's official future default, backed by Canonical's direct funding. For sysadmins, the practical steps are clear: install from the GitHub releases page, write a TOML config pointing at NTS-capable time sources, stop chrony, and start ntpd-rs. After that, verify with ntp-ctl status and connect your Prometheus scraper to port 9975 for built-in metrics with no extra tooling required. For Ubuntu shops specifically, getting familiar with ntpd-rs today means the Ubuntu 26.10 and 27.04 transitions require no emergency work. For RHEL and AlmaLinux environments, chrony remains the supported default and there is no pressure to migrate immediately — but ntpd-rs is worth evaluating wherever NTS authentication and Rust memory safety are explicit security requirements. The full Canonical announcement is at OMG Ubuntu, and the technical background is covered at Phoronix.