🛠️ Stratum 1 NTP/NTS Server Setup Guide for Raspberry Pi

Configuration Instructions

← Back to Main Page

Introduction

The following instructions can be used to set up a public NTP/NTS server running chrony on a Raspberry Pi, with automatic SSL certificate renewals from Let’s Encrypt Certificate Authority.

Please note the following important points:

Power Warning: Care must be taken not to power the circuit board via the USB port while it is also receiving power from the Pi. You can connect only one source of power at a time! To ensure the board does not receive power from the USB port (e.g., when connecting to a computer for u-center software), we use a Portapow USB Power Blocker. This blocks power from the computer while allowing data signals through.

1. Configure the Firewall 🛡️

This step ensures that your Raspberry Pi is accessible from the internet for the necessary time and security services.

Configure your firewall to allow ports 80, 123, and 4460 and forward them to the Raspberry Pi.


2. Prepare Serial Port 🔗

This step prepares the Raspberry Pi's hardware to communicate with the GPS/Galileo HAT, which provides the precise time data. Disabling the login shell frees the serial port for the GPS device.

Start raspi-config:

sudo raspi-config
  1. Select option "Interface Options".
  2. Select option "Serial Port".
  3. At "Would you like a login shell to be accessible over serial?" Answer "No".
  4. At "Would you like the serial port hardware to be enabled?" Answer "Yes".
  5. Exit raspi-config and reboot the Pi.

3. Install Required Packages 📦

This installs the core software components: gpsd (to process GPS data), pps-tools (for the precise time signal), chrony (the time server software), and apache2/certbot (for NTS security certificates).

sudo apt install gpsd pps-tools chrony apache2 python3-certbot-apache

4. Setup PPS ⏳

Adding this line enables the Linux kernel to recognize and process the highly accurate Pulse-Per-Second (PPS) signal from the GPS module on the specified GPIO pin.

Edit /boot/firmware/cmdline.txt:

sudo nano /boot/firmware/cmdline.txt

At the end of the line, add the following:

bcm2708.pps_gpio_pin=18 nohz=off

5. Setup Serial ⚙️

This creates a custom script and a systemd service to ensure the serial port's communication settings (e.g., 9600 baud rate) are correctly configured automatically every time the Pi boots, allowing reliable GPS data transfer.

Create the script file:

sudo nano /usr/local/bin/configure-ttyAMA0.sh

Add the following content to the script:

#!/bin/bash /bin/stty -F /dev/ttyAMA0 raw 9600 cs8 clocal -cstopb -echo

Make the script executable:

sudo chmod +x /usr/local/bin/configure-ttyAMA0.sh

Create a systemd service to run this script:

sudo nano /etc/systemd/system/configure-serial-port.service

Add the following configuration:

[Unit] Description=Configure Serial Port ttyAMA0 Settings # This ensures the service runs only after the device node is present After=dev-ttyAMA0.device [Service] Type=oneshot ExecStart=/usr/local/bin/configure-ttyAMA0.sh [Install] WantedBy=multi-user.target

Enable and start the service:

sudo systemctl daemon-reload sudo systemctl enable configure-serial-port.service sudo systemctl start configure-serial-port.service

6. Set up Modules & Overlays 🔌

This loads the necessary device drivers and configures the hardware-software interface for the PPS signal, formally activating the PPS function on the kernel level.

Edit modules configuration:

sudo nano /etc/modules-load.d/modules.conf

Add at the bottom:

pps-gpio

Edit /boot/firmware/config.txt:

sudo nano /boot/firmware/config.txt

Add the following at the bottom:

# PPS on PGIO pin 18 dtoverlay=pps-gpio,gpiopin=18

7. Setup gpsd 🛰️

This configures the gpsd daemon to monitor both the serial data (/dev/ttyAMA0) and the precise PPS signal (/dev/pps0), combining them into a usable time source for chrony.

Edit gpsd defaults:

sudo nano /etc/default/gpsd

Change file to match the following:

DEVICES="/dev/ttyAMA0 /dev/pps0" GPSD_OPTIONS="-n" USBAUTO="false"

8. Setup Chrony ⏰

This is the core configuration to enable NTS (Network Time Security), set rate limits to protect the public server, and configure the high-precision PPS source from the GPS HAT as the primary Stratum 1 reference clock.

Edit daemon options:

sudo nano /etc/default/chrony

Change to:

DAEMON_OPTS="-F 1 -r"

Edit chrony configuration:

sudo nano /etc/chrony/chrony.conf

Apply the following changes (comment out default pools and default DHCP sources):

#pool 2.debian.pool.ntp.org iburst #sourcedir /run/chrony-dhcp dumpdir /var/run/chrony makestep 1 1 # Set maximum client log size clientloglimit 2147483648 # Set rate limits ratelimit ntsratelimit # Allow all allow # Certificate in the PEM format ntsservercert /etc/chrony/certs/fullchain.pem # Private key in the PEM format ntsserverkey /etc/chrony/certs/privkey.pem # Number of helper processes for NTS ntsprocesses 10 # Maximum number of concurrent NTS-KE connections per process maxntsconnections 512 # Main reference clock using socket interface refclock SOCK /run/chrony.pps0.sock refid GNSS precision 1e-9

Enable services:

sudo systemctl enable gpsd sudo systemctl enable chrony

Reboot now:

sudo reboot

9. Setup Network Time Security (NTS) 🔐

This finalizes the cryptographic security. It uses Certbot to obtain the necessary SSL certificates for NTS and creates a renewal hook script to automatically copy the new certificates and restart the chrony service whenever they are renewed, ensuring continuous secure operation.

Obtain an SSL Certificate (replace time.yourdomain.com with your domain):

sudo certbot --apache -d time.yourdomain.com

Copy certificates for chrony (replace time.yourdomain.com with your domain):

cd /etc/chrony sudo mkdir certs sudo su cat /etc/letsencrypt/live/time.yourdomain.com/fullchain.pem > /etc/chrony/certs/fullchain.pem cat /etc/letsencrypt/live/time.yourdomain.com/privkey.pem > /etc/chrony/certs/privkey.pem exit

Create a renewal hook script:

sudo nano /etc/letsencrypt/renewal-hooks/deploy/chrony_NTS_certs.sh

Add script content:

#!/bin/bash FULLCHAIN_PATH="${RENEWED_LINEAGE}/fullchain.pem" PRIVKEY_PATH="${RENEWED_LINEAGE}/privkey.pem" cat "${FULLCHAIN_PATH}" > /etc/chrony/certs/fullchain.pem cat "${PRIVKEY_PATH}" > /etc/chrony/certs/privkey.pem systemctl restart chronyd systemctl restart gpsd

Make executable:

sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/chrony_NTS_certs.sh

Final reboot:

sudo reboot

10. Maintenance & Troubleshooting 🔧

Use these commands to verify that your GPS/PPS reference clock is operating correctly, check the status of your NTS connection, and manage your chrony and Let's Encrypt services.

NTS Verification

Test NTS from a machine on a separate internet connection (replace time.yourdomain.com with your domain):

chronyd -Q -t 5 "server time.yourdomain.com iburst nts maxsamples 1"

What it achieves: Queries your server using chronyd client mode to verify that the NTS key exchange (Port 4460 TCP) and the authenticated NTP service (Port 123 UDP) are both working correctly. This test is crucial to perform from outside your local network, as internal network configurations often prevent successful external time server verification.

Serial Port and PPS Diagnostics

Display serial settings:

stty -F /dev/ttyAMA0 -a

What it achieves: Shows the current communication parameters (baud rate, data bits, etc.) for the serial port, confirming that the script in Step 5 ran successfully.

sudo setserial -v /dev/ttyAMA0

What it achieves: Reports hardware-level settings and statistics for the serial port.

Display serial output:

cat /dev/ttyAMA0

What it achieves: Prints the raw NMEA data stream from the GPS module to the console. Look for recognizable GPS sentences like $GPGGA or $GNGGA. If the command reports the device as busy, it is likely due to gpsd having exclusive control of the device. In this case, stop gpsd using the maintenance commands below before retrying.

Test PPS:

sudo ppstest /dev/pps0

What it achieves: Verifies that the kernel is receiving the physical Pulse-Per-Second (PPS) signal, indicated by timestamps printed once per second. This is the ultimate test of the high-accuracy time source.

Display GPS data:

cgps -s

What it achieves: Launches the curses-based GPS monitoring utility, providing a real-time, structured display of satellite fix status, coordinates, and time extracted by the gpsd service.

gpsmon

What it achieves: Displays the raw NMEA sentences and gpsd status information, often used for advanced debugging of the GPS connection.

GPSD Service Management

Stop gpsd:

sudo systemctl stop gpsd
sudo systemctl stop gpsd.socket

What it achieves: Temporarily halts the gpsd service and its listening socket. This is necessary if you need to manually inspect the serial port output using cat /dev/ttyAMA0, as gpsd takes exclusive control of the device.

Start gpsd:

sudo systemctl start gpsd.socket
sudo systemctl start gpsd

What it achieves: Restarts the gpsd socket listener and the main daemon, ensuring the GPS data is correctly processed and provided to chrony again. The socket is typically started first.

Service Status and Logging

Check service status:

sudo systemctl status chronyd

What it achieves: Confirms that the main chrony time service is running and shows recent log messages and status (Active/Inactive).

sudo systemctl status apache2

What it achieves: Checks the status of the Apache web server, which is required by Certbot to prove domain ownership for SSL certificate renewal.

journalctl -xeu chrony.service

What it achieves: Displays the full system journal logs for the chrony service, which is essential for diagnosing why the service might be failing to start or synchronize.

Let's Encrypt Management

Let's Encrypt management:

sudo certbot renew –force-renewal

What it achieves: Forces Certbot to attempt a certificate renewal immediately, regardless of when the last renewal occurred. Use this to test your renewal hook script.

sudo certbot renew --dry-run

What it achieves: Simulates the entire renewal process without actually saving any new certificates or affecting your live server. It's the safest way to test your setup.