Homelab · Part 6

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.

Quick idea: dc01 holds every FSMO role in this lab, including PDC emulator, which makes it the one machine that is supposed to reach outside Active Directory for time. This part points dc01 at external NTP servers with w32tm /config /manualpeerlist, confirms dc02 still follows dc01 through the normal domain hierarchy, and verifies both with w32tm /query.
PDC Emulator

The one domain controller per forest that’s supposed to look outside AD for the correct time.

w32tm

The command-line tool used to configure, query, and troubleshoot the Windows Time service.

Clock Skew

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.

Series scope: This post continues from Part 4 — Domain Controllers and Part 5 — DNS. It assumes dc01 (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.

dc01 (PDC Emulator)

Must point at an external NTP source directly. This is the only machine in the lab that should.

dc02 (Ordinary DC)

Left on its default NT5DS setting, it already follows dc01 automatically. Nothing to configure.

Everything Else

Any future domain-joined VM in this lab inherits the hierarchy the same way dc02 does — no per-machine setup.

Important: Never point dc02, or any other domain member added later in this series, at an external NTP server directly. Doing so breaks the single hierarchy the whole domain relies on and makes clock skew between machines far more likely, not less.

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
/manualpeerlistSpace-delimited list of DNS names or IP addresses to sync from, quoted because it holds multiple entries.
,0x8Marks 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:manualTells W32Time to sync from the manual peer list instead of the domain hierarchy (domhier).
/reliable:yesMarks this computer as a reliable time source. Only meaningful on a domain controller, which dc01 is.
/updateApplies the configuration change immediately instead of waiting for the next poll cycle.
Practical rule: The example Microsoft publishes for this exact scenario uses a single NIST server at Microsoft’s Redmond campus. This lab uses three independent providers instead — Cloudflare, NIST, and the NTP Pool Project — so that one provider having a bad day doesn’t leave dc01 with nothing to compare against.

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
Healthy output: 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
Healthy output: 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.

Key point: This lab has not needed to touch that five-minute default, and shouldn’t — it is a reasonable value for almost every environment. What this part actually fixes is making sure dc01’s own clock stays close enough to reality that the five-minute budget is never spent on drift that a correctly configured PDC emulator would have avoided.

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.

Key takeaway: Before moving on to Part 7, confirm 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.
Next in this series

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.