Homelab Build — Part 6 — Time Hierarchy
dc01 has been quietly inheriting whatever time its VM host happened to have since Part 4 — this part points it at an actual authoritative external source, confirms dc02 still follows the domain hierarchy behind it, and explains why five minutes of drift is enough to break Kerberos.
w32tm /config /manualpeerlist, confirms dc02 still follows dc01 through the normal domain hierarchy, and verifies both with w32tm /query.
The one domain controller per forest that’s supposed to look outside AD for the correct time.
The command-line tool used to configure, query, and troubleshoot the Windows Time service.
The gap between two clocks. Past five minutes by default, Kerberos stops trusting either one.
What This Part Covers
Parts 4 and 5 left time exactly where Install-ADDSForest and Windows setup put it: dc01 and dc02 both trust whatever clock their Proxmox VM inherited at boot, with no external source configured on either one. That has worked so far because both VMs share the same hypervisor host, so their clocks have never had a reason to drift apart from each other. It has not been correct, and the gap between “hasn’t broken yet” and “configured on purpose” is exactly what this part closes.
Think of the domain’s time hierarchy as a chain of command that only works if someone at the top is actually looking outside the organisation. Every domain-joined computer defers to its domain controller, every domain controller defers to the PDC emulator, and the PDC emulator is the one role in the whole forest that is supposed to break that chain deliberately and sync from somewhere real.
10.10.10.10) created the forest and therefore holds all five FSMO roles, including PDC emulator, and dc02 (10.10.10.11) is a second, ordinary domain controller. For the full mechanics of the Windows Time service and the domain hierarchy generally, see The Windows Time Service (W32Time) — this post applies that background to this specific lab rather than repeating it.
Why Only dc01 Reaches Outside
Every domain-joined computer in this lab, dc02 included, has its Type registry value under HKLM\SYSTEM\CurrentControlSet\Services\W32Time\Parameters set to NT5DS by default — “synchronize from the domain hierarchy.” In a single-domain, single-site forest like this one, that resolves to one thing: sync from whichever domain controller holds the PDC emulator role, which is dc01.
dc01 sits at the top of that hierarchy, which makes syncing it from the domain hierarchy a contradiction — there is nothing above it to sync from. If dc01 is left on its default NT5DS setting, W32Time notices the problem itself and logs event ID 12 from the W32Time source, warning that the PDC emulator is configured to sync from the domain hierarchy, which is not valid.
Must point at an external NTP source directly. This is the only machine in the lab that should.
Left on its default NT5DS setting, it already follows dc01 automatically. Nothing to configure.
Any future domain-joined VM in this lab inherits the hierarchy the same way dc02 does — no per-machine setup.
Configuring dc01 as the Authoritative Time Source
Microsoft’s own recommendation for a lab or production forest alike is to point the PDC emulator at three or more external NTP servers rather than one, since the improved synchronization algorithms in Windows Server 2016 and later were built around comparing multiple sources rather than trusting a single peer outright. This lab runs Windows Server 2025 throughout, so the modern algorithm applies without any extra configuration.
# On dc01 only: point at three external NTP sources, sync manually rather than from
# the domain hierarchy, and mark this server as reliable
w32tm /config /manualpeerlist:"time.cloudflare.com,0x8 time.nist.gov,0x8 pool.ntp.org,0x8" /syncfromflags:manual /reliable:yes /update
# Force W32Time to pick up the new configuration and re-discover its sources immediately
w32tm /resync /rediscover
| Flag | Purpose |
|---|---|
/manualpeerlist | Space-delimited list of DNS names or IP addresses to sync from, quoted because it holds multiple entries. |
,0x8 | Marks each peer as a client-mode source — the standard flag for a normal NTP peer, as opposed to symmetric-active mode or a fallback-only source. |
/syncfromflags:manual | Tells W32Time to sync from the manual peer list instead of the domain hierarchy (domhier). |
/reliable:yes | Marks this computer as a reliable time source. Only meaningful on a domain controller, which dc01 is. |
/update | Applies the configuration change immediately instead of waiting for the next poll cycle. |
Confirming dc02 Still Follows the Hierarchy
dc02 needs no configuration change at all — the point of this section is to confirm that, not assume it. A domain-joined server that has never had its Type value touched should already show NT5DS and should already be resolving dc01 as its time partner.
# On dc02: confirm it is still on the domain hierarchy setting, not a manual override
w32tm /query /configuration
# On dc02: confirm the actual computer it is currently syncing from
w32tm /query /source
w32tm /query /source on dc02 should return dc01.lab.example.com, not an external NTP name and not “Local CMOS Clock”. If it returns anything else, dc02’s Type value has been changed from its default at some point and should be reset to NT5DS.
Verifying the Time Hierarchy End to End
Run these on dc01 after the reconfiguration, then again on dc02, to confirm the hierarchy actually behaves the way it is supposed to rather than assuming the commands above were enough on their own.
# On dc01: confirm which external peers it is using and their current state
w32tm /query /peers
# On dc01: full sync status, including current offset and last successful sync
w32tm /query /status /verbose
# On either DC: check the runtime configuration and which policy or registry value set each setting
w32tm /query /configuration
w32tm /query /peers on dc01 should list all three configured peers with a low, stable offset. w32tm /query /status should show a recent Last Successful Sync Time and a Source matching one of the three external names, not “Free-running System Clock”.
Why Five Minutes Matters
None of this is cosmetic. Kerberos V5 uses timestamps as part of its own protocol to prevent replay attacks, and for that to work, the client’s clock and the domain controller’s clock have to agree closely enough that a timestamp still means something. The tolerance for that disagreement is a Kerberos policy setting, not a guess: Maximum tolerance for computer clock synchronization, under Computer Configuration\Windows Settings\Security Settings\Account Policies\Kerberos Policy, defaults to five minutes in the Default Domain Policy.
Cross that five-minute threshold in either direction and Kerberos authentication starts failing outright, not degrading gracefully — the exact failure a later part of this series (once client machines join the lab) will be able to demonstrate directly, because it is one of the more common real-world causes of unexplained authentication failures in any AD environment, lab or production.
Time Sync Issues
| Symptom | Likely Cause | Fix |
|---|---|---|
| W32Time event ID 12 on dc01 | dc01 is still configured to sync from the domain hierarchy despite holding the PDC emulator role — the default it inherited from promotion in Part 4. | Re-run the w32tm /config /manualpeerlist ... /syncfromflags:manual /reliable:yes /update command above on dc01 specifically. |
w32tm /query /source on dc01 returns “Local CMOS Clock” |
None of the three external peers were reachable when W32Time last tried to sync, so it fell back to the hardware clock. | Confirm dc01 can resolve and reach the peers over UDP 123 — check the DNS forwarder configured in Part 5 and pfSense’s WAN rules from Part 3 — then run w32tm /resync /rediscover. |
w32tm /query /source on dc02 returns an external NTP name instead of dc01 |
dc02’s Type registry value was changed from the NT5DS default, pointing it outside the domain hierarchy. |
Run w32tm /config /syncfromflags:domhier /update on dc02, then restart the service with Restart-Service w32time. |
| Kerberos authentication fails intermittently between dc01 and dc02 | Clock offset between the two has exceeded the five-minute Kerberos tolerance, usually after one VM was paused or snapshotted for longer than expected. | Check w32tm /query /status /verbose on both DCs for the current offset, then force an immediate correction with w32tm /resync on whichever one has drifted. |
dc01’s offset stays large even after /resync |
All three external peers are unreachable, or firewall rules on pfSense are blocking outbound UDP 123 from the Servers segment. | Confirm outbound UDP 123 is permitted in the pfSense ruleset from Part 3, then test each peer individually with w32tm /stripchart /computer:time.cloudflare.com /samples:5. |
Final Thoughts
Time sync is the kind of homelab task that produces no visible change when it goes right — dc01 and dc02 look exactly the same before and after, and nothing in Server Manager celebrates the fact that w32tm /query /peers now shows three healthy external sources instead of an inherited hypervisor clock. What changed is that the lab’s authentication now rests on a deliberate decision instead of an accident of VM boot order.
What’s still missing on purpose: no certificate authority yet, so no LDAPS or internal TLS anywhere in the lab, and no Group Policy beyond the domain defaults. Part 7 depends directly on what this part fixed — certificate validity checks compare “not before” and “not after” timestamps against the system clock, and a CA issuing or validating certificates against a clock that drifted before this part would have quietly undermined every certificate it touched.
w32tm /query /source on dc01 returns one of the three configured external peers, w32tm /query /source on dc02 returns dc01.lab.example.com, and neither DC’s event log has logged a fresh W32Time event ID 12.
Part 7 stands up Active Directory Certificate Services on dc01, covers the root-versus-subordinate CA decision, and issues the lab’s first certificate — work that depends directly on the time hierarchy this part just made trustworthy.