← Projects
raspberry-pi intermediate Jul 29, 2026 ◑ 2 views ◯ 4 min read

Build a Stratum 1 NTP Time Server with Raspberry Pi and GPS

Build time: 3-5 hours
Tools needed: Small Phillips screwdriver, soldering iron (only if the GPS module needs header pins soldered on), wire strippers, laptop for SSH/configuration
Parts List
ntpstratum 1gpsppschronytime serverraspberry piprecision timinggnss

Every device on a home network gets its clock from an NTP server somewhere upstream, usually a pool of public internet time servers several network hops away with tens of milliseconds of jitter. That's plenty accurate for browsing and email, but it isn't good enough for precise packet timestamping, ham radio digital modes, security camera correlation, or just the satisfaction of running infrastructure most people don't know exists. A Raspberry Pi with a GPS receiver and its 1-pulse-per-second (PPS) output becomes a Stratum 1 NTP server — disciplined directly by the GPS satellite constellation's atomic clocks rather than by another server's opinion of the time — and can serve sub-millisecond accuracy to every other device on the local network.

Why GPS Specifically

GPS satellites carry atomic clocks and broadcast time as part of their navigation signal, accurate to tens of nanoseconds. The GPS module's serial NMEA output alone is only accurate to within a second or so due to processing and transmission delay, but the PPS pin — a hardware pulse that fires at the exact start of each UTC second — is accurate to tens of nanoseconds once the receiver has a satellite lock. Combining the NMEA sentence (which second it is) with the PPS edge (exactly when that second starts) gives the Pi a time reference that's dramatically better than anything reachable over the internet.

Wiring the GPS Module

GPS module pinRaspberry Pi GPIO pin VCC3.3V (physical pin 1) GNDGND (physical pin 6) TX (module) → RX (Pi)GPIO 15 / RXD (physical pin 10) RX (module) ← TX (Pi)GPIO 14 / TXD (physical pin 8) PPSGPIO 18 (physical pin 12) — or any free GPIO, configured below

Base OS Configuration

  1. Flash Raspberry Pi OS Lite (64-bit, headless) with Raspberry Pi Imager, enabling SSH in the imager's advanced options before first boot.
  2. Disable the serial console (so the OS doesn't fight the GPS module for the UART) but keep the hardware UART enabled: run sudo raspi-config → Interface Options → Serial Port → "No" to login shell over serial, "Yes" to hardware serial enabled.
  3. Edit /boot/firmware/config.txt and add:
    dtoverlay=pps-gpio,gpiopin=18
    enable_uart=1
  4. Reboot, then confirm the PPS device exists: ls /dev/pps0 should return without error.

Installing GPS and PPS Tools

  1. Install the required packages: sudo apt update && sudo apt install -y gpsd gpsd-clients pps-tools chrony
  2. Test the raw PPS signal is arriving: sudo ppstest /dev/pps0 should print a steady stream of timestamps roughly one second apart once the GPS has a lock (a lock can take several minutes outdoors, longer near a window, and won't happen indoors away from any window at all).
  3. Configure gpsd to use the correct serial device by editing /etc/default/gpsd: set DEVICES="/dev/ttyAMA0" (or /dev/serial0 depending on Pi model) and GPSD_OPTIONS="-n".
  4. Verify NMEA data is flowing with cgps -s — watch for a 3D fix and a reasonable satellite count (6+ is solid) before moving on.

Configuring Chrony as the Stratum 1 Source

Edit /etc/chrony/chrony.conf and add:

refclock SHM 0 offset 0.0 delay 0.2 refid GPS noselect refclock PPS /dev/pps0 refid PPS lock GPS

This tells chrony to use the coarse NMEA time (via gpsd's shared memory segment) only to identify which second it is, then discipline the actual clock against the much more precise PPS edge, locked to the GPS reference. Restart chrony (sudo systemctl restart chrony) and after a few minutes check status with chronyc sources -v and chronyc tracking — a healthy setup shows the PPS refclock selected with a system time offset in the tens of microseconds or better.

Serving Time to the Local Network

Add an allow line to chrony.conf for your LAN subnet, e.g. allow 192.168.1.0/24, then restart chrony again. Point other devices — a home server, a NAS, security camera NVR, or another Pi — at this Pi's IP address as their NTP source, either individually or via a DHCP option on the router so the whole network picks it up automatically.

Verifying Accuracy

CheckCommandWhat to look for GPS fix qualitycgps -s3D fix, 6+ satellites PPS signal presentsudo ppstest /dev/pps0Steady ~1 second interval timestamps Chrony source selectionchronyc sources -vPPS refclock marked with an asterisk (currently selected) System clock offsetchronyc tracking"System time" offset in the microsecond range Stratum levelchronyc trackingStratum 1 (this Pi is now a primary reference itself)

Troubleshooting

Once running, this box quietly becomes the most accurate clock on the network, disciplined by satellites rather than by trust in an upstream server several hops away. It's a genuinely small build — a GPS module, some GPIO wiring, and a chrony config — for a piece of infrastructure that most home networks never have and would rarely miss, right up until precise timestamps actually matter.