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.
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.
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.
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://calomel.org/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
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
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"
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
The configuration is complete. Take a look in the questions section below if you are interested in monitoring chrony in real time.
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
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
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.