SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor · Actualizado 2026-08-24

Cómo corregir el desfase del reloj en su VPS

Aprenda a detectar el desfase del reloj de su VPS con chronyc y timedatectl, y restaure la sincronización NTP que puede impedir el acceso con 2FA.

Por qué se desajusta el reloj de su VPS

El reloj de un VPS se desajusta porque nada lo corrige. El kernel cuenta el tiempo a partir de un contador de hardware que funciona un poco más rápido o más lento. Si no hay ningún cliente de sincronización horaria en ejecución, ese pequeño error aumenta cada hora. En una máquina virtual hay una segunda causa: el invitado comparte una CPU física con otros invitados. Por tanto, los intervalos en los que no se programa son intervalos en los que no puede contar.

En un invitado KVM actual, el contador rara vez es el problema real. La fuente kvm-clock paravirtualizada lee un valor que mantiene el host, por lo que un invitado en buen estado sigue de cerca la hora del host. Los relojes que muestran un desfase evidente suelen tener un problema más simple. No se está ejecutando ningún daemon de sincronización, hay dos en ejecución y entran en conflicto, o el tráfico UDP saliente al puerto 123 no sale de la red del proveedor. Un invitado ajusta su hora a partir del host o de NTP (network time protocol), no de su propio oscilador.

Qué problemas causa realmente un reloj incorrecto

  • Los códigos TOTP (contraseña de un solo uso basada en el tiempo) dejan de coincidir y se pierde el acceso a un servidor cuyas credenciales y clave son correctas.
  • Se rechaza un certificado emitido hace un minuto y curl muestra SSL certificate problem: certificate is not yet valid.
  • apt update rechaza un repositorio con E: Release file for ... is not valid yet (invalid for another 1d 2h 3min 4s).
  • Las tareas programadas se ejecutan en el momento incorrecto. Un salto del reloj puede hacer que una tarea se ejecute dos veces y que otra se omita.
  • Los registros de dos servidores no se pueden alinear. La cronología del incidente debe reconstruirse por aproximación.

La tolerancia es menor de lo que suele esperarse. Las cifras siguientes son valores predeterminados documentados, no mediciones de una prueba.

ChartHow far the clock can be off before something breaks (documented defaults)
The data behind this chart
[
  {
    "label": "TLS certificate boundary",
    "tolerance_seconds": 0,
    "documented_in": "RFC 5280"
  },
  {
    "label": "chrony steps instead of slewing",
    "tolerance_seconds": 1,
    "documented_in": "Debian and Ubuntu chrony.conf"
  },
  {
    "label": "TOTP code, one time step",
    "tolerance_seconds": 30,
    "documented_in": "RFC 6238"
  },
  {
    "label": "Kerberos clock skew",
    "tolerance_seconds": 300,
    "documented_in": "MIT krb5 default"
  }
]

Un código TOTP se calcula a partir de un contador que avanza cada 30 segundos, y la mayoría de los verificadores acepta un intervalo a cada lado. Un desfase de medio minuto en cada dirección agota todo el margen disponible. Kerberos es mucho más tolerante, con un margen de desfase predeterminado de 300 segundos. Un certificado no admite ese margen: se comprueba contra instantes fijos con un periodo de gracia de 0 segundos, por lo que un reloj adelantado un segundo rechaza un certificado perfectamente válido.

Los tres relojes y cuál importa

El reloj del sistema es el que importa. Es el CLOCK_REALTIME del kernel: el número de segundos desde el 1 de enero de 1970 UTC, almacenado en memoria y consultado por todo lo que asigna una marca de tiempo. Las líneas de registro, las comprobaciones de certificados, los códigos TOTP y las fechas de modificación de los archivos proceden de él. Cuando alguien dice que la hora del servidor es incorrecta, se refiere a este reloj.

El reloj de hardware, también llamado RTC (real time clock), es un contador independiente que sigue funcionando mientras la máquina está apagada. En una máquina física es un chip respaldado por una batería. Dentro de un guest lo emula el hipervisor, por lo que depende en gran medida del host. Linux lo lee una vez durante el arranque para obtener un valor inicial y después mantiene su propio contador. timedatectl lo muestra en la línea RTC time. No diagnostique problemas a partir de esa línea en un VPS, porque informa de la hora que tiene el host, no del estado de sincronización del reloj del sistema. En un contenedor normalmente no existe ningún /dev/rtc, por lo que hwclock --show falla con hwclock: Cannot access the Hardware Clock via any known method.

La fuente de reloj es el mecanismo que usa el kernel para contar entre esas lecturas. Consulte cuál ha seleccionado el kernel:

cat /sys/devices/system/clocksource/clocksource0/current_clocksource
cat /sys/devices/system/clocksource/clocksource0/available_clocksource

En KVM normalmente verá kvm-clock. Lee un valor que mantiene el host. Por eso, un guest de KVM sin ningún cliente NTP sigue manteniendo una hora aproximada durante un tiempo. tsc es el contador propio de la CPU. Los guests de Xen informan de xen y los guests de Hyper-V informan de una fuente hyperv. No cambie este ajuste salvo que tenga un motivo medido para hacerlo, porque el kernel ya selecciona la mejor fuente en la que confía para ese hardware.

Algunos hosts también proporcionan al guest un dispositivo PTP (precision time protocol), que permite a chrony leer directamente el reloj del host en lugar de hacerlo a través de la red. Conviene comprobarlo, aunque a menudo no está disponible en un VPS compartido:

sudo modprobe ptp_kvm
ls /dev/ptp*
cat /sys/class/ptp/ptp0/clock_name

Si modprobe falla o no aparece ningún dispositivo, el host no lo ofrece y su opción es usar NTP por red. Si clock_name identifica el reloj virtual de KVM, chrony puede usarlo mediante una línea refclock PHC /dev/ptp0 poll 2 en su configuración.

Lee el estado de la hora en tu propia máquina

Empieza con un comando. Responde en una sola pantalla a la pregunta «¿hay algo manteniendo correcta esta hora?».

timedatectl

Lee estas líneas en lugar de confiar en un número que recuerdes:

  • Local time y Universal time representan el mismo instante, mostrado en tu zona horaria y en UTC. Si son idénticos, la máquina ya usa UTC.
  • RTC time es el reloj de hardware descrito arriba. En un VPS, ignóralo.
  • Time zone indica lo que usa el sistema para formatear la hora local.
  • System clock synchronized es el indicador propio del kernel. Un daemon de hora lo establece cuando confía en sus fuentes, por lo que no significa que ningún proceso ha sincronizado este reloj desde el arranque.
  • NTP service informa específicamente sobre systemd-timesyncd. n/a es normal en una máquina que ejecuta chrony, porque timesyncd no está instalado allí. System clock synchronized: yes junto con NTP service: n/a significa que chrony está realizando el trabajo y que el kernel coincide con él.

A continuación, comprueba cuánto se desvía el reloj. No lo compares a ojo con el teléfono. Si chrony está en ejecución:

chronyc tracking
chronyc sources -v

chronyc tracking muestra los valores que responden a la pregunta. System time es el desfase actual respecto a la hora de NTP, seguido de la palabra fast o slow. Last offset es el tamaño de la corrección más reciente. Frequency es el error de frecuencia que chrony ha medido en tu reloj y que ya está compensando. Leap status debería mostrar Normal. Si muestra Not synchronised y Reference ID es 00000000 (), chrony todavía no ha seleccionado una fuente.

chronyc sources -v muestra una leyenda sobre la lista, para que no tengas que recordar los símbolos. Dos columnas contienen la mayor parte de la información. El carácter de estado al principio de cada línea indica cómo evalúa chrony esa fuente: * marca la fuente que está usando actualmente y ? en todas las líneas significa que ninguna responde. Reach es el historial de respuestas de las últimas ocho consultas, mostrado en octal: 377 significa que se respondieron las ocho y 0 significa que no se respondió ninguna.

Si systemd-timesyncd es el responsable:

timedatectl timesync-status
timedatectl show-timesync --all

timesync-status muestra el servidor con el que se comunica, el intervalo de consulta y un valor Offset. Si el comando devuelve un error sobre el servicio en lugar de mostrar el estado, timesyncd no es el daemon responsable en este equipo. Esa también es la respuesta a tu pregunta.

Para realizar una comprobación aproximada frente al exterior sin herramientas adicionales, compara tu reloj con una cabecera HTTP pública Date, que se sirve en GMT con una resolución de un segundo:

date -u
curl -sI https://www.cloudflare.com | grep -i '^date:'

Una diferencia de uno o dos segundos es normal y no significa nada. Una diferencia de un minuto indica un problema en tu equipo.

chrony o systemd-timesyncd en un VPS

Ubuntu y Debian incluyen systemd-timesyncd de forma predeterminada. Es un cliente SNTP (simple network time protocol): consulta un servidor cada vez y ajusta gradualmente el reloj hacia ese valor. En una máquina que permanece conectada y cuyo reloj parte de un valor aproximado, es suficiente y su consumo es prácticamente nulo.

chrony es una implementación completa de NTP y una opción predeterminada más adecuada para una máquina virtual, por motivos que se pueden observar en su propia salida. Consulta varias fuentes a la vez y descarta las que no coinciden. Mide el error de frecuencia del reloj y lo escribe en un archivo de deriva, por lo que corrige la tendencia del reloj en lugar de perseguir cada muestra. También se recupera rápidamente de las dos situaciones que una máquina virtual puede experimentar y un equipo físico no: el host puede pausarla y puede trasladarla a otro host mientras está en ejecución. Cuando el host ofrece un dispositivo PTP, chrony es el encargado de leerlo.

sudo apt update && sudo apt install -y chrony
systemctl status chrony --no-pager
chronyc sources -v
chronyc tracking

Observe la salida de apt mientras se ejecuta. En Debian y Ubuntu, los paquetes chrony y systemd-timesyncd proporcionan ambos time-daemon, por lo que apt elimina timesyncd al instalar chrony. Esto es correcto y esperado. Nunca ejecute ambos, porque dos demonios que ajustan el mismo reloj entrarán en conflicto y no se podrá confiar en el desplazamiento informado por ninguno mientras lo hagan. En Rocky y AlmaLinux, instale con sudo dnf install -y chrony, donde la unidad se llama chronyd en lugar de chrony.

El archivo de configuración es /etc/chrony/chrony.conf en Debian y Ubuntu, y /etc/chrony.conf en Rocky y Alma. La configuración predeterminada de la distribución ya es adecuada para un VPS, así que cámbiela sólo si existe un motivo. Conviene entender dos directivas:

  • Las líneas pool y server especifican las fuentes de tiempo. Añadir iburst indica a chrony que envíe una ráfaga rápida al iniciar, de modo que la primera sincronización se produzca en segundos y no en minutos.
  • makestep determina cuándo chrony adelanta o atrasa el reloj de golpe en lugar de ajustarlo gradualmente. Compruebe su valor con grep -n makestep /etc/chrony/chrony.conf. El valor predeterminado de Debian y Ubuntu, makestep 1 3, significa lo siguiente: durante las tres primeras actualizaciones posteriores al inicio de chronyd, adelanta o atrasa el reloj si presenta una diferencia superior a un segundo; después, lo corrige sólo mediante ajuste gradual.

Si desea autenticar el tráfico horario para detectar manipulaciones en la ruta, chrony 4 y posteriores admiten NTS (network time security). Confirme primero la versión con chronyd -v y tenga en cuenta que NTS necesita abierto el puerto TCP saliente 4460, además del puerto UDP 123:

server time.cloudflare.com iburst nts

Reinicie el servicio y verifique su estado antes de confiar en él. Si la configuración no se puede analizar, se quedará sin ningún demonio de sincronización horaria, y el reloj no se lo indicará.

sudo systemctl restart chrony
chronyc sources -v
chronyc tracking

Por qué un reloj atrasado varios minutos sigue atrasado

Un daemon de tiempo tiene dos formas de corregir un desfase. El ajuste gradual acelera o ralentiza el reloj hasta eliminar el error. Así, el tiempo sigue avanzando y nunca repite ni omite una marca de tiempo. El ajuste inmediato salta directamente al valor correcto. Es rápido, pero puede hacer que el reloj retroceda. Retroceder es peligroso para cualquier elemento que mida el tiempo transcurrido a partir del reloj de pared. Por eso, ambos daemons prefieren el ajuste gradual.

Esta preferencia explica por qué un reloj muy desfasado puede seguir así durante mucho tiempo. chrony sólo hace un ajuste inmediato dentro de la ventana que permite makestep. De forma predeterminada, esa ventana corresponde a las primeras actualizaciones después de iniciar el daemon. Si chronyd lleva una semana activo y después detecta un desfase de cuarenta segundos, lo corregirá gradualmente. Ajustar gradualmente cuarenta segundos tarda mucho más de lo razonable. Fuerce la corrección una vez, de forma deliberada y en un momento de poca actividad:

sudo chronyc makestep
chronyc tracking

chronyc tracking debería mostrar ahora un desfase de System time cercano a cero. Last offset debería mostrar el tamaño de la corrección que se acaba de aplicar. Piense antes de ejecutar esto en un host de base de datos con mucha actividad. Un reloj que retrocede puede confundir al software que presupone que el tiempo sólo avanza. Reiniciar el daemon es una versión más moderada de la misma corrección, porque la ventana de makestep vuelve a abrirse al iniciar.

Los contenedores comparten el reloj del host

Un contenedor no tiene su propio reloj de pared, por lo que no hay nada que sincronizar dentro de él. Los espacios de nombres de tiempo de Linux virtualizan únicamente los relojes monotónico y de tiempo de arranque. CLOCK_REALTIME no se virtualiza, por lo que un contenedor lee el mismo reloj del sistema que el host donde se ejecuta. Corrija el reloj en el host y todos los contenedores de ese host quedarán corregidos en el mismo momento.

Esto tiene varias consecuencias. No instale chrony ni ntpd en una imagen, porque, en el mejor de los casos, no hacen nada. Establecer la fecha dentro de un contenedor sin privilegios falla con date: cannot set date: Operation not permitted, ya que el kernel requiere CAP_SYS_TIME para esa llamada. Conceder CAP_SYS_TIME no proporciona al contenedor un reloj privado. Le proporciona la capacidad de cambiar el reloj del host y, por tanto, también el reloj de todos los demás contenedores.

Una zona horaria diferente dentro de un contenedor no es un problema del reloj. Una imagen que incluya su propio /etc/localtime muestra el mismo instante con el formato de otra zona, por lo que date parece incorrecto aunque el reloj sea correcto. Establezca TZ=UTC en el entorno del contenedor para eliminar la confusión. El runtime que elija no cambia nada en este aspecto. La comparación entre Podman y Docker sin root explica qué aspectos sí cambia.

Zonas horarias: UTC en el servidor, hora local para las personas

Configure la máquina con UTC y manténgala así.

timedatectl list-timezones | grep -i utc
sudo timedatectl set-timezone UTC
timedatectl

UTC no aplica horario de verano, y ese es todo el argumento. Una tarea diaria a las 02:30 en una zona que aplica horario de verano se ejecuta dos veces el día en que se retrasan los relojes y no se ejecuta en absoluto el día en que se adelantan. man 8 cron documenta el tratamiento especial para cambios de menos de tres horas: las tareas omitidas por un adelanto se ejecutan poco después del cambio, y las tareas que quedan dentro de una hora repetida por un retraso no se ejecutan por segunda vez. Ese comportamiento es razonable, pero no debería tener que analizarlo a las 03:00. Con UTC, la tarea se ejecuta una vez al día, todos los días del año. Si una tarea suya desaparece por completo en lugar de ejecutarse a una hora inusual, las razones por las que una tarea de cron nunca se ejecuta en silencio es la explicación más probable.

El mismo argumento se aplica a la lectura de registros. journalctl muestra las marcas de tiempo en la zona horaria del sistema y journalctl --utc fuerza UTC. Dos servidores en dos zonas convierten cada incidente en un ejercicio de conversión, y las conversiones hechas bajo presión hacen que se interprete mal una línea temporal. Mantenga los sistemas en UTC, almacene las marcas de tiempo en UTC y conviértalas una sola vez, cuando las lea una persona. Quien necesite ver la hora local para un comando puede solicitarla sin cambiar la máquina:

TZ=Europe/Berlin date

Otra línea de la salida de timedatectl corresponde a esta sección. RTC in local TZ debería mostrar no. Establecerlo en yes es una solución provisional para iniciar Windows en arranque dual en un portátil, pero en un servidor sólo añade un desfase que puede causar problemas más adelante. Cuando está establecido, timedatectl muestra una advertencia que indica que el sistema está configurado para leer la hora del RTC en la zona horaria local.

Diagnóstico por síntoma

El código de autenticación de dos factores se rechaza en un servidor. Compruebe el reloj antes que cualquier otra cosa. El código procede de un contador que avanza cada 30 segundos, por lo que un servidor atrasado 90 segundos calcula un código correspondiente a un intervalo que el teléfono ya ha superado. timedatectl mostrará System clock synchronized: no, o chronyc tracking informará de un desfase System time grande. Este fallo es distinto del rechazo directo de una clave, que muestra su propio mensaje y se trata en la guía sobre fallos de autenticación con claves públicas.

apt update indica que un archivo Release aún no es válido. El mensaje completo identifica el repositorio e indica cuánto tiempo seguirá sin ser válido, por ejemplo, is not valid yet (invalid for another 1d 2h 3min 4s). El reloj está atrasado respecto a la fecha incluida en el archivo Release del repositorio, y esa duración mide directamente cuánto tiempo lleva de retraso. Corrija el reloj. No desactive la comprobación de fechas de apt para evitar el error, porque esa comprobación impide que alguien le sirva un índice de paquetes obsoleto.

Todas las líneas de origen muestran el estado inaccesible y Reach es 0. Nadie responde, por lo que debe revisar el tráfico saliente y no la configuración. NTP utiliza el puerto UDP 123 para el tráfico saliente, y algunas redes lo filtran o redirigen. sudo chronyc ntpdata muestra contadores por origen, incluidos Total TX y Total RX. Si el contador TX aumenta mientras RX permanece en cero, los paquetes salen y no regresa ninguno. Esto apunta a un firewall entre usted y el origen.

El reloj era correcto y después saltó. Los eventos del host pueden causar este comportamiento. Una instantánea restaurada, un invitado en pausa o una migración en vivo a otro host pueden dejar atrasada la hora que ve el invitado respecto a la hora real. chrony lo detecta en la siguiente consulta y corrige el desfase; systemd-timesyncd puede esperar primero un intervalo de consulta largo. Confirme que el daemon se inicia durante el arranque con systemctl is-enabled chrony, porque un daemon iniciado manualmente deja de ejecutarse después del siguiente reinicio.

El desfase es pequeño, pero nunca se estabiliza. Revise el tiempo de steal de CPU. Si un invitado no se programa cuando debe ejecutarse su interrupción de temporizador, sus muestras se retrasan y el desfase varía en lugar de converger. top muestra este valor como la cifra st en la línea de CPU. Interpretación del tiempo de steal de CPU en un host compartido explica qué significa ese número y qué medidas puede tomar.

Un certificado que acaba de emitir se rechaza porque aún no es válido. curl muestra SSL certificate problem: certificate is not yet valid, y los navegadores indican algo similar. El certificado es correcto; el reloj que lo comprueba está atrasado. Cualquiera de las dos máquinas puede ser la responsable, así que compruebe el cliente y el servidor. Si el servidor que lo emitió es el que tiene el reloj incorrecto, la guía de certificados de certbot y nginx explica la renovación en esta misma configuración.

Añádalo a las comprobaciones que ya ejecuta

La sincronización horaria es un ajuste del arranque que puede fallar silenciosamente meses después. Es exactamente el tipo de problema que una rutina detecta y la memoria no. timedatectl y chronyc tracking se leen juntos en dos segundos. Ejecútelos como parte de los primeros diez minutos en un VPS nuevo y de nuevo cuando complete la lista habitual de mantenimiento de servidores Linux. Si prefiere que la comprobación se ejecute por sí sola y avise cuando aumente el desfase, escribir un servicio y un temporizador de systemd explica el patrón para una unidad pequeña que informa según un horario. Una comprobación de este tipo es un script corto, no un daemon, por lo que necesita Type=oneshot en lugar del valor predeterminado. El resumen de los tipos de servicio de systemd explica por qué usar el tipo incorrecto deja una unidad que informa de un éxito que no ha obtenido.

FAQ

¿Cómo compruebo si el reloj de mi VPS está sincronizado?

Ejecute timedatectl y lea la línea System clock synchronized. Esa es la marca del propio kernel. La establece el daemon que sincroniza el reloj. Por eso, yes junto con NTP service: n/a es normal y correcto en un equipo que usa chrony. Para conocer el tamaño del error, ejecute chronyc tracking y lea System time. También puede ejecutar timedatectl timesync-status y leer Offset si systemd-timesyncd se encarga de la sincronización. Para comparar el reloj con una referencia externa al equipo, compare date -u con la cabecera Date que devuelve cualquier sitio HTTPS.

¿Debo usar chrony o systemd-timesyncd en un VPS?

Use chrony en cualquier servidor importante. systemd-timesyncd es un cliente SNTP que sigue a un solo servidor. Es adecuado para un equipo que permanece conectado y cuyo reloj empieza con una hora aproximada. chrony consulta varias fuentes, descarta las que no coinciden, aprende el error de frecuencia del reloj y se recupera rápidamente después de una pausa del host o de una migración en vivo. Al instalar chrony en Debian o Ubuntu, systemd-timesyncd se elimina automáticamente porque ambos paquetes proporcionan time-daemon. Nunca ejecute dos daemons de hora a la vez.

¿Por qué fallan mis códigos TOTP en un servidor, pero funcionan en los demás?

Porque un código TOTP depende de la hora actual. El código procede de un contador que avanza cada 30 segundos. Por tanto, el servidor y el teléfono deben coincidir en el intervalo actual. La mayoría de los verificadores acepta un intervalo anterior o posterior. Esto deja un margen aproximado de medio minuto en cada dirección. Compruebe timedatectl en ese servidor. Si System clock synchronized muestra no, corrija la sincronización. Los códigos volverán a coincidir sin cambiar el secreto compartido.

¿Puedo establecer la hora dentro de un contenedor Docker?

No, y no es necesario. Un contenedor comparte el CLOCK_REALTIME del host porque los espacios de nombres de tiempo de Linux sólo virtualizan los relojes monotónico y de tiempo de arranque. Un contenedor sin privilegios obtiene date: cannot set date: Operation not permitted. Añadir CAP_SYS_TIME le permite cambiar el reloj del host, en lugar de proporcionarle un reloj propio. Sincronice el host. Una hora local diferente dentro de un contenedor es una configuración de zona horaria. Por tanto, establezca TZ en el entorno del contenedor.

¿Debe un servidor usar UTC o la hora local?

UTC. Aplique la hora local cuando una persona lea la salida. UTC nunca cambia por el horario de verano. Por eso, una tarea diaria se ejecuta una vez al día durante todo el año y las marcas de tiempo de distintos servidores coinciden sin conversiones. Establézcalo con sudo timedatectl set-timezone UTC. Si alguien necesita consultar la hora local, puede anteponerla a un único comando, por ejemplo TZ=America/New_York date. Esto no cambia el reloj del sistema.