home June 06, 2019

Chrony Network Time Server


a FreeBSD install of chronyd (ntp)

Chrony is an accurate network time daemon and an alternate implementation of the Network Time Protocol (NTP) compared to ntp.org's NTPd, Ntimed, OpenNTPd and systemd-timesyncd. Chrony can be used to sync with NTP servers, reference clocks (e.g. GPS receiver), and even input by hand for an air-gapped network. The daemon will operate as an NTPv4 (RFC 5905) server and peer providing time service to other computers in the network.

Chrony's typical accuracy when synced over the Internet is normally within a few milliseconds. When Chrony is synced between two(2) machines on a LAN the accuracy is a few hundred microseconds, but when Chrony is paired with a GPS receiver, sub-microsecond accuracy is possible. Chrony's accuracy is significantly better than both NTPd and OpenNTPd.

Chrony has quite a few advantages over the other NTP implementations, check the chrony ntp comparison page for more details.

Methodology

FreeBSD 12 supports Chrony v3.4 which allows privilege separation. We will install Chrony from the FreeBSD package system and configure the daemon to run as the unprivileged user, "chronyd" which is a user available on the default FreeBSD 12 install.

The Chrony daemon running as the "chronyd" user will be configured to be a Network Time Protocol (NTP) server on the local LAN to provide millisecond accuracy to its local clock as well as to the hundreds of clients in the cluster.

Install the Chrony package

pkg install chrony libedit

NOTE: after the package install you may see a warning about insecurities in the Chrony package. This is an older warning from a previous Chrony package which we can safely ignore because we are going to configure Chrony to run as a completely unprivileged user. FreeBSD should really remove this unnecessary alarmist text. Also, if you recieve the error, Shared object "libedit.so.0" not found, required by "chronyc" make sure libedit is installed.

Configuration file: chrony.conf

The chrony configuration file defines the Network Time Protocol (NTP) servers our machine will sync to as well as general daemon options. Our example configuration lists out all stratum one(1) public NTP servers for the highest possible accuracy. Create the configuration file in "/usr/local/etc/chrony.conf" and take a look at the file comments for details. All paths are correct for our FreeBSD install.

root@calomel#  vi /usr/local/etc/chrony.conf

# Chrony for FreeBSD, /usr/local/etc/chrony.conf
# https://moneyslow.com/html/webconf/chrony_network_time.html

# Stratum 1 NTP servers, define at least five(5) and check "chronyc sources"
# for accuracy. Chrony can combine multiple time sources for higher accuracy.
# The following NTP servers are in the United States. 

server bonehed.lcs.mit.edu
server clock.nyc.he.net
server gnomon.cc.columbia.edu
server level1e.cs.unc.edu
server navobs1.gatech.edu
server navobs1.wustl.edu
server ntp.mrow.org
server ntp.quintex.com
server ntp.your.org
server ntp1.conectiv.com
server otc1.psu.edu
server tick.ucla.edu
server tick.uh.edu
server time-a-b.nist.gov
server time-a-g.nist.gov
server time-a-wwv.nist.gov
server time-b-b.nist.gov
server time-b-g.nist.gov
server time-b-wwv.nist.gov
server time-c-b.nist.gov
server time-c-g.nist.gov
server time-c-wwv.nist.gov
server time-d-b.nist.gov
server time-d-g.nist.gov
server time-d-wwv.nist.gov
server time-e-b.nist.gov
server time-e-g.nist.gov
server time-e-wwv.nist.gov
server time1.google.com
server time2.google.com
server time3.google.com
server time4.google.com
server tock.usshc.com
server usno.labs.hp.com.
server utcnist.colorado.edu
server utcnist2.colorado.edu

#pool 0.north-america.pool.ntp.org iburst
#pool 1.north-america.pool.ntp.org iburst

# ip address to listen on
#bindaddress 127.0.0.1
#bindaddress 10.10.10.100
#bindaddress 192.168.10.100
#bindaddress fddd:0:0:10::100

# unprivileged user when root privileges are dropped
user chronyd

# pid file
pidfile /var/run/chronyd.pid

# drift file and dump directory to record system clock gains and losses
driftfile /var/db/chrony/drift
dumponexit
dumpdir /var/db/chrony

# ignore stratum in source selection because any clock can go bad
stratumweight 0

# while chronyd is running, step the local clock if the time is off by more
# than one(1) second for no more then three(3) iterations
makestep 1.0 3

# allow NTP clients on the LAN to sync from the following networks
allow 10/8
allow 192.168/24
allow fddd::/48

# serve time even if not synchronized to any NTP servers (local mode)
#local stratum 10

# command port 323 disabled
cmdport 0

# log clock adjustments larger than 0.5 seconds
logchange 0.5

# logs for debugging
#logdir /var/log/chrony
#log measurements statistics tracking rtc

#
## EOF

Permission changes for the "chronyd" user

Since we are running the chrony daemon as the "chronyd" daemon and not root, we need to change the permissions on some of the daemon directories so chrony can update its database and cache directories.

The following lines will change the permissions of the chrony database and /var/run directory.

root@calomel#  mkdir /var/run/chrony /var/db/chrony
root@calomel#  chmod 750 /var/run/chrony /var/db/chrony 
root@calomel#  chown chronyd:chronyd /var/run/chrony /var/db/chrony

Start chronyd at server boot

At reboot we require chronyd to start and begin setting the system time. Add chronyd_enable="YES" to /etc/rc.conf to allow FreeBSD to execute the rc.d start script at system boot.

root@calomel#  vi /etc/rc.conf

chronyd_enable="YES"

Start and stop the chronyd daemon

The Chronyd daemon can be manually started and stopped using the rc.d script we created. Just for reference, here are the exact commands.

root@calomel#  service chronyd start

root@calomel#  service chronyd stop

Chrony setup complete

The configuration is complete. Take a look in the questions section below if you are interested in monitoring chrony in real time.

Questions?

How can I monitor Chrony ?

A simple while loop will query the crony service every 10 seconds.

while true; do clear; chronyc sources -v; echo "" ;chronyc sourcestats -v ; echo ""; chronyc tracking; sleep 10; done

What does the monitor output look like ?

The monitor line above will print the statistics of the time servers once every 10 seconds. This is the output on our time server after chrony had been running for over an hour. Notice the line "System time" towards the bottom of the output which confirms Chrony is able keep time to at least millisecond accuracy.

210 Number of sources = 23

  .-- Source mode  '^' = server, '=' = peer, '#' = local clock.
 / .- Source state '*' = current synced, '+' = combined , '-' = not combined,
| /   '?' = unreachable, 'x' = time may be in error, '~' = time too variable.
||                                                 .- xxxx [ yyyy ] +/- zzzz
||      Reachability register (octal) -.           |  xxxx = adjusted offset,
||      Log2(Polling interval) --.      |          |  yyyy = measured offset,
||                                \     |          |  zzzz = estimated error.
||                                 |    |           \
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^- caspak.cerias.purdue.edu      1   6   377    19  -1893us[-1899us] +/-   21ms
^- clock.isc.org                 1   6   277    18  +4818us[+4812us] +/-   41ms
^* clock.nyc.he.net              1   6   377    17   -856us[ -862us] +/- 5974us
^+ gnomon.cc.columbia.edu        1   6   377    18   -265us[ -271us] +/- 6842us
^- gps1.tns.its.psu.edu          1   6   377    18  -7466us[-7472us] +/-   17ms
^- india.colorado.edu            1   6   337    22  +2402us[+2690us] +/-   29ms
^+ level1f.cs.unc.edu            1   6   377    20  +1191us[+1185us] +/-   15ms
^- montpelier.ilan.caltech.e     1   6   377    20  -2549us[-2261us] +/-   34ms
^+ navobs1.gatech.edu            1   6   377    16  -1105us[-1105us] +/-   12ms
^+ navobs1.oar.net               1   6   377    17  -3669us[-3675us] +/-   16ms
^- navobs1.wustl.edu             1   6   377    18  -1269us[-1275us] +/-   17ms
^- ntp-s1.cise.ufl.edu           1   6   377    16  +4082us[+4082us] +/-   28ms
^+ ntp.colby.edu                 1   6   377    22   +240us[ +528us] +/-   11ms
^- ntp.okstate.edu               1   6   377    19  +2433us[+2427us] +/-   24ms
^+ ntp1.conectiv.com             1   6   377    17    +79us[  +79us] +/- 6099us
^+ ntp1.nss.udel.edu             1   6   377    16  +1175us[+1175us] +/- 7727us
^- ntp1.versadns.com             1   6   373    22   -606us[ -318us] +/-   21ms
^+ rackety.udel.edu              1   6   377    19  +1721us[+1715us] +/- 8590us
^- tick.ucla.edu                 1   6   377    21   -711us[ -423us] +/-   34ms
^- tick.uh.edu                   1   6   377    21    +83us[ +371us] +/-   23ms
^+ tick.usno.navy.mil            1   6   377    20   -566us[ -278us] +/- 7145us
^- time.keneli.org               1   6   377    17  +2545us[+2539us] +/-   13ms
^- usno.labs.hp.com              1   6   373    20    -98ms[  -98ms] +/-  132ms

210 Number of sources = 23
                             .- Number of sample points in measurement set.
                            /    .- Number of residual runs with same sign.
                           |    /    .- Length of measurement set (time).
                           |   |    /      .- Est. clock freq error (ppm).
                           |   |   |      /           .- Est. error in freq.
                           |   |   |     |           /         .- Est. offset.
                           |   |   |     |          |          |   On the -.
                           |   |   |     |          |          |   samples. \
                           |   |   |     |          |          |             |
Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev
==============================================================================
caspak.cerias.purdue.edu   11   8   649     +0.033      3.917  -2121us   520us
clock.isc.org              10   7   649     +4.692      5.397  +4888us   762us
clock.nyc.he.net           11   6   649     -0.487      2.715   -597us   327us
gnomon.cc.columbia.edu     11   7   649     +1.102      3.392   -785us   444us
gps1.tns.its.psu.edu       11   8   649     +0.765      3.708  -7469us   552us
india.colorado.edu         10   7   647     +0.861      1.238  +2257us   158us
level1f.cs.unc.edu         11   6   648     -0.250      2.537  +1286us   351us
montpelier.ilan.caltech.e  11   5   650     -0.080      3.280  -2382us   478us
navobs1.gatech.edu         11   6   649     -1.681      6.647  +3569ns   820us
navobs1.oar.net            11   5   650     +0.256      3.361  -3222us   437us
navobs1.wustl.edu           7   4   389     +1.050      5.447   -917us   226us
ntp-s1.cise.ufl.edu         9   5   519     +0.340      2.796  +4440us   173us
ntp.colby.edu              11   7   646     -0.224      2.107    +37us   283us
ntp.okstate.edu            11   6   649     -0.033      7.054  +1594us  1146us
ntp1.conectiv.com          11   8   649     +0.832      1.748  -3646ns   245us
ntp1.nss.udel.edu          11   7   649     +0.212      2.261   +949us   344us
ntp1.versadns.com          10   9   647     +7.833     62.564   +135us  8185us
rackety.udel.edu            7   4   389     +2.348     10.031  +2455us   462us
tick.ucla.edu              11   7   648     -0.272      1.996  -1436us   297us
tick.uh.edu                11   5   647     +0.100      2.433   +688us   290us
tick.usno.navy.mil         11   8   648     -0.861      2.541   -618us   343us
time.keneli.org            11   8   649     +0.893      6.807  +3041us  1085us
usno.hpl.hp.com            10   4   649     +8.359    137.037  -8118us    18ms

Reference ID    : 209.51.161.238 (clock.nyc.he.net)
Stratum         : 2
Ref time (UTC)  : Fri May 20 21:23:33 2016
System time     : 0.000001215 seconds slow of NTP time
Last offset     : -0.000006298 seconds
RMS offset      : 0.000150691 seconds
Frequency       : 5.575 ppm slow
Residual freq   : -0.003 ppm
Skew            : 0.949 ppm
Root delay      : 0.009598 seconds
Root dispersion : 0.000623 seconds
Update interval : 2.8 seconds
Leap status     : Normal

How can I build Chrony from source on FreeBSD ?

Download and build chrony

To build chrony, the GNU version of make is required which can be installed from the FreeBSD package system or ports. Then download the chrony tarball from the chrony web site and build the chronyc and chronyd binaries. The last step is to copy the binaries into the system paths which are the same paths the FreeBSD package normally installs chrony to. Once the install is done you are welcome to delete the chrony source files from /tmp .

# install the GNU version of make
root@calomel#   pkg install gmake

# download and untar chrony in /tmp
root@calomel#   cd /tmp
root@calomel#   wget https://download.tuxfamily.org/chrony/chrony-3.4.tar.gz
root@calomel#   tar zxvf chrony-3.4.tar.gz
root@calomel#   cd chrony-3.4

# build the chronyc and chronyd binaries
root@calomel#   CC=clang ./configure && gmake && echo "BUILD SUCCESSFUL"

# copy the chronyd daemon and chronyc query tool into the system paths
root@calomel#   cp chronyc /usr/local/bin/chronyc
root@calomel#   cp chronyd /usr/local/sbin/chronyd

Create the chronyd startup script

To start and stop chrony as a service we need to generate an rc.d script. Create a new file in "/usr/local/etc/rc.d/chronyd" and place the following startup script in the file. Save the file and make sure the permissions are 555 with the command, "chmod 555 /usr/local/etc/rc.d/chronyd" .

root@calomel#  vi /usr/local/etc/rc.d/chronyd

#!/bin/sh
#
# PROVIDE: chronyd
# REQUIRE: DAEMON
#

. /etc/rc.subr

name=chronyd
rcvar=chronyd_enable
command=/usr/local/sbin/${name}

load_rc_config ${name}

: ${chronyd_enable="NO"}

run_rc_command "$1"


root@calomel#  chmod 555 /usr/local/etc/rc.d/chronyd

Create the chronyd dump directory

Chrony is able to sync time quicker on reboot or service restart if chronyd can gather time statistics about each NTP server from the last time chronyd was running. Create a directory to allow chrony to dump time statistics about each time source to /var/db/chrony and allow the unprivileged user daemon to write to the directory. The statistics are less than a few hundred kilobytes in total so space usage is not an issue.

root@calomel#  mkdir /var/db/chrony

root@calomel#  chown daemon /var/db/chrony

Source build install complete.