NTPsec: GPS Stratum-1 Time Server

From MattWiki

This document will walk you thru how to build a Stratum-1 Time Server on a Raspberry Pi using the Raspberry Pi OS (previously called Raspbian).

In a nutshell, we will be receiving time data from the Global Positioning System (GPS) and distributing it via the Network Time Protocol to other computers on the network.

Note: In this how-to, we will be building this on a network with the gateway at The system its self with have the IP address of and the host name of time01.local.

Hardware Needed

Prepare the System

Image the SD Card

We will be using Raspberry Pi OS Lite (64-bit) distribution for this project. The quickest and easiest way of installing it is via the Raspberry Pi Imager found on Raspberry Pi's website.

Download and install Raspberry Pi Imager to a computer with an SD card reader. Put the SD card you'll use with your Raspberry Pi into the reader and run Raspberry Pi Imager.

Configuring the Image

Using the gear in the lower right hand side of the imager, set the following parameters before writing the image.

  • Set hostname
  • Enable SSH
    • You may choose to use a password or you may add a public-key to increase security
  • Set your Time zone
  • Set Keyboard layout

Once everything is set, you may write the image by clicking write.

Update the system

Start by bring the system up-to-date and install needed software

sudo apt update
sudo apt -y dist-upgrade
sudo rpi-update
sudo apt -y install gpsd gpsd-tools ntpsec

Set a Static IP address


interface eth0
static ip_address=
static routers=
static domain_name_servers=
static domain_search=local

Enable Serial Port Interface

The GPS module sends serial data via the onboard uart port. We must enable this port before we may read any data from the GPS module.

echo "enable_uart=1" |sudo tee -a /boot/config.txt

Enable PPS Support

The Adafruit Ultimate GPS HAT is set for GPIO pin 4, so that is what we will use.

echo "dtoverlay=pps-gpio,gpiopin=4" |sudo tee -a /boot/config.txt

If you are instead using the Waveshare L76X Multi-GNSS Hat instead, set the GPIO pin to 18.

echo "dtoverlay=pps-gpio,gpiopin=18" |sudo tee -a /boot/config.txt

Disable Wi-Fi and Bluetooth Support (Optional)

Since we are using an ethernet cable and not a Wi-Fi connection, it is best practice to disable Wi-Fi on the board, by running the following command.

echo "dtoverlay=disable-wifi" |sudo tee -a /boot/config.txt

Likewise, to disable Bluetooth, run the following command.

echo "dtoverlay=disable-bt" |sudo tee -a /boot/config.txt


Reboot the system to allow access to the newly configured serial interface.

sudo reboot

Configure GPSd


# Default settings for the gpsd init script and the hotplug wrapper.
# Start the gpsd daemon automatically at boot time

# Use USB hotplugging to add new USB devices automatically to the daemon

# Devices gpsd should collect to at boot time.
# They need to be read/writeable, either by user gpsd or the group dialout.
DEVICES="/dev/ttyS0 /dev/pps0"

# Other options you want to pass to gpsd

Enable GPSd to start at boot time, then start the service.

sudo systemctl enable gpsd.service
sudo systemctl start gpsd.service

Configure NTPsec

Enable NTPsec to start at boot time, then start the service.

sudo systemctl enable ntpsec.service
sudo systemctl start ntpsec.service

Testing and Monitoring


Expired Leapsecond file

CLOCK: leapsecond file ('/usr/share/zoneinfo/leap-seconds.list'): expired less than ?? days ago
sudo curl -Ls https://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list -o /usr/share/zoneinfo/leap-seconds.list

Optional Configurations

Network Time Security (NTS)

Network Time Security (NTS) provides cryptographic security for the client-server mode of the Network Time Protocol (NTP). This allows users to obtain time in an authenticated manner.

The NTS protocol is divided into two phases:

  1. NTS key exchange: Establishes the necessary key material between the NTP client and the server, using a Transport Layer Security (TLS) handshake (the same public key infrastructure as the web). Once the keys are exchanged, the TLS channel is closed and the protocol enters the second phase.
  2. NTP authentication: Authenticates NTP time synchronization packets using the results of the TLS handshake. For more information, refer to RFC 8915.
sudo apt install certbot


#!/bin/sh -eu
# vim: ai ts=4 sts=4 et sw=4

if [ -r /etc/default/ntpsec ]
    . /etc/default/ntpsec

    exit 0

# If the certificate being deployed is not the one for ntpd, exit.
for domain in $RENEWED_DOMAINS
    if [ "$domain" = "$NTPSEC_CERTBOT_CERT_NAME" ]
if [ "$found" = "0" ]
    exit 0

# Copy the certificate (including chain) and key so ntpd can read them
# after dropping privileges.
install -m 644 /etc/letsencrypt/live/"$NTPSEC_CERTBOT_CERT_NAME"/fullchain.pem \
install -m 640 -g ntpsec \
    /etc/letsencrypt/live/"$NTPSEC_CERTBOT_CERT_NAME"/privkey.pem \

# Tell ntpd to reload the certificate and key.
nginx -s reload
killall -HUP ntpd 2>/dev/null || true

After the above file has been created, make sure that it is executable and has the correct permissions.

sudo chmod 750 /etc/letsencrypt/renewal-hooks/deploy/ntpsec-nts-deploy-hook.sh
sudo chown root:root /etc/letsencrypt/renewal-hooks/deploy/ntpsec-nts-deploy-hook.sh

After the ntpsec-nts-deploy-hook.sh file is all set, you can run the below command to create a new certificate.

sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt/cloudflaire-theodin.ini -d time.theodin.network --renew-hook /etc/letsencrypt/renewal-hooks/deploy/ntpsec-nts-deploy-hook.sh


# To enable Network Time Security support as a server, obtain a certificate
# (e.g. with Let's Encrypt), configure the paths below, and uncomment:
nts cookie /var/lib/ntp/nts-keys
nts cert /etc/ntpsec/nts/cert-chain.pem
nts key /etc/ntpsec/nts/key.pem
nts server time.theodin.network
nts enable

Leapsecond File Fetch Service (Optional)

ntpleapfetch will validate the file currently on the local system and if necessary, update leap second definition file.

First create the timer file:


Description=Run ntpleapfetch once a week

OnCalendar=Sun 00:03:00


Next create the service file:


Description=Validate & update leap second definition file

ExecStart=/usr/local/bin/ntpleapfetch -f /etc/ntpsec/ntp.conf -p 4 -l -s https://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list -e "30 days"

Once the files are created, you may active the timers by running the following commands:

sudo systemctl enable ntpleapfetch.timer
sudo systemctl start ntpleapfetch.timer

To confirm the timer is running, run the following command and look for the line with ntpleapfetch.timer

systemctl list-timers --all

DNSMasq / PiHole DHCP Configuration (Optional)

If you are using DNSMasq or PiHole for dhcp provisioning you may added the dhcp option 42 to your /etc/dnsmasq.conf or if dnsmasq.conf is being managed by an outside source (say PiHole) you may put it in it's own file (ie. /etc/dnsmasq.d/42-pihole-dhcp-ntp.conf).



Or if you have more then one NTP server, you may add them as following.


SNMP Configuration (Optional)

Other Resources


Other Configuration Examples


  • Flawed Routers Flood University of Wisconsin Internet Time Server - In May 2003, the University of Wisconsin - Madison found that it was the recipient of a continuous large scale flood of inbound Internet traffic destined for one of the campus' public Network Time Protocol (NTP) servers. The flood traffic rate was hundreds-of-thousands of packets-per-second, and hundreds of megabits-per-second.