Todo indica “sincronizado”. Tus paneles están en verde. Y, sin embargo, los registros insisten en que el servidor viaja lentamente en el tiempo: los handshakes TLS fallan, Kerberos se pone quisquilloso, las ventanas de copia de seguridad se desplazan y las trazas distribuidas parecen arte moderno.
Este es el tipo de fallo que hace que los SRE sospechen de la propia realidad: NTP “funciona”, pero la deriva persiste. La solución rara vez es “reiniciar chrony”. La solución es entender qué reloj miente, quién disciplina a quién y qué hace en silencio tu hardware (o hipervisor) entre bastidores.
Qué significa realmente “NTP funciona pero la deriva persiste”
Cuando la gente dice “NTP funciona”, normalmente se refieren a una de estas cosas:
- El servicio está activo (chronyd está en ejecución).
- Hay fuentes accesibles (algunos servidores aparecen como en línea).
- El reloj del sistema no está completamente equivocado en el momento en que lo comprobaron.
Cuando dicen “la deriva persiste”, generalmente quieren decir otra cosa completamente distinta:
- El reloj está correcto justo después del arranque pero equivocado horas después.
- El reloj está correcto, pero salta hacia adelante/atrás ocasionalmente.
- NTP informa sincronizado, pero las marcas de tiempo de las aplicaciones discrepan entre nodos.
- El reloj del sistema está bien, pero el reloj de hardware (RTC) está mal, así que cada reinicio parte de la hora equivocada otra vez.
La trampa: NTP no es una función de “ajustar la hora una vez”. Es un sistema de control. Si el lazo de control está peleando contra un oscilador malo, un clocksource defectuoso, un difuminado de tiempo del hipervisor o una política que prohíbe los pasos bruscos, obtendrás el estado “sincronizado” y aun así experimentarás síntomas parecidos a la deriva.
Datos interesantes y contexto histórico (para que dejes de pelear con la física)
- NTP es anterior a la Internet moderna. El primer trabajo de especificación de NTP comenzó a principios de los años 80; es más antiguo que la mayoría de las carreras “cloud-native”.
- El tiempo Unix no es monotónico. El “reloj de pared” puede retroceder; el tiempo monotónico es un contador separado usado para medir intervalos.
- Los segundos intercalares no son teóricos. Se han insertado docenas desde los años 70, y su manejo difiere entre sistemas.
- El RTC del PC nunca estuvo pensado como fuente de precisión. Es un reloj para sobrevivir ciclos de energía, no para ganar premios de exactitud.
- Los osciladores de cuarzo derivan con temperatura y envejecimiento. Las piezas comerciales suelen derivar decenas de ppm; eso son segundos por día, no por mes.
- Algunos hipervisores “ayudan” forzando el tiempo del guest. Eso puede pelear con chrony y producir offsets en sierra y saltos “misteriosos”.
- Las elecciones de clocksource del kernel importan. Un TSC estable puede ser excelente; uno inestable es caos con apariencia verosímil.
- Chrony se diseñó para redes feas. Maneja conectividad intermitente y gran variación de latencia mejor que el ntpd clásico en muchos casos.
Guion de diagnóstico rápido
Cuando se reporta deriva de tiempo, quieres encontrar el cuello de botella rápido: ¿es entrada (fuentes malas), política de control (no permite stepping, umbrales incorrectos), oscilador (hardware/VM inestable) o ruta de arranque (RTC erróneo)? Haz esto en orden:
1) Confirma qué tiempo está mal (reloj del sistema vs RTC vs “tiempo de la app”)
- Comprueba la hora del sistema, la zona horaria y el estado de sincronización.
- Comprueba la hora del RTC y si está guardada como UTC.
- Comprueba si la queja es sobre el orden de los registros, la validez TLS o temporizadores monotónicos (causas distintas).
2) Mira la visión de chrony de la realidad
- ¿chrony está rastreando una fuente estable?
- ¿Está haciendo slewing muy lentamente debido a límites?
- ¿Se está dando pasos frecuentemente porque los offsets son enormes?
3) Busca saltos de tiempo y peleas
- Mensajes del kernel sobre inestabilidad del clocksource.
- Herramientas del VM / agente del hipervisor forzando la hora del guest.
- Múltiples demonios de tiempo ejecutándose a la vez.
4) Si es estable en ejecución pero está mal después del reinicio: ruta RTC
- Configuración de hwclock, desajuste UTC/localtime, falta de sincronización periódica.
- Pila de la batería del RTC defectuosa (sí, aún ocurre).
Una cita que vale la pena pegar cerca de tu frente: idea parafraseada de Gene Kranz: “Sé duro y competente.” Los errores de cronometraje requieren ambas cualidades.
Modelo mental: tres relojes y un par de mentirosos
En un sistema Debian 13 te interesan tres constructos de tiempo:
- Reloj del sistema (también llamado reloj de pared): lo que imprime
date; usado para marcas de tiempo, validez de certificados, cron, Kerberos, registros. - Reloj monotónico: usado para medir intervalos; no debería retroceder; los demonios de tiempo pueden ajustar su tasa indirectamente, pero no “saltará” del mismo modo.
- Reloj de hardware (RTC): un reloj con batería en la placa base (o su equivalente virtual). Se usa al arranque para sembrar el reloj del sistema.
NTP/chrony disciplina el reloj del sistema. No “corrige” automáticamente tu RTC a menos que sincronices explícitamente o configures un servicio para hacerlo. Si tu RTC está mal, reiniciarás en la mala hora, y chrony la corregirá después: a veces lentamente, a veces no en absoluto si la política prohíbe los pasos.
Además: Debian puede ejecutar systemd-timesyncd o chrony (o ambos, lo cual no es un punto a presumir). Elige uno. Para servidores, elige chrony. Es más transparente, más configurable y te dice lo que está ocurriendo.
Broma #1: El tiempo es una ilusión. Chrony es una ilusión con registros.
Tareas prácticas: comandos, salidas y decisiones (12+)
Estas son las tareas que ejecuto en producción cuando alguien afirma “NTP está bien” mientras la hora del sistema claramente no lo está. Cada tarea incluye: el comando, una salida realista y la decisión que tomas después.
Tarea 1: Comprueba el estado actual con timedatectl
cr0x@server:~$ timedatectl
Local time: Tue 2025-12-31 10:14:22 UTC
Universal time: Tue 2025-12-31 10:14:22 UTC
RTC time: Tue 2025-12-31 09:58:05
Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
Qué significa: El reloj del sistema está sincronizado, pero el RTC va retrasado ~16 minutos. Esa es una trampa al reiniciar.
Decisión: Si este es un RTC físico, planea sincronizar el RTC desde el reloj del sistema después de que chrony se estabilice (e investiga por qué el RTC deriva). Si es una VM, revisa la configuración de sincronización host/guest.
Tarea 2: Verifica qué servicio de sincronización de tiempo está activo (evita peleas de demonios)
cr0x@server:~$ systemctl status chrony --no-pager
● chrony.service - chrony, an NTP client/server
Loaded: loaded (/lib/systemd/system/chrony.service; enabled; preset: enabled)
Active: active (running) since Tue 2025-12-31 09:50:10 UTC; 24min ago
Docs: man:chronyd(8)
man:chronyc(1)
Process: 612 ExecStart=/usr/sbin/chronyd -F 1 (code=exited, status=0/SUCCESS)
Main PID: 640 (chronyd)
Tasks: 1
Memory: 3.2M
CPU: 120ms
CGroup: /system.slice/chrony.service
└─640 /usr/sbin/chronyd -F 1
cr0x@server:~$ systemctl status systemd-timesyncd --no-pager
● systemd-timesyncd.service - Network Time Synchronization
Loaded: loaded (/lib/systemd/system/systemd-timesyncd.service; disabled; preset: enabled)
Active: inactive (dead)
Qué significa: Bien: solo chrony está activo.
Decisión: Si ambos están activos, desactiva systemd-timesyncd (o elimina chrony, pero no lo hagas en servidores sin una razón).
Tarea 3: Obtén la vista de seguimiento de chrony (¿está confiado o adivinando?)
cr0x@server:~$ chronyc tracking
Reference ID : 203.0.113.10 (ntp1.example.net)
Stratum : 3
Ref time (UTC) : Tue Dec 31 10:14:18 2025
System time : 0.000423812 seconds slow of NTP time
Last offset : -0.000221901 seconds
RMS offset : 0.000612554 seconds
Frequency : 24.731 ppm fast
Residual freq : -0.112 ppm
Skew : 0.931 ppm
Root delay : 0.022741 seconds
Root dispersion : 0.004921 seconds
Update interval : 64.2 seconds
Leap status : Normal
Qué significa: El reloj del sistema está efectivamente bien ahora. La frecuencia es 24.7 ppm rápida, lo cual no es una locura para hardware comercial, pero indica que existe deriva y chrony la está compensando.
Decisión: Si los usuarios siguen reportando deriva, probablemente sean reinicios/RTC, saltos periódicos u otro componente que overridee la hora.
Tarea 4: Inspecciona la calidad de las fuentes (no puedes disciplinar contra basura)
cr0x@server:~$ chronyc sources -v
.-- Source mode '^' = server, '=' = peer, '#' = local clock.
/ .- Source state '*' = current best, '+' = combined, '-' = not combined,
| / 'x' = may be in error, '~' = too variable, '?' = unreachable.
|| .- xxxx [ yyyy ] +/- zzzz
|| Reachability register (octal) -. | xxxx = adjusted offset,
|| Log2(Polling interval) --. | | yyyy = measured offset,
|| \ | | zzzz = estimated error.
|| | | |
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^* ntp1.example.net 2 6 377 22 -221us[ -311us] +/- 8ms
^+ ntp2.example.net 2 6 377 21 -102us[ -190us] +/- 10ms
^- ntp3.example.net 3 6 377 20 +891us[ +830us] +/- 22ms
Qué significa: Reach saludable (377), múltiples fuentes, offsets pequeños. No es tu problema.
Decisión: Si ves ? unreachable o ~ demasiado variable, arregla la ruta de red, el firewall o elige servidores mejores.
Tarea 5: Comprueba eventos de step y correcciones grandes
cr0x@server:~$ journalctl -u chrony --since "today" --no-pager
Dec 31 09:50:10 server chronyd[640]: chronyd version 4.5 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SIGND +ASYNCDNS +NTS)
Dec 31 09:50:11 server chronyd[640]: System clock was stepped by -963.241 seconds
Dec 31 09:50:11 server chronyd[640]: Selected source 203.0.113.10
Dec 31 09:52:15 server chronyd[640]: System clock TAI offset set to 37 seconds
Qué significa: Al inicio, el reloj fue ajustado por casi 16 minutos y se dio un step. Eso suele venir de un RTC malo o de una semilla inicial de tiempo errónea.
Decisión: Arregla el RTC y asegúrate de que chrony pueda hacer steps temprano en el arranque (makestep); de lo contrario, los servicios arrancan con la hora equivocada y no se recuperan por completo.
Tarea 6: Compara RTC vs tiempo del sistema directamente
cr0x@server:~$ sudo hwclock --show
2025-12-31 09:58:15.123456+00:00
cr0x@server:~$ date -u
Tue Dec 31 10:14:31 UTC 2025
Qué significa: El RTC está retrasado. Si reinicias ahora, arrancarás en el pasado.
Decisión: Si esto es un servidor físico, considera problemas de batería/firmware del RTC. Si es una VM, deja de tratar al RTC como autoritativo y arregla la integración host/guest del tiempo.
Tarea 7: Comprueba si el RTC está configurado como UTC (debería estarlo)
cr0x@server:~$ cat /etc/adjtime
0.000000 1767174612 0.000000
0
UTC
Qué significa: El RTC se espera que esté en UTC. Bien.
Decisión: Si ves LOCAL aquí en un servidor, arréglalo salvo que tengas una razón específica de arranque dual.
Tarea 8: Identifica el clocksource y si el kernel lo considera estable
cr0x@server:~$ cat /sys/devices/system/clocksource/clocksource0/current_clocksource
tsc
cr0x@server:~$ dmesg | grep -i clocksource | tail -n 8
[ 0.000000] tsc: Detected 2592.000 MHz processor
[ 0.120000] clocksource: tsc: mask: 0xffffffffffffffff max_cycles: 0x2557f2f71a, max_idle_ns: 440795309246 ns
[ 0.130000] clocksource: Switched to clocksource tsc
Qué significa: Usando TSC. En hardware moderno esto puede ser excelente. En algunos escenarios virtualizados o con gestión agresiva de energía, puede ser problemático.
Decisión: Si ves advertencias de inestabilidad o saltos frecuentes de tiempo, prueba otro clocksource (ver sección más abajo).
Tarea 9: Detecta saltos de tiempo y “el reloj retrocedió” a nivel de aplicación
cr0x@server:~$ journalctl -k --since "today" | grep -E "time.*(jump|backward)|clocksource.*unstable" --no-pager
Dec 31 10:02:44 server kernel: clocksource: timekeeping watchdog on CPU2: Marking clocksource 'tsc' as unstable because the skew is too large
Dec 31 10:02:44 server kernel: clocksource: Switched to clocksource hpet
Qué significa: El kernel detectó inestabilidad en TSC y cambió el clocksource. Eso es una traza evidente de “la deriva persiste”.
Decisión: Arregla ajustes de BIOS/firmware, desactiva estados C agresivos o fija un clocksource estable. En VMs, arregla la configuración de tiempo/tsc del host.
Tarea 10: Asegura que los paquetes NTP no estén bloqueados o mangled
cr0x@server:~$ sudo ss -uapn | grep :123
UNCONN 0 0 0.0.0.0:123 0.0.0.0:* users:(("chronyd",pid=640,fd=5))
UNCONN 0 0 [::]:123 [::]:* users:(("chronyd",pid=640,fd=6))
cr0x@server:~$ sudo nft list ruleset | grep -n "dport 123" | head
127: udp dport 123 accept
Qué significa: chrony está escuchando; el firewall permite NTP.
Decisión: Si no existe una regla accept y las fuentes son inalcanzables, añade una regla o arregla el firewall aguas arriba.
Tarea 11: Verifica el estado de disciplina del reloj del sistema (comportamiento del PLL del kernel)
cr0x@server:~$ timedatectl show-timesync --all
SystemNTPServers=
FallbackNTPServers=
ServerName=
ServerAddress=
RootDistanceMaxUSec=5s
PollIntervalMinUSec=32s
PollIntervalMaxUSec=34min 8s
Frequency=24731
Qué significa: Esta salida es más relevante para systemd-timesyncd, pero aún así puede mostrar valores de disciplina de frecuencia. No le des más lectura de la necesaria si usas chrony.
Decisión: Usa las propias herramientas de chrony para la verdad; evita mezclar interpretaciones entre demonios.
Tarea 12: Comprueba si chrony puede hacer step cuando es necesario (corrección al arrancar)
cr0x@server:~$ grep -nE "^(makestep|rtcsync|driftfile|leapsectz)" /etc/chrony/chrony.conf
12:driftfile /var/lib/chrony/chrony.drift
18:makestep 1.0 3
22:rtcsync
26:leapsectz right/UTC
Qué significa: makestep 1.0 3 permite hacer step si el offset > 1 segundo, pero solo durante las primeras 3 actualizaciones. rtcsync copiará periódicamente la hora del sistema al RTC.
Decisión: Si arrancas muy desfasado, aumenta la ventana de step (el conteo) temporalmente mientras arreglas el RTC. Mantener rtcsync suele ser correcto en hardware físico.
Tarea 13: Valida actualizaciones del driftfile (¿chrony aprende el oscilador?)
cr0x@server:~$ sudo ls -l /var/lib/chrony/chrony.drift
-rw-r--r-- 1 _chrony _chrony 18 Dec 31 10:14 /var/lib/chrony/chrony.drift
cr0x@server:~$ sudo cat /var/lib/chrony/chrony.drift
24.731 0.931
Qué significa: Chrony ha medido el offset de frecuencia (~24.7 ppm) y el error estimado. Si esto nunca se actualiza, algo anda mal (permisos, FS en solo lectura, restricciones de contenedor).
Decisión: Arregla la persistencia; sin aprendizaje del drift, volverás a aprender en cada reinicio y tardarás más en converger.
Tarea 14: Confirma que nada más esté forzando la hora (herramientas de VM, scripts)
cr0x@server:~$ ps aux | egrep -i "(ntpd|timesyncd|openntpd|ptp4l|phc2sys)" | grep -v egrep
root 640 0.0 0.1 81200 3520 ? Ssl 09:50 0:00 /usr/sbin/chronyd -F 1
Qué significa: Solo chronyd aparece en la lista obvia.
Decisión: Si encuentras múltiples demonios de tiempo, elige uno y desactiva los demás. Si estás en una VM, revisa los agentes del guest por separado (ver sección de virtualización).
Ajustes de Chrony que realmente ayudan
Los valores por defecto de Chrony son razonables, pero “razonable” asume que tu RTC no es un desastre y que tu plataforma no salta el tiempo aleatoriamente. Cuando la deriva persiste, afinas con dos objetivos:
- Arrancar con la hora correcta rápidamente para que los servicios dependientes no empiecen en el siglo equivocado.
- Mantener estabilidad incluso cuando las fuentes son ruidosas o la conectividad es intermitente.
1) Permitir step temprano, pero no para siempre: makestep
El stepping es un salto repentino. El slewing es un ajuste gradual de la tasa. Stepping es lo que quieres al arrancar cuando estás minutos fuera; slewing es lo que quieres en operación normal cuando estás milisegundos fuera.
Una configuración típica de servidor:
cr0x@server:~$ sudo grep -n "^makestep" /etc/chrony/chrony.conf
18:makestep 1.0 3
Guía con opinión: Si tu RTC a veces está mal por decenas de segundos, pon algo como makestep 1.0 10 temporalmente mientras arreglas la disciplina del RTC. No dejes políticas de “step siempre” en nodos sensibles a latencia salvo que disfrutes depurar marcas de tiempo raras en transacciones.
2) Persistir el aprendizaje del oscilador: driftfile debe ser escribible
Chrony puede compensar un reloj consistentemente rápido/lento si puede aprender y almacenar el offset de frecuencia. Ese aprendizaje vive en el driftfile.
Si usas imágenes inmutables o sistemas de archivos raíz en solo lectura, necesitas asegurar que /var/lib/chrony persista. Si no lo hace, tendrás repetidos periodos largos de convergencia después de cada reinicio.
3) Sincronizar el RTC desde la hora del sistema (servidores físicos): rtcsync
rtcsync permite copiar periódicamente la hora del sistema al RTC. Esto no convierte al RTC en un dispositivo de precisión. Hace que tu próximo arranque sea menos embarazoso.
En metal desnudo, generalmente quiero rtcsync. En algunas VMs, “RTC” es una abstracción y sincronizarlo puede ser irrelevante o contraproducente si el hipervisor también lo gestiona.
4) Controlar la frecuencia de actualización y la sensibilidad a la red
Si tus fuentes NTP están a través de una WAN inestable, chrony lo manejará, pero tus offsets pueden mostrar más ruido. Puedes mejorar la estabilidad eligiendo servidores más cercanos, o reduciendo la dependencia de una sola fuente.
Cuando alguien propone “simplemente sondear más seguido”, recuerda: sondear más puede aumentar la sensibilidad al ruido y la carga. También puede incomodar a servidores NTP corporativos si te conviertes en un sondeador entusiasta.
5) Usa buenas fuentes, no “lo que resuelva”
Para redes empresariales, apunta chrony a:
- tus servidores internos stratum-1/2 (si están bien gestionados),
- o un servicio NTP proveedor bien gestionado,
- o dispositivos de red locales con respaldo GPS/PTP (cuando corresponda).
Y siempre configura múltiples fuentes. Una sola fuente es un único punto de autodecepción.
Reloj de hardware (RTC) y hwclock: volverlo aburrido
La mayoría de los casos “la deriva persiste” no son realmente fallos de NTP. Son fallos en el ciclo de vida del RTC: la máquina arranca con la hora equivocada, luego NTP la corrige, luego alguien reinicia y vuelve a culpar a NTP. No persigues deriva; persigues un bucle de reinicio a estado malo.
El RTC debe estar en UTC, casi siempre
En servidores Linux, mantén el RTC en UTC. El sistema operativo puede aplicar zonas horarias; el RTC no debe hacerlo. Las reglas de zona cambian. UTC no. Esto no es ideología; es control de daños.
Escribe la hora del sistema al RTC después de sincronizar (cuando corresponda)
Si chrony está proporcionando buena hora, actualiza el RTC:
cr0x@server:~$ sudo hwclock --systohc --utc
Qué significa: El RTC se establece desde la hora actual del sistema, almacenada como UTC.
Decisión: Haz esto en metal desnudo una vez que hayas confirmado que chrony está estable. Si tu RTC deriva rápidamente, espera repetir y investigar hardware.
Leer RTC en el sistema (sobre todo para recuperación)
cr0x@server:~$ sudo hwclock --hctosys --utc
Qué significa: Ajustas la hora del sistema desde el RTC. Típicamente esto lo hace el SO muy temprano en el arranque.
Decisión: No uses esto para “arreglar” un sistema en ejecución ya disciplinado por NTP, a menos que estés entrando deliberadamente en respuesta a un incidente.
Cuando la deriva del RTC es hardware real
En servidores físicos, la deriva persistente del RTC puede deberse a:
- Una batería del RTC fallida (clásico, aburrido y real).
- Errores de firmware alrededor de las actualizaciones del RTC.
- Oscilaciones de temperatura en despliegues en el borde.
- Un dispositivo RTC que simplemente es malo.
Para un servidor de centro de datos, un RTC que deriva rápidamente suele ser una situación de “reemplazar la pieza”, no de “afinar chrony intensamente”.
Clocksource del kernel, TSC y por qué “estable” es condicional
Si el reloj del sistema salta, chrony parecerá culpable porque es el cronista visible. Pero el motor bajo el capó es el clocksource del kernel. Si ese motor es inestable, puedes observar:
- offsets de chrony en sierra o que nunca se estabilizan,
- logs del kernel sobre watchdog del clocksource,
- aplicaciones reportando “el reloj se movió hacia atrás”,
- guests de VM derivando en sincronía con la carga del host o eventos de migración.
Comprueba los clocksources disponibles
cr0x@server:~$ cat /sys/devices/system/clocksource/clocksource0/available_clocksource
tsc hpet acpi_pm
Qué significa: Existen múltiples clocksources; el kernel elige uno. TSC suele ser el más rápido y bueno cuando es invariant/estable.
Decisión: Si el kernel marca TSC como inestable, considera fijar otro source como mitigación mientras arreglas firmware/configuración de VM.
Fijar un clocksource (mitigación, no estilo de vida)
Como prueba, puedes establecer un parámetro del kernel en el arranque (vía GRUB) como clocksource=hpet o similar. Eso es específico del entorno y debe probarse. El objetivo no es “HPET para siempre”. El objetivo es “dejar de saltar el tiempo mientras corregimos la plataforma”.
Broma #2: El TSC es como la hoja de horas de un becario—preciso si está supervisado, creativo si se deja solo.
Trampas de virtualización: cuando el host engaña al guest
En VMs, “reloj de hardware” es lo que el hipervisor emula. Eso puede ser estable, o puede ser “suficientemente cercano” hasta que ocurre una migración en vivo, sobrecarga del host o una suspensión/resume.
El modo de fallo clásico en VM: dos maestros
Ejecutas chrony dentro del guest, mientras el hipervisor (o el agente del guest) también fuerza periódicamente la hora del guest. Esto crea una pelea:
- chrony hace slewing lentamente, intentando mantenerse estable,
- el hipervisor da pasos abruptos, para “ayudar”,
- las aplicaciones ven saltos de tiempo hacia atrás/adelante,
- chrony registra eventos de step y recibe la culpa.
Detecta agentes comunes del guest
Por ejemplo, en algunas plataformas puedes ver qemu-guest-agent o similar:
cr0x@server:~$ systemctl status qemu-guest-agent --no-pager
● qemu-guest-agent.service - QEMU Guest Agent
Loaded: loaded (/lib/systemd/system/qemu-guest-agent.service; enabled; preset: enabled)
Active: active (running) since Tue 2025-12-31 09:49:58 UTC; 25min ago
Main PID: 510 (qemu-ga)
Tasks: 1
Memory: 2.8M
CPU: 52ms
CGroup: /system.slice/qemu-guest-agent.service
└─510 /usr/sbin/qemu-ga
Qué significa: El agente del guest está en ejecución. Eso no garantiza que esté ajustando la hora, pero es un sospechoso.
Decisión: Revisa la política del hipervisor: o dejas que el guest controle el tiempo vía chrony, o dejas que el host imponga el tiempo y desactivas NTP en el guest. El control mixto es donde la cordura muere.
Migración en vivo y reportes de “deriva súbita”
Si la deriva aparece después de migraciones, comprueba:
- ajustes de estabilidad del TSC en el host,
- modelo de CPU de la VM y exposición de TSC invariante,
- salud NTP del host (si el host está mal, los guests heredan raruras).
En flotas empresariales de VM, arreglas el tiempo en la capa del host primero. Los guests son consumidores a la baja.
Tres mini-historias del mundo corporativo (anonimizadas)
Incidente causado por una suposición errónea: “Sincronizado” significa correcto después del reinicio
Una empresa mediana ejecutaba una capa de logging basada en Debian en metal. El monitor comprobaba chronyc tracking cada hora y alertaba si el offset del sistema excedía un umbral. Nunca lo hacía. Todos se sentían bien con el tiempo.
Entonces llegó una ventana de mantenimiento. Reiniciaron la mitad de la flota para aplicar parches de kernel. Inmediatamente, la latencia de ingestión se disparó y un montón de registros llegaron fuera de orden. La persona on-call vio “System clock synchronized: yes” y asumió que el problema estaba en otra parte.
La causa real fue mundana: deriva del RTC. En cada servidor, el RTC iba varios minutos atrás. Antes del reinicio, chrony había disciplinado el reloj del sistema, así que el monitor parecía perfecto. Tras el reinicio, los servicios arrancaron con la hora equivocada, escribieron un pico de registros mal timestamped, y solo después chrony dio un step para corregirlo. El “daño” ya estaba hecho.
La solución no fue exótica. Activaron rtcsync, verificaron que el RTC estuviera en UTC y añadieron una protección en el arranque: los servicios que necesitaban tiempo correcto arrancaban después de que chrony reportara sincronización. También cambiaron el monitoreo para comparar explícitamente RTC vs reloj del sistema una vez al día. La lección caló porque fue embarazosa de la forma más simple posible.
Optimización que salió mal: evitar steps agresivamente en nodos sensibles a latencia
Otra organización tenía una postura estricta: “Nunca hacer step; solo slewing.” La razón sonaba profesional: los pasos pueden confundir bases de datos y desordenar el orden. Configuraron chrony para nunca steppear después del arranque y pusieron un umbral pequeño al inicio.
Funcionó bien hasta que parte de la flota se movió a un segmento de red ruidoso. Los paquetes NTP llegaron con retardo variable, y los offsets ocasionalmente superaban un segundo durante breves caídas. Chrony hizo lo que le pidieron—solo slewing—pero el slewing a la velocidad máxima del kernel tardó mucho en corregir offsets de varios segundos.
Las aplicaciones no se cayeron. Hicieron algo más sutil: tokens de autenticación expiraban “temprano”, jobs programados derivaron y la coordinación entre nodos se comportó de forma inconsistente. Como no se daban steps, los incidentes fueron más difíciles de notar. Parecía como fallos aleatorios en sistemas no relacionados.
Eventualmente adoptaron una política más realista: permitir step solo en las primeras N actualizaciones tras el arranque (makestep) y arreglar el jitter de red subyacente. La regla de “nunca step” pasó a “hacer step solo cuando la alternativa es horas de hora equivocada”. Menos puro, más efectivo.
Práctica aburrida pero correcta que salvó el día: bloqueo de arranque hasta la sincronización de tiempo
Una plataforma de pagos (regulada, auditada y alérgica a sorpresas) tenía una regla operativa poco sexy: los sistemas que firman tokens o negocian Kerberos no arrancan hasta que la sincronización de tiempo está confirmada. Sin excepciones, sin “probablemente estará bien”.
Lo implementaron con ordering de systemd: chrony arranca pronto; la unidad de la aplicación tiene un ExecStartPre que hace loop en chronyc tracking hasta que el estado de leap es normal y el sistema está sincronizado. También añadieron una unidad de “sanidad de tiempo” que se niega a arrancar si el reloj está muy fuera de rango.
Esto les salvó durante un incidente de red en un centro de datos donde la alcanzabilidad NTP estuvo rota temporalmente durante el arranque para un subconjunto de hosts. Sin bloqueo, esas máquinas hubieran arrancado con la hora stale del RTC y habrían emitido tokens con timestamps inválidos. Con el bloqueo, simplemente esperaron. El arranque fue más lento; la corrección se mantuvo.
Fue aburrido. Fue correcto. Evitó un incidente que habría sido culpado a “la red”, “Linux” o “Mercurio retrógrado”, dependiendo de quien escribiera el postmortem.
Errores comunes: síntoma → causa raíz → solución
1) “timedatectl dice synchronized, pero la hora sigue mal después del reinicio”
Síntoma: Inmediatamente tras el arranque, la hora está fuera por minutos; más tarde parece bien.
Causa raíz: El RTC está mal y el arranque del sistema toma la hora del RTC. NTP corrige después.
Solución: Asegura que el RTC esté en UTC (/etc/adjtime), habilita rtcsync en chrony, ejecuta hwclock --systohc --utc tras la sincronización e investiga la batería/firmware del RTC.
2) “chrony muestra fuentes alcanzables, pero los offsets nunca convergen”
Síntoma: chronyc sources muestra reach, pero tracking RMS offset se mantiene alto; la frecuencia oscila.
Causa raíz: Ruta de red ruidosa, enrutamiento asimétrico o servidores upstream malos; a veces un firewall/NAT local hace algo extraño con UDP.
Solución: Usa fuentes más cercanas/buenas, confirma la ruta UDP/123, evita sondear demasiado agresivamente, considera servidores stratum internos.
3) “El reloj salta hacia atrás/adelante a veces; apps registran ‘el reloj retrocedió’”
Síntoma: Logs del kernel o de apps mencionan saltos hacia atrás; chrony registra steps fuera de ventanas esperadas.
Causa raíz: Inestabilidad del clocksource del kernel, hipervisor forzando el tiempo o múltiples demonios de tiempo peleando.
Solución: Revisa dmesg por mensajes del watchdog del clocksource, asegura un único mecanismo de sincronización, ajusta la configuración de tiempo de VM, mitiga fijando un clocksource estable.
4) “Todo va bien hasta que la VM migra”
Síntoma: Picos de offset correlacionados con migraciones o mantenimiento del host.
Causa raíz: El host tiene la hora mal o expone un TSC inestable; el guest ve discontinuidades.
Solución: Arregla NTP/PTP en el host primero, asegura modelo de CPU consistente/exposición de TSC invariante, evita agentes que sincronicen tiempo en el guest.
5) “Chrony hace pasos grandes en cada arranque”
Síntoma: El journal de chrony muestra un gran step en cada arranque.
Causa raíz: El RTC no se actualiza, el driftfile no es persistente o el sistema arranca sin red por demasiado tiempo y los servicios usan una semilla de tiempo equivocada.
Solución: Habilita rtcsync, asegura persistencia del driftfile, y bloquea el arranque de servicios críticos hasta que se logre la sincronización.
6) “El tiempo deriva lentamente incluso con chrony en ejecución”
Síntoma: A lo largo de horas, el offset crece y chrony no puede mantenerlo dentro de límites.
Causa raíz: El kernel se niega a disciplinar lo suficientemente rápido por límites de configuración, o el clocksource es inestable, o las fuentes NTP son inconsistentes.
Solución: Verifica la frecuencia y skew de chrony; confirma las fuentes; revisa la inestabilidad del clocksource; considera PTP si necesitas límites más estrictos que los que NTP puede ofrecer en tu entorno.
Listas de verificación / plan paso a paso
Paso a paso: arreglar “NTP funciona pero la deriva persiste” en Debian 13
-
Elige un demonio de tiempo.
Usa chrony en servidores; desactiva systemd-timesyncd si está presente.
cr0x@server:~$ sudo systemctl disable --now systemd-timesyncd Removed "/etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service".Decisión: Si desactivar timesyncd rompe algo, tenías dependencias ocultas. Arregla eso, no vuelvas a habilitar demonios en duelo.
-
Confirma que chrony tiene fuentes estables.
cr0x@server:~$ chronyc sources -v ...^* ntp1.example.net ...Decisión: Si no puedes alcanzar ninguna fuente, arregla la red/firewall antes de tocar ajustes de chrony.
-
Permite step temprano en el arranque.
En
/etc/chrony/chrony.confasegúrate de algo como:cr0x@server:~$ sudo grep -n "^makestep" /etc/chrony/chrony.conf 18:makestep 1.0 3Decisión: Si los offsets suelen ser > 1s al arrancar, aumenta el conteo temporalmente mientras arreglas el RTC.
-
Haz persistente el aprendizaje del drift.
cr0x@server:~$ sudo stat /var/lib/chrony/chrony.drift File: /var/lib/chrony/chrony.drift Size: 18 Blocks: 8 IO Block: 4096 regular file Access: (0644/-rw-r--r--) Uid: ( 109/_chrony) Gid: ( 116/_chrony) Access: 2025-12-31 10:14:18.000000000 +0000 Modify: 2025-12-31 10:14:18.000000000 +0000 Change: 2025-12-31 10:14:18.000000000 +0000Decisión: Si no se actualiza, arregla permisos o persistencia (especialmente en imágenes/contenedores).
-
Arregla el RTC: UTC y sincronizado.
cr0x@server:~$ cat /etc/adjtime 0.000000 1767174612 0.000000 0 UTCcr0x@server:~$ sudo hwclock --systohc --utcDecisión: Si el RTC sigue derivando rápidamente en metal desnudo, trátalo como hardware/firmware, no como ajuste de NTP.
-
Busca saltos de tiempo: clocksource y peleas en VMs.
cr0x@server:~$ journalctl -k --since "today" | grep -i clocksource --no-pager | tail Dec 31 10:02:44 server kernel: clocksource: Switched to clocksource hpetDecisión: Si ves inestabilidad, arregla configuraciones de plataforma (BIOS/host) y considera fijar un clocksource como mitigación.
-
Bloquea servicios críticos hasta que haya sincronización.
Para sistemas que firman tokens, hacen auth o coordinan transacciones distribuidas, no los inicies antes de que la sincronización sea real. Esto es aburrido y correcto.
Checklist operacional para seguridad continua
- Monitorea delta RTC vs reloj del sistema diariamente en metal desnudo.
- Alerta sobre eventos de step de chrony fuera de la ventana esperada al arranque.
- Mantén al menos tres fuentes NTP, idealmente en diferentes dominios de fallo.
- Registra si un nodo es VM o metal desnudo; los modos de fallo de tiempo difieren.
- Durante migraciones de VM, correlaciona con picos de offset para probar causalidad.
Preguntas frecuentes
1) Si System clock synchronized: yes, ¿cómo puede seguir “mal” la hora?
Porque “sincronizado” es un estado en un momento y a menudo se refiere solo al reloj del sistema. Tu RTC aún puede estar mal (problema al reiniciar), o puedes tener saltos intermitentes por comportamiento de clocksource/hipervisor.
2) ¿Debo usar systemd-timesyncd o chrony en Debian 13?
Para servidores: chrony. Es más diagnósticable y configurable. Para escritorios minimalistas o pequeños appliances: timesyncd puede ser suficiente. No ejecutes ambos.
3) ¿Cuál es la diferencia operativa entre stepping y slewing?
Stepping cambia la hora de pared instantáneamente. Slewing cambia la tasa para que el reloj converja gradualmente. Haz step al arrancar si estás muy fuera. Slew en operación normal para no confundir aplicaciones.
4) ¿Es seguro habilitar rtcsync?
En servidores en metal desnudo, sí, generalmente. Reduce sorpresas al reiniciar. En algunas VMs puede ser irrelevante, y el hipervisor puede manejar la semántica del RTC de todos modos.
5) Mi RTC está en hora local. ¿Eso es realmente un problema?
En servidores, sí. Los cambios de DST y actualizaciones de reglas de zona son donde “RTC en hora local” genera problemas. Usa UTC salvo que tengas una necesidad específica de arranque dual.
6) ¿Por qué mi reloj deriva más bajo carga?
La carga pesada puede revelar problemas del clocksource, demoras en la planificación de la VM y jitter de red. Chrony puede manejar mucho, pero si el clocksubyacente es inestable o los paquetes NTP se demoran impredeciblemente, los offsets se vuelven ruidosos.
7) ¿Puedo arreglar una deriva persistente sondeando NTP más seguido?
A veces ayuda un poco; a menudo solo amplifica el ruido. Mejores fuentes y un clocksource estable superan el sondeo agresivo. Si necesitas márgenes más estrechos, considera PTP en entornos que lo soporten.
8) ¿Por qué veo grandes steps al inicio aún con chrony configurado?
Porque la semilla de tiempo inicial (RTC) está muy fuera o el driftfile no es persistente. Chrony solo puede corregir después de arrancar y alcanzar las fuentes; cualquier cosa que arranque antes puede ver la hora equivocada.
9) ¿Cómo sé si un hipervisor está sobrescribiendo la hora?
Busca saltos de tiempo correlacionados con migraciones o eventos del host, y revisa agentes del guest o configuraciones de plataforma que “sincronicen el tiempo”. En la práctica, decides: tiempo gestionado por el host o por el guest, no ambos.
10) ¿Qué precisión puedo esperar de NTP en una LAN típica?
A menudo milisegundos, a veces mejor. En WAN o redes ruidosas, decenas de milisegundos o peor. Si necesitas coordinación sub-milisegundo o microsegundo, estás en territorio PTP y necesitas soporte hardware.
Próximos pasos que deberías dar
- Mide lo correcto: sigue el offset del sistema (
chronyc tracking) y el delta del RTC (hwclock --showvsdate -u) por separado. - Elimina peleas: asegura que solo un mecanismo de sincronización de tiempo controle cada nodo (y define si el host o el guest posee el tiempo en entornos VM).
- Haz el arranque seguro: configura
makesteppara corrección temprana y bloquea el arranque de servicios sensibles hasta que la sincronización sea real. - Haz el RTC aburrido: mantenlo en UTC, habilita
rtcsyncen metal desnudo y reemplaza baterías RTC defectuosas sin drama. - Investiga advertencias de clocksource de inmediato: si el kernel marca un clocksource inestable, trátalo como un error de hardware con timestamp.
Si haces esos cinco, “NTP funciona pero la deriva persiste” deja de ser una historia de fantasmas y se convierte en un elemento de checklist. A producción le gusta lo aburrido. El cronometraje debería ser agresivamente aburrido.