Skip to content

Chrony GPS NTP Server

The ntppool namespace runs a stratum-1 NTP server backed by a GPS receiver with PPS (Pulse Per Second) output, connected via USB to one of the cluster nodes.

Architecture

flowchart LR
    gps["GPS receiver\nTTL UART 115200\nmulti-constellation\n(GP/GL/GA/BD)"]
    ft232["FT232R USB-UART\n(ttyUSB0 in pod)"]
    gpsd["gpsd\nSHM 0: NMEA\nSHM 1: PPS (TIOCMIWAIT)"]
    chrony["chronyd\nSHM 0: NMEA (falseticker)\nSHM 1: PPS (primary)"]
    clients["NTP pool clients\nstratum 2"]

    gps -->|"NMEA + PPS on DCD pin"| ft232 --> gpsd
    gpsd -->|"SHM 0 + SHM 1"| chrony
    chrony -->|"NTP port 123"| clients

Key Configuration

refclock SHM 0 refid NMEA precision 1e-1
refclock SHM 1 refid PPS precision 1e-7 offset -0.100 lock NMEA

The offset -0.100 corrects for the FT232R's 100 ms early-fire characteristic on the PPS signal.

Current Status

Source Offset Role
NMEA (SHM 0) ~+118ms Falseticker — used only for second identification
PPS (SHM 1) ~-7µs ±9µs Primary stratum-1 source

Key Findings

  • gpsd SHM timestamp inversion — gpsd 3.26.1 writes clockTimestamp=system_time and receiveTimestamp=GPS_time, opposite of the NTP SHM spec. This is intentional and well-known.
  • Do not use ldattach / N_PPS ldisc — it drops all NMEA serial data on the same port. gpsd's TIOCMIWAIT-based PPS (SHM 1) is the correct approach.
  • Startup order matters — gpsd must start first (gpsd & sleep 3 && exec chronyd). Reversed order causes zombie accumulation and stale SHM slots.
  • gpsd SHM 2/3 not written — only SHM 0 (NMEA) and SHM 1 (PPS) are populated by gpsd 3.26.1.

Deployment Notes

The pod runs in the ntppool namespace on node qui (which has the USB GPS receiver). It participates in the public NTP Pool Project, serving stratum-2 time to pool clients via PureLB VIP 192.168.1.48.