Build you own stratum-1 NTP server for less than $100
You can build a highly accurate Stratum-1 NTP Server for less than $100 using an old Wyse WinTerm (see picture), a GPS and a few electronic components.
The first thing you must do is replace the flash inside of the Wyse with a new flash with a real operating system. You can use an embedded version of Linux such as BusyBox, NetBSD, or FreeBSD with FlashBoot. On my Wyse WinTerm I installed OpenBSD and used the package flashrd to build an embeded version of OpenBSD.
I usually build my own OpenBSD flash, but you can use one of the pre-made flash distributions available on the flashrd site.
NTP Server using OpenBSD and a Garmin GPS18LVC
- Wyse WinTerm V30-vx0 - $25 on eBay
- Garmin GPS18LVC - $45 on eBay
- A few wires, 2 resistors, 2 LED, 1 prototyping board, connectors - less than $9 at Fry's Electronics
Configuring your GPS
According to its manual, the Garmin GPS18LVC draws 60mA at 5.0V. Add a 20mA for the LEDs, a total of 80mA will be drawn from the USB port. A standard USB port is able to provide 500mA of power, therefore there is no concern that a standard USB port is able to provide power for our GPS and little board.
Here is the schematics I used to connect the Garmin GPS18LVC to the computer:
Connect the GPS to the serial port, and on a USB port. The only
purpose of the USB port is to provide power (5V) to the GPS. On the
Wyse WinTerm there is only one serial port, therefore the address will
Once your GPS is connected to the Wyse the power LED should be on and after a few seconds the PPS indictor LED should flash once every second. By default the PPS is enabled on the Garmin GPS18LVC. If the PPS LED does not flash you can use the Windows based Garmin software to configure your GPS or simply use a serial terminal emulator.
On mine I used the command
cu -4800 -l /dev/cua00 to connect to the
GPS and verify that the configuration was fine. You can configure your
GPS using the Garmin software, manually using
cu and typing the
commands directly on the console. You can also use a little script
like the one I used to set the GPS with the right options. The
advantage of using a script is that you can run it again if the GPS is
reset to the factory defaults, or if you want to configure a second
from time import sleep from serial import Serial ser = Serial(port='/dev/cua00', baudrate=4800) print "Set all NMEA sentence OFF" ser.write("$PGRMO,,2\r\n") print "response: " + ser.readline()[:-1] print "Read PGRMC register" ser.write("$PGRMCE,\r\n") sleep(1) print "Working settings: " + ser.readline()[:-1] print "Writting new settings" ser.write("$PGRMC,A,27.0,100,,,,,,A,5,1,2,4,\r\n") sleep(1) print "New saved setting: " + ser.readline()[:-1] print "Configuring NMEA sentence..." #ser.write("$PGRMO,GPGCA,1\r\n") ser.write("$PGRMO,GPRMC,1\r\n") #ser.write("$PGRMO,GPGSA,1\r\n") print "Configuration done." print print "Reading NMEA sentences from GPS receiver" while True: print ser.readline()[:-1]
After configuring your device or after running the Python script the
output of your GPS should be as follows. Where only the NMEA code
$GPRMC is printed. The PPS LED situated on the prototyping board
should continue to flash once every second. If the LED doesn't flash
or the output is different try configuring your GPS again.
Also beware that the lines should be terminated by the sequence
\r\n. If you are using a terminal emulator, make sure it is
correctly configured to send the appropriate
CR NL every time you
Example of GPS output after configuration:
It is important to remove as many messages returned by the GPS as
possible, because the NTP driver uses the
$ sign as the beginning of
the second. At 4800 Baud it can take more than one second to print all
the messages sent by the GPS.
Now that your GPS is correctly configured, you need to create a link
/dev/gps0 pointing to the serial port where your GPS is
connected. The NTP driver can only handle devices named
n is the GPS number
bash# ln -s /dev/cua00 /dev/gps0 bash# ls -l /dev/gps0 lrwxr-xr-x 1 root wheel 10 Jun 24 14:34 /dev/gps0 -> /dev/cua00
Configuring the NTP daemon
By default OpenBSD uses OpenNTPd to synchronize its clock. OpenNTPD is a simple, lightweight NTP server designed with security as a priority. Even though you can use OpenNTPD with a GPS, I have decided to use the NTP server from ntp.org, which provides better precision and more control.
To install NTP simply use the packages tools provided by OpenBSD.
bash# pkg_add ntp
To have NTP started at boot time you need to add the following line
near the end of the file
/etc/ntp.conf to add the GPS as a clock server. My
# enable stats statsdir /var/log/ntp statistics loopstats peerstats clockstats # filegen peerstats file peerstats type day enable filegen loopstats file loopstats type day enable filegen clockstats file clockstats type day enable logconfig =syncstatus +sysevents +syncall +clockall logfile /var/log/ntp/log driftfile /var/db/ntp.drift # leapfile /var/db/leap.ntp # server 127.127.20.0 mode 1 prefer fudge 127.127.20.0 flag1 1 flag2 0 # server 127.127.1.0 # local clock fudge 127.127.1.0 stratum 7 # local clock # restrict default kod limited nomodify notrap nopeer restrict 127.0.0.1
The first lines of the configuration file, are for what to log
where. The lines telling NTP to use a reference clock, the GPS in our
case, are the first two lines starting with
server 127.127... and
fudge 127.127.... For more information on reference clocks you can
check the page
Reference Clock Support.
Our NTP server uses a GPS supporting the NMEA standard The address for
the Generic NMEA GPS Receiver is
127.127.20.n where n specifies
which GPS to use. You remember when we created the link
The zero is the number that we are going to use here
mode 1 tells the driver to use the NMEA phrase
$GPMRC to get the
time reference from.
The second line starting with
fudge followed by the driver address,
passes some more configuration info to the driver.
flag1 1 Enable the use of the PPS signal.
flag2 0 Tell the driver to capture the pulse at the rising edge.
The following two lines starting with
server 127.127.1.0 and
127.127.1.0 configure the internal clock. This is important when
other machines in your datacenter are synchronized to your NTP server
and when having all the machines in sync is more important than the
time accuracy. If your GPS has problems receiving the signal, or
simply fails, your NTP server will use its internal clock to continue
to provide the time to the client machines. The time may drift away
from the "real" time but all the machines will drift the same way and
they will all stay in sync.
The last line I want to talk about in this configuration file is the
line starting with
leapfile. The US NIST publishes a file which
contains a table of past and upcoming leap seconds. This file can be
used by NTP to become aware of leap second announcements. Part of the
job of a stratum-1 server is to advertise pending leap seconds during the
day prior to the event. You can download this file at
Check if your NTP server is working
The best way to verify that your NTP server is working well is to use
ntpdc utility. The option
-c peers displays informations
about the peers.
$ ntpdc -c peers remote local st poll reach delay offset disp ======================================================================= *GPS_NMEA(0) 127.0.0.1 0 64 377 0.00000 -0.000736 0.03931 =LOCAL(0) 127.0.0.1 7 64 0 0.00000 0.000000 3.99217
You can also use the option
-c sysinfo which will print a variety of
system state variables.
$ ntpdc -c sysinfo system peer: GPS_NMEA(0) system peer mode: client leap indicator: 00 stratum: 1 precision: -18 root distance: 0.00000 s root dispersion: 0.00662 s reference ID: [GPS] reference time: d3e9704b.f5d0d41e Wed, Aug 29 2012 21:53:31.960 system flags: auth monitor ntp kernel stats jitter: 0.002462 s stability: 0.000 ppm broadcastdelay: 0.000000 s authdelay: 0.000000 s