How to Debug NTS Connection Problems with chrony or ntpd-rs
Debug NTS connection problems by verifying DNS resolution, testing UDP/TCP connectivity, validating configuration syntax in chrony.conf or ntp.toml, and using verbose logging to isolate TLS handshake and certificate failures.
The jauderho/nts-servers repository maintains a curated list of Network Time Security (NTS) capable NTP servers, but clients like chrony and ntpd-rs can fail to connect due to DNS misconfiguration, firewall rules, or certificate issues. Understanding how to debug NTS connection problems requires a systematic approach across the network stack, from basic connectivity tests to deep TLS handshake inspection. This guide walks through the exact commands, configuration files, and verification scripts provided in the repository to diagnose and resolve connection failures.
Verify DNS and Network Connectivity First
Before debugging NTS-specific protocol issues, confirm that the underlying network path is clear.
Check DNS Resolution
NTS failures often stem from hostname resolution problems. Use standard DNS tools to verify the server resolves correctly:
dig +short time.cloudflare.com
host time.cloudflare.com
If these commands return no IP addresses, the issue lies with your local resolver or the server's DNS records, not the NTS implementation.
Test UDP Port 123
Chrony uses UDP port 123 for NTP traffic. Verify basic reachability with netcat:
nc -vz -u time.cloudflare.com 123
A Connection timed out error indicates that firewalls, NAT rules, or routing problems are blocking UDP traffic before it reaches the NTS server.
Validate Configuration Files
NTS requires explicit configuration keywords that differ between chrony and ntpd-rs.
Inspect chrony.conf
The repository provides chrony.conf, which lists servers with the nts keyword required to enable NTS. According to the source analysis, each server entry must include the nts flag:
# Example entry in chrony.conf
server time.cloudflare.com iburst nts
Missing the nts keyword causes chrony to attempt standard NTP authentication rather than NTS, resulting in connection failures or "NTS not supported" errors.
Inspect ntp.toml
For ntpd-rs, the repository generates ntp.toml from the same source list. This TOML configuration file contains the server definitions used by the Rust daemon. Verify that your local copy matches the repository version, as the file is kept up-to-date via scripts/ntpServerConverter.py processing nts-sources.yml.
Test NTS Connections with Command-Line Tools
The repository includes purpose-built scripts to test NTS functionality without modifying your system configuration.
Single-Shot Tests Using chronyd
The scripts/ntsCheck.sh file provides a wrapper around chrony's built-in NTS client. It executes:
chronyd -Q -t 5 "server time.cloudflare.com iburst nts maxsamples 1"
Run the script directly to test any server:
./scripts/ntsCheck.sh time.cloudflare.com
The -Q flag performs a one-shot query and exits, printing specific error messages such as NTS handshake successful, NTS not supported, or Network unreachable directly to the terminal.
Batch Verification with verifyNTSServers.py
To test the entire server list at once, use the Python verification script which processes nts-sources.yml:
python3 scripts/verifyNTSServers.py nts-sources.yml
As implemented in scripts/verifyNTSServers.py, the script extracts hostnames from the YAML file (handling both plain text and markdown links) and runs the same chronyd query for every entry. Output is grouped into Good and Failed sections, making it easy to identify problematic servers across the entire list.
Enable Verbose Logging for TLS and NTS Handshake Debugging
When basic connectivity tests fail, verbose logging reveals whether the problem occurs during the TLS handshake or the NTS extension negotiation.
Debug chrony with Foreground Mode
Start chrony in debug mode to view protocol-level details:
sudo chronyd -d -q -n -f chrony.conf
Key flags explained:
-denables debug output showing TLS and NTS protocol steps-qquits after the first successful poll-nruns in the foreground without daemonizing
Watch the output for specific error patterns:
NTS: TLS handshake failed (error 0x80000000)indicates certificate or TLS version issuesNTS: Server does not support NTS extensionmeans the server offers HTTPS but lacks the NTS-KE (Network Time Security Key Establishment) service
Debug ntpd-rs with RUST_LOG
For the Rust implementation, enable debug tracing via environment variables:
RUST_LOG=debug ntpd-rs -c ntp.toml -n
The debug log includes entries such as:
[DEBUG ntpd_rs::nts] TLS handshake completed, NTS ready
[ERROR ntpd_rs::nts] NTS handshake failed: certificate verification error
If you encounter certificate verification error, update your system's CA certificate bundle (update-ca-certificates on Debian/Ubuntu systems) to ensure the client recognizes the server's certificate authority.
Cross-Check with Legacy NTP Tools
Although NTS uses TCP/443 for the initial handshake, the underlying time synchronization relies on UDP/123. Verify basic NTP functionality to isolate transport layer issues:
ntpdate -q time.cloudflare.com
ntpq -p time.cloudflare.com
Success here confirms that UDP traffic flows correctly; failure usually indicates network blocking rather than NTS-specific configuration problems.
Summary
Debugging NTS connections requires methodical verification across multiple layers:
- Use
digandncto confirm DNS resolution and UDP connectivity before troubleshooting NTS protocols - Reference
chrony.confandntp.tomlto ensure the nts keyword or equivalent configuration is present - Run
scripts/ntsCheck.shfor quick single-server tests usingchronyd -Q - Execute
scripts/verifyNTSServers.pyagainstnts-sources.ymlto batch-check the entire curated list - Enable
chronyd -dorRUST_LOG=debugto inspect TLS handshake details and certificate validation - Update system CA bundles when
ntpd-rsreports certificate verification errors
Frequently Asked Questions
Why does chrony report "NTS handshake failed"?
This error typically indicates a TLS layer problem, such as an expired server certificate, unsupported TLS version, or missing intermediate certificates. Run sudo chronyd -d -q to view the specific TLS error code. If the server uses a modern certificate chain, ensure your system's CA certificates are current by running update-ca-certificates.
How do I test if my firewall is blocking NTS traffic?
First, test UDP port 123 with nc -vz -u <hostname> 123. Then test TCP port 443 (used for the NTS-KE handshake) with nc -vz <hostname> 443. If the UDP test fails but TCP succeeds, your firewall is likely blocking standard NTP traffic while allowing HTTPS. Both protocols must be open for NTS to function.
What's the difference between the chrony.conf and ntp.toml files in the repository?
Both files contain the same curated server list from nts-sources.yml, but chrony.conf uses chrony's native configuration syntax with the server and nts keywords, while ntp.toml uses TOML format required by ntpd-rs. The repository keeps both synchronized via scripts/ntpServerConverter.py, which regenerates the files whenever nts-sources.yml is updated.
Can I use verifyNTSServers.py to test custom NTS servers?
Yes, the script accepts any YAML file following the nts-sources.yml structure. Create a file listing your custom hostnames and run python3 scripts/verifyNTSServers.py your-file.yml. The script will attempt NTS handshakes with each entry using the same chronyd -Q command used for the official repository list.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →