Der NTP Pool lebt von Freiwilligen, die ihre Server als öffentliche Zeitquelle zur Verfügung stellen. Da mein Netcup-VPS ohnehin schon per Chrony mit NTS gegen mehrere Stratum-1-Quellen synchronisiert, lag es nahe, ihn auch aktiv am Pool teilnehmen zu lassen. In diesem Artikel dokumentiere ich die Konfiguration und wie ich sie vor der Anmeldung getestet habe.
Ausgangslage
Mein VPS lief bereits mit folgender Chrony-Basiskonfiguration:
server time.cloudflare.com iburst nts
server ptbtime1.ptb.de iburst nts
server ptbtime2.ptb.de iburst nts
makestep 1.0 3
rtcsync
Damit synct der Server bereits stabil als Stratum-2-Client gegen Cloudflare und die PTB (Physikalisch-Technische Bundesanstalt). Für die Pool-Teilnahme fehlten aber zwei Dinge: eine allow-Freigabe für eingehende Client-Anfragen und ein Rate-Limiting gegen Missbrauch.
Chrony für Client-Anfragen öffnen
Ohne explizite allow-Direktive beantwortet Chrony ausschließlich die eigenen Upstream-Anfragen – eingehende Zeitanfragen von außen werden sonst stillschweigend verworfen. Ergänzt habe ich:
allow 0.0.0.0/0
allow ::/0
ratelimit interval 1 burst 8 leak 2
ratelimit begrenzt, wie oft eine einzelne IP innerhalb eines Zeitfensters beantwortet wird. Das ist vor allem wichtig, weil NTP historisch für Amplification-Angriffe missbraucht wurde (v. a. über das inzwischen aus modernem NTP entfernte monlist-Kommando). Mit Rate-Limiting bleibt der Server auch bei ungewöhnlichen Anfragemustern kontrollierbar.
Redundanz der Zeitquellen erhöhen
Mit nur drei Upstream-Quellen – davon zwei von derselben Institution – hat Chronys Selektionsalgorithmus wenig Spielraum, einen Ausreißer zuverlässig zu erkennen. Ergänzt habe ich einen echten Pool-Eintrag:
pool 2.de.pool.ntp.org iburst
minsources 2
Der Unterschied zwischen server und pool ist wichtig: server ist für einzelne, feste Hosts gedacht (wie die PTB-Server), pool für DNS-Namen, die zu mehreren wechselnden IPs auflösen – Chrony wählt sich daraus automatisch mehrere Quellen. minsources 2 verhindert außerdem, dass der Server synct, sobald nur noch eine einzige Quelle übrig ist – gerade als Pool-Teilnehmer sollte man selbst keine fehlerhafte Zeit weitergeben.
Die finale Konfiguration:
server time.cloudflare.com iburst nts
server ptbtime1.ptb.de iburst nts
server ptbtime2.ptb.de iburst nts
pool 2.de.pool.ntp.org iburst
server time1.uni-stuttgart.de iburst
server ntp1.rrze.uni-erlangen.de iburst
minsources 2
makestep 1.0 3
rtcsync
driftfile /var/lib/chrony/drift
bindcmdaddress ::1
allow 0.0.0.0/0
allow ::/0
ratelimit interval 1 burst 8 leak 2
Ein Hinweis zum Kommandoport (323): bindcmdaddress ::1 sorgt dafür, dass chronyc-Befehle nur lokal ausgeführt werden können. Eine zusätzliche cmdallow-Direktive, die den Kommandoport global öffnet, braucht es für die Pool-Teilnahme nicht – im Gegenteil, das wäre ein unnötiges Sicherheitsrisiko. Dazu findet man auch offizielle Konfigurationsempfehlungen.
Firewall-Freigaben
Auf Serverebene reicht eine einfache UFW-Regel:
sudo ufw allow 123/udp comment 'NTP Pool'
Bei einer vorgelagerten, zustandslosen (stateless) Firewall lohnt sich ein zweiter Blick: Hier ist es entscheidend, Port 123 als Destination Port für eingehenden Traffic freizugeben – nicht als Source Port. Eine Regel, die nur Pakete von Port 123 erlaubt, deckt lediglich die ausgehenden Antworten des eigenen Chrony-Clients an die Upstream-Server ab, nicht aber eingehende Anfragen von Pool-Clients. Das war bei mir tatsächlich die Ursache, warum externe Testanfragen zunächst ins Leere liefen, obwohl Chrony und UFW schon korrekt konfiguriert waren.
Testen vor der Anmeldung
Bevor man sich im Pool registriert, sollte der Server einige Tage im „Echtbetrieb“ laufen, um Stabilität zu verifizieren – der eigene Score im Pool baut sich ohnehin erst über mehrere Tage auf, ein Vortest kostet also praktisch keine Zeit.
Lokale Diagnose auf dem VPS:
sudo ss -ulnp | grep :123 # Lauscht Chrony auf allen Interfaces?
sudo chronyc tracking # Aktueller Stratum, Offset, Skew
sudo chronyc sourcestats # Stabilität der einzelnen Quellen über Zeit
sudo chronyc clients # Eingehende Client-Anfragen, inkl. Drop-Zähler
Ein Mitschnitt mit tcpdump hilft, um zu sehen, ob externe Testpakete überhaupt am Server ankommen – nützlich, um zu unterscheiden, ob ein Problem an einer vorgelagerten Firewall liegt oder an der Chrony-Konfiguration selbst:
sudo tcpdump -ni any udp port 123 -v
Verbindungstest von einem externen Windows-Rechner:
Da ntpdate unter Windows nicht verfügbar ist, eignet sich das Bordmittel w32tm:
w32tm /stripchart /computer:<vps-ip> /samples:3 /dataonly /packetinfo
Ein Timeout-Fehler (0x800705B4) bedeutet, dass zwar ein Anfrage-Paket verschickt wurde, aber keine Antwort zurückkam – typisches Symptom, wenn entweder allow in Chrony fehlt oder eine Firewall (lokal oder vorgelagert) die Antwort blockiert. Sobald alles korrekt konfiguriert ist, liefert der Befehl statt eines Timeouts einen echten Zeit-Offset-Wert zurück.
Auf Last vorbereitet sein:
Ressourcentechnisch ist NTP-Traffic auch bei mehreren hundert gleichzeitigen Clients auf einem kleinen VPS kein Thema – ein einzelnes UDP-Paket wird in Mikrosekunden verarbeitet, CPU- und RAM-Last bleiben verschwindend gering. Relevanter ist das monatliche Traffic-Volumen, das im NTP-Pool-Panel selbst über ein einstellbares Limit gesteuert wird.
Ergebnis
Nach ein paar Tagen Testbetrieb zeigte chronyc tracking einen System-Offset im niedrigen Mikrosekundenbereich und einen stabilen Skew unter 0,25 ppm – solide Werte für die Anmeldung im Pool. Der eigentliche Fehler auf dem Weg dorthin war unspektakulär, aber lehrreich: eine vertauschte Source-/Destination-Port-Regel in der vorgelagerten Firewall, die sich erst durch den kombinierten Einsatz von tcpdump auf dem Server und w32tm von außen sauber eingrenzen ließ.
Anmeldung am NTP Pool
Über den Link findet man weitere Informationen und kann dort einen Account anlegen seine Server eintragen. Anschließend werden die Server gemonitored und sobald sie Score >10 erreichen, werden sie in das Cluster mit aufgenommen. Bei mir hat das ca. 6-7h gedauert. Dabei wird IPv4 und IPv6 unterschiedlich bewertet.
Meine öffentliche Profilseite.
Ein Einblick in die Anzahl der Requests findet man im Statistikdashboard
Erfahrungswerte nach sieben Wochen teil des Pools
Seit dem 09.09.2026 ist mein Server im Pool. Nach rund drei Tagen Anlaufphase lag die Last stabil bei etwa einer halben Million Anfragen pro Tag. Am 23.10. habe ich die Net-Speed-Einstellung im Pool für IPv4 und IPv6 von je 12 auf je 25 Mbit/s erhöht. Seitdem hat sich die Zahl der Anfragen ziemlich genau verdoppelt.
| Kennzahl (Median pro Tag) | 12 Mbit/s je IPv4/IPv6 | 25 Mbit/s je IPv4/IPv6 |
|---|---|---|
| Zeitraum | 12.09. bis 22.10.2026 (41 Tage) | 24.10. bis 29.10.2026 (6 Tage) |
| Anfragen pro Tag | ca. 511.000 | ca. 1.009.000 |
| Anfragen pro Sekunde (Ø über den Tag) | ca. 5,9 | ca. 11,7 |
| Ausgehender Traffic pro Tag | ca. 37 MiB | ca. 71 MiB |
| Ausgehender Traffic hochgerechnet auf 30 Tage | ca. 1,1 GiB | ca. 2,1 GiB |
| Spannweite der Tageswerte (Anfragen) | 416.000 bis 641.000 (ein Ausreißer: 1,24 Mio.) | 943.000 bis 1.032.000 |
Ein paar Dinge, die mich überrascht haben:
- Net Speed ist kein Limit, sondern ein Gewicht. Der Wert sagt dem Pool nur, wie oft dein Server im DNS-Round-Robin ausgegeben wird. Tatsächlich genutzt werden davon nur wenige Kilobit pro Sekunde. Doppelte Einstellung, doppelte Last: aus 12 auf 25 Mbit/s (Faktor 2,1) wurden fast genau doppelt so viele Anfragen (Faktor 2,0).
- Eine NTP-Antwort ist winzig. Im Schnitt gehen rund 75 Byte pro Anfrage raus. Eine Million Anfragen am Tag sind damit gut 70 MiB. Für einen VPS mit Inklusiv-Traffic spielt das keine Rolle.
- IPv6 ist eine Nebenrolle. In einer Momentaufnahme kamen rund 94 % der Anfragen über IPv4 (9,3 von 9,9 Anfragen pro Sekunde).
- Es gibt Ausreißer. Am 21.10. kamen an einem Tag 1,24 Millionen Anfragen, gut doppelt so viele wie üblich. Der Median glättet solche Tage weg, deshalb steht er in der Tabelle und nicht der Mittelwert.


