One of my first posts to this blog involved using Mikrotik’s RouterOS to create a local NTP server. I even thought about using a Raspberry Pi and a USB GPS to accomplish this project. Well…it’s time to revisit the idea using a GPS receiver with PPS and creating a high accuracy Stratum-1 NTP server. While this may not be necessary for the average homelab or someone who would like to keep the time and logs of devices connected to an air gapped or isolated network accurate, accuracy becomes quite important when applications begin timing actions over the network (such as commonly seen with industrial operations and communication systems). Throughout this post, I’ll be using posts located at https://www.jacobdeane.com/iot/2020/building-a-gps-based-time-server/ and https://weberblog.net/ntp-server-via-gps-on-a-raspberry-pi/ as references.
Needed Hardware
The hardware needed will be the following:
- Raspberry Pi – Any Raspberry Pi with network connectivity will work but Pi 4 has the Ethernet interface connected via PCIe instead of USB so it will be a little faster compared to previous generations.
- GPS Receiver with PPS – In this case I will be using a Goouuu Tech GT-U7 I got off of Amazon for around $15. This is a TTL device so it will interface directly with the Pi’s GPIO header.
- Antenna for GPS – I will be using a Mikrotik ACGPSA active GPS antenna with a u.FL adapter to interface with the GPS receiver.
Software
- Pi OS Lite – Debian 11 based image (32 bit for this particular instance).
- pps-tools – Recognizes PPS.
- gpsd – GPS daemon.
- ntp – NTP server
Configuration
Assuming you have already flashed Pi OS to a flash medium and are now able access the Pi, either via KVM or via SSH. If attempting to use a serial console…try a different method as the serial port that is used for serial console is about to be disabled so it can be used for the GPS interface.
Configure the Serial Interface
First step is to disable the console interface. Enter sudo raspi-config
and navigate to 3 Interface Options > I6 Serial Port
and set the login shell to not be accessible over serial. Be careful not to accidentally disable the serial port in addition to the login shell.
Reboot the system as you exit raspi-config. Next we will need to disable getty services with the following commands.
sudo systemctl stop serial-getty@ttyAMA0
sudo systemctl disable serial-getty@ttyAMA0
Since we want full control of the UART and don’t want to let Bluetooth have it…we will disable Bluetooth by adding the following to the /boot/config.txt
file (which is read during the boot process) using your text editor of choice and reboot. This will use GPIO_18 as the PPS input but this may not be where the PPS signal is mapped for those using HATs.
# Disable Bluetooth for GPS
dtoverlay=disable-bt
dtoverlay=pps-gpio,gpiopin=18
Connect the GPS Receiver
Now we will need to look at the Raspberry Pi’s GPIO header to figure out where we need to connect things…
In the case of this GPS receiver, we will be using 5V power, ground, TXD, RXD and a pin for PPS. 5V will come from either pin 2 or 4, ground from pin 6, TXD (which will go to RXD on the receiver) on pin 8, RXD (which will go to TXD on the receiver) on pin 10 and GPIO 18 for PPS on pin 12.
Once the GPS is connected, running cat /dev/ttyAMA0
should return some structured NEMA output.
Install and Configure GPS tools
Now we need to install GPS related tools and configure settings. First we will load the pps-gpio module by adding pps-gpio
to /etc/modules
and rebooting.
Next we will install gpsd and pps-tools with the following.
sudo apt install gpsd gpsd-clients pps-tools -y
Assuming the GPS is now hooked up and has locked, we can run a pps test to make sure our pin is configured correctly.
sudo ppstest /dev/pps0
Which should return something like the following if PPS is working correctly.
Next we will configure GPSD by editing /etc/default/gpsd
and add the serial and pps interfaces, disable USB hot plugging and pass the -n
flag.
# Devices gpsd should collect to at boot time.
# They need to be read/writeable, either by user gpsd or the group dialout.
DEVICES="/dev/ttyAMA0 /dev/pps0"
# Other options you want to pass to gpsd
GPSD_OPTIONS="-n"
# Automatically hot add/remove USB GPS devices via gpsdctl
USBAUTO="false"
Now we will enable the gpsd service and start it.
sudo systemctl enable gpsd
sudo systemctl start gpsd
And reboot.
To test the GPS…run gpsmon -n
where the -n
flag will force the output into NEMA0183 sentences. If everything is functional, you should see your position in the window.
Configure NTP
We need to start off by editing /etc/dhcp/dhclient.conf
and removing the references to dhcp6.sntp-servers
and ntp-servers
. Now we can install the NTP server.
sudo apt install ntp -y
Now we can edit /etc/ntp.conf
. In my case, I am commenting out several of the pools but in an air-gapped system these would be used to provide additional stratum-1 servers on the network but it is recommended to leave at least one or two other servers in place. Next we will add the memory register locations (which look like loopback IP addresses) to the config file.
# pps-gpio /dev/pps0
server 127.127.22.0 minpoll 4 maxpoll 4
fudge 127.127.22.0 refid PPS
# gpsd clock via shared memory
server 127.127.28.0 minpoll 4 maxpoll 4 prefer
fudge 127.127.28.0 time1 +0.000 refid GPS flag1 1
Save the file and restart the ntp service by running sudo systemctl restart ntp
and give the device a few minutes. After you should be able to run ntpq -p
which will display stats of the NTP servers in the config file.
That’s it. We can now point end devices at our NTP server (unicast mode) and let them sync.
Conclusion
This was an interesting exercise in building a stratum-1 NTP server. There are Raspberry Pi HATs which provide a cleaner setup. If I were planning on building this as a marketable soltuion, I would most likely look into using a Compute Module 4 on a carrier board that had PoE in support and a built in GPS interface in a 1U rack mount enclosure. A plus would also provide the PPS line to be used as a reference for a 10 MHz Reference Clock at 1 Vpp (it’s like a major radio manufacturer uses that or something). However, to really make this usable in an air-gapped setup, you really need one to three more stratum-1 NTP servers throughout the network.