Skip to content
234 changes: 234 additions & 0 deletions docs/management/time-synchronization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
---
sidebar_position: 8
---

# Time synchronization
Comment thread
thomas-dkmt marked this conversation as resolved.

XCP-ng keeps the dom0 clock synchronized using `chronyd`. A host whose date is wrong keeps
working normally until something needs to trust that date. When that happens, the resulting
failures rarely point to the clock as the cause. This page explains why the clock matters, how
to configure NTP, and how to check and correct it.

## Why the clock must be correct {#why-the-clock-must-be-correct}

- **Access to the repositories.** Updates are fetched over HTTPS, and TLS validates the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would put this item at end of this list, since a non accurate time is not too annoying for https

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the one I would push back on. An inaccurate clock does not merely annoy HTTPS: if the host's date falls outside the certificate's validity window, the handshake fails outright and nothing is fetched. I tested that on a host earlier today, and it is the whole subject of the companion PR #504.

It is also the reason people arrive at this page. Forum threads 11558 and 9560 are both someone whose yum stopped working with an error that never mentions time, and the second one ends with nobody working it out. The item is first because it is the failure that hides its own cause, not because it is the most severe.

The pool and certificate items are arguably worse when they bite. They are just easier to recognise.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would still insist on moving it further down. Failure to join update repositories doesn't have a direct impact production, whereas failure to communicate correctly between hosts can prevent you from performing important operations.

server's certificate against the host's own date. If the host's clock is set too far in the
past, the TLS handshake fails because, from the host's perspective, the mirror's certificate
is not yet valid. The error `yum` prints in that situation does not mention time.
- **Pool membership.** A host joining a pool must have its clock synchronized with the pool

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be worth expanding on. Same time when joining is necessary, but we also want it not to drift later, as this can cause subtle synchronization issues, and I'm not sure it's entirely covered by the next bullet point about certificates (which are used by hosts to authenticate to each other, notably).

@gounthar gounthar Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expanded it. The bullet now covers staying synchronized as well as joining, and says why the second is the harder one to catch: a failed join tells you what is wrong; drift afterwards does not. It surfaces as hosts disagreeing about when things happened, each convinced by its own clock.

I kept it separate from the certificates bullet, since that is a different mechanism, and folded the old Pools section into this bullet as well, per your comment further down.

master, and must stay synchronized afterwards. A failed join tells you what is wrong. Drift
that sets in later does not: it surfaces as hosts disagreeing about when things happened,
each of them convinced by its own clock. Keep every host in a pool on the same time sources.
See [Pool Requirements](../../installation/requirements#pool-requirements) for the other
conditions a host has to meet before it can join.
Comment on lines +18 to +23

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested rewording. Straight out of my fingers, so feel free to improve the language correctness.

Suggested change
- **Pool membership.** A host joining a pool must have its clock synchronized with the pool
master, and must stay synchronized afterwards. A failed join tells you what is wrong. Drift
that sets in later does not: it surfaces as hosts disagreeing about when things happened,
each of them convinced by its own clock. Keep every host in a pool on the same time sources.
See [Pool Requirements](../../installation/requirements#pool-requirements) for the other
conditions a host has to meet before it can join.
- **Hosts synchronization inside a pool.** Desynchronized time references between hosts
in a pool can cause a variety of subtle issues for operations that require the hosts to agree
on the current time. As such, it is necessary for hosts to synchronize time from a common
source. Disagreeing clocks can also prevent adding a new host to an existing pool. The correct
way to fix it is to ensure synchronization works, rather than a one time fix which would let
them drift apart in the future.

- **Certificates.** Certificates are only valid inside a validity window. A host whose date
falls outside that window will reject, or be rejected by, connections that would otherwise
succeed.
- **Logs and scheduled operations.** Correlating events across the hosts of a pool, and
anything that runs on a schedule such as backups, depend on the hosts agreeing on what
time it is.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here let's add a word about Xen Orchestra, which, when used, must also have a synchronized clock?

## How XCP-ng keeps time {#how-xcp-ng-keeps-time}

The time daemon on dom0 is `chronyd`, configured through `/etc/chrony.conf`.

The default configuration enables `rtcsync`, allowing chronyd to keep the hardware clock
synchronized with the system clock automatically. There is no need to manually update the
hardware clock after correcting the system time, and the correction persists across reboots.

It also sets `makestep 1.0 3`, which lets chronyd jump the clock rather than ease it into
place, for the first three updates after the service starts. A host that boots with a badly
wrong date therefore fixes itself within seconds, as long as it can reach a time source.
Measured on 8.3: a clock put 45 days in the past was corrected between five and ten seconds
after `chronyd` started.
Comment on lines +42 to +43

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove this log-like precision.


After those three updates chronyd only slews, which for an offset of months or years never

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't know verb "to slew", and think that "gradually adjusts" who be easier to understand by non-native english speakers like me.

converges. That is the case the manual correction below exists for, along with the host that
had no time source to begin with.
Comment on lines +46 to +47

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not so sure about this claim. As I understand it, a reboot fixes the clock if ntp is correctly configured, so:

  • either the hosts haven't been rebooted in a very long time and they're likely behind on updates, and should probably be updated+rebooted.
  • if rebooting doesn't fix the problem, it's probably elsewhere and not caused by the fact that chronyd can only gradually adjust time after first three times since last reboot, but by another, bigger cause (heavily drifting hardware clock, misconfigured ntp or failure to join it due to firewall...).


## Configuring the time sources {#configuring-the-time-sources}

### During installation

The installer prompts you to enter the time, select a time zone, and either configure NTP
servers or set the time manually. Always configure at least one NTP server (see
[Install XCP-ng](../../installation/install-xcp-ng) for where this falls in the installation
sequence).

:::warning
If you set the time manually at this step, the host can end up with `chronyd` running but no
time source configured at all. The clock still ticks, but nothing ever checks it: it drifts
from the date you typed, and if that date was wrong, it stays wrong. This is also the one
case that does not fix itself at boot, since `makestep` needs a source to measure against.
Comment on lines +61 to +62

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"This is also the one case that does not fix itself at boot, since makestep needs a source to measure against."

=> this could be removed, if the sentence just above would say that nothing adjusts it (instead of checks it).

[Checking the time sources](#checking-the-time-sources) below shows how to recognise that
state on a running host.
:::

### During an automated installation

The installation answer file accepts one or more NTP servers through the `<ntp-server>`
element (see [Answer file](../../appendix/answerfile) for its syntax).

### On an installed host

Use `xsconsole`. Its NTP screen adds and removes time servers and restarts `chronyd` for you.

:::warning
Editing `/etc/chrony.conf` by hand is a last resort, for when no other route works. Reach for
`xsconsole` first.

Xen Orchestra does not configure NTP on hosts. Its `xoa network ntp` command sets the time
servers of the XOA appliance itself, which is a Debian VM keeping its own clock, and the NTP
field in the XOA deployment form does the same for the appliance being deployed. Neither
touches the chrony configuration of the hosts XO manages.
:::

## Checking the time sources {#checking-the-time-sources}

Check that the service is running, and that it actually has something to synchronize with:

```bash
systemctl status chronyd
chronyc sources

@rzr rzr Aug 12, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you can mention the default/expected result is:

systemctl status chronyd

   Active: active (running) since Tue 2026-08-11 21:26:08 GMT; 9h ago


chronyc sources
210 Number of sources = 4
MS Name/IP address         Stratum Poll Reach LastRx Last sample               
===============================================================================
^+ (...)                      1  10   377   276   +320us[ +320us] +/-   17ms
(...)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added, with the output taken off an 8.3 host here rather than composed. Running it turned up something I'd missed: the legend listed *, + and ?, but a normal four-source listing is mostly -, which wasn't explained anywhere. So - is in the list now, along with the ^ source-type character.

```

Both matter, and the second is the one that gets skipped. `chronyd` can be running and
enabled while having **no time sources configured at all**:

```
# chronyc sources
210 Number of sources = 0
```

Then, the service behaves exactly as configured, and does nothing. Every other check an
operator would normally run looks healthy, which is what makes this one worth running early
rather than late.

On a host that is synchronizing normally, the same two commands look like this:

```
# systemctl status chronyd
● chronyd.service - NTP client/server
Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2026-08-12 08:38:14 CEST; 46min ago

# chronyc sources
210 Number of sources = 4
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^* ntp1.example.net 2 7 377 59 -361us[ -444us] +/- 8522us
^+ ntp2.example.net 3 9 377 118 +203us[ +122us] +/- 12ms
^+ ntp3.example.net 2 9 377 113 -1029us[-1110us] +/- 9934us
^- ntp4.example.net 3 8 377 506 +688us[ +491us] +/- 49ms
```

In the `MS` column, the first character is the source type, `^` for a server, and the second
is the state of that source:

- `*` marks the one currently being used.
- `+` marks another acceptable source, combined with it.
- `-` marks a source chrony is measuring but has excluded from the combination.
- `?` means the source is unreachable.

At least one source should reach the `*` state. Seeing `-` on some of the others is normal
and does not need correcting.

To see the offset chrony believes it has, and whether it has settled:

```bash
chronyc tracking
```

## Correcting a wrong clock {#correcting-a-wrong-clock}

A host with working time sources does not usually have a wrong clock, because chronyd steps
it within seconds of starting. So a clock that is still wrong is telling you that something
upstream of it is broken. Find that first. Stepping the clock by hand gets you working again
today, and if you stop there the date is wrong again in a few weeks.

Work outward, from the configuration to the network:

1. **Are there any sources?** `chronyc sources`. `Number of sources = 0` means none were
ever configured, which is the manual-time-at-install case. Add them with `xsconsole`.
2. **Are they reachable?** Sources stuck at `?` are configured but unanswered. NTP goes out
over UDP 123, so a firewall between the host and its servers produces exactly this, as
does a network with no route to the public pool, which
[Networks without internet access](#networks-without-internet-access) below covers.
Comment on lines +153 to +156

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could also be that the ntp server they have chosen doesn't exist anymore

3. **Is the daemon healthy?** `systemctl status chronyd`, and `journalctl -u chronyd` for
what it made of its configuration at startup.
4. **Was the configuration changed underneath you?** `rpm -V chrony` reports whether
`/etc/chrony.conf` still matches the package. Hand edits and `xsconsole` both show up here.
Comment on lines +159 to +160

@stormi stormi Aug 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have doubts about this one. Can you verify?

  1. If xsconsole changes chrony.conf, then of course it will differ from the base file provided by the package
  2. more generally, rpm -V checks differences between a file as provided by the RPM package and what's on the system. For a configuration file, it's natural that there's a difference. It's there for this purpose. I don't know what rpm -V says here but I wouldn't be surprised if either it would always show it different (with a flag stating that it's configuration), or always ignore it. It also depends whether the file is declared %config or %config(noreplace) in the RPM spec file. Here, we have %config(noreplace) %{_sysconfdir}/chrony.conf which means that the RPM must not overwrite the file with future updates if the sysadmin (XAPI/xsconsole being considered an extension of the sysadmin for this purpose) has made any change to the file.

So, the output of rpm -V tells you nothing here, except maybe in some cases "it was never configured", but you would already have found out with earlier checks.

What you probably really want is to determine if something has modified the configuration outside the supported way (installer, xsconsole, xe/XAPI), and I'm not sure there's an answer to this one, but I haven't digged into the details.


Once sources are reachable, restarting the daemon corrects the clock on its own, because the
`makestep` allowance applies again from a fresh start:
Comment on lines +162 to +163

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To understand this, one must have read #how-xcp-ng-keeps-time


```bash
systemctl restart chronyd
chronyc sources
date
```

### Stepping the clock immediately

If you need the correct date right now and the daemon has been running for a while, its
`makestep` allowance is already spent and it will only slew:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment about "slew" that earlier.


```bash
chronyc makestep
date
```

This is a stopgap. It needs at least one reachable source to have something to step to, and
on a host with `Number of sources = 0` it reports success while moving nothing. It also does
nothing about the reason the clock was wrong, so treat it as buying time for the diagnosis
above rather than as the end of it.

:::note
**Check the host certificate after a large correction.**

XAPI issues certificates with a ten-year validity, anchored on the clock at the moment they
are generated. Small corrections stay comfortably inside that window, so most of the time
there is nothing to do.

A big correction is different. A host that generated its certificates believing the year was
2016 holds them valid 2016 to 2026, and moving the clock to the real date can leave them
expired. A clock set far into the future produces the mirror image: certificates not valid
yet once the date is corrected backwards.

There are two, and they are refreshed by different commands:

| Certificate | What it is | Regenerate with |
|---|---|---|
| `/etc/xensource/xapi-ssl.pem` | The TLS certificate clients see, including Xen Orchestra | `xe host-reset-server-certificate` |
| `/etc/xensource/xapi-pool-tls.pem` | The internal certificate hosts use between themselves | `xe host-refresh-server-certificate host=<host>` |

Check both windows against the corrected date:

```bash
openssl x509 -in /etc/xensource/xapi-ssl.pem -noout -dates
openssl x509 -in /etc/xensource/xapi-pool-tls.pem -noout -dates
date -u
```

If the date falls outside `notBefore` to `notAfter`, regenerate the one concerned using the
table above. Do not reach for `host-refresh-server-certificate` to fix `xapi-ssl.pem`: it
refreshes the internal certificate, reports success, and leaves the TLS one untouched.

On a host whose TLS certificate is already rejected, and which therefore cannot be reached the
usual way, `xe host-emergency-reset-server-certificate` runs locally on the host itself.
:::
Comment on lines +186 to +219

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should just be a short note explaining how to verify the certificate validity periods. How to renew certificates is a topic that doesn't belong here. There's an old draft on this whole topic, which stalled: #216

The certificate topic is a big one in itself, we should cover it independently.


:::tip
If `date` is wrong again after every power cycle, the motherboard's RTC battery is probably
dead and should be replaced. `rtcsync` can only keep the hardware clock in step while the
host is running; it cannot help a clock that loses its value when the power goes.
Comment on lines +222 to +224

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What consequences does it have? Doesn't chronyd fix the date shortly after initial startup? Does it cause problems at startup that do not self-heal?

@gounthar gounthar Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, chronyd fixes it quickly, as long as it has a source.

The stock /etc/chrony.conf carries makestep 1.0 3, so for the first three updates after the service starts, it jumps the clock instead of easing it into place. I stopped chronyd, put the clock 45 days into the past, and started it again:

skew    2026-07-03T12:17:41Z   chronyd started
t+05s   2026-07-03  still wrong
t+10s   2026-08-17T12:17:46Z   corrected

Under ten seconds for 45 days. The page claimed chrony only slews and so never converges for offsets of months or years, which is true once those three updates are spent and wrong at startup. Fixed, and it changes the shape of the page: a host with sources heals itself, so the manual correction is for the daemon that has been up a while, or the host that never had a source at all.

What does not self-heal is Number of sources = 0, since makestep needs something to measure against. That is now said where the manual-time-at-install warning is.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If date is wrong again after every power cycle

This part implies, to me, that we you get a wrong date again after every power cycle DESPITE ntp, and I don't see how that is possible thanks to makestep, unless there's a problem with the ntp configuration which must then be fixed and the battery then doesn't matter. Or does it?

It's still unclear to me what the problem is if you have a dead battery, outside the fact that the clock needs to be fixed at each boot (implying a part of the boot process with wrong log times and maybe worse consequences that I can't foresee).

:::

## Networks without internet access {#networks-without-internet-access}

Hosts without Internet access cannot reach the public NTP pool. The result is the same as
having no sources at all: `chronyc sources` lists servers that never leave the `?` state.

On such networks, point the hosts at a time source they can actually reach, using `xsconsole`
as above: an appliance on the same network, or a local server that is itself synchronized and
acts as the reference time for the network.
Comment on lines +232 to +234

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using xsconsole is one way to do it, for an already installed host. But here we're not in the troubleshooting part of the document anymore, so the best course of action is to set it right at installation time.