Sunucu saat dilimi: Yanlış saat neden her şeyi bozar

API token'ınız süresinden önce mi sona eriyor veya loglar kronolojik sırada değil mi? Muhtemelen sunucu saat dilimi ve NTP ayarlanmamış. Tanıma ve düzeltme yolunu görün.

7 dk Güncellendi 3 Nov 2026

JWT token'ınız Token used before issued hatasıyla reddediliyor. Ya da yeni kurulmuş SSL sertifikası tarayıcıda "süresi dolmuş" olarak gösteriliyor, oysa son kullanma tarihi aylar sonra. Ya da Kibana'da arka arkaya iki log görüyorsunuz ve ikinci logun zamanı birinciden daha eski. Bu üç belirtinin tek bir kökü var: sistem saatiniz dış dünyayla senkronize değil. Sorun genellikle donanım saatinden değil, sunucu saat diliminden başlar.

İlk yapmanız gereken şey şu an nerede durduğunuzu anlamak. Tek komut, üç satır çıktı:

timedatectl
               Local time: Sat 2025-01-11 14:22:07 +0330
           Universal time: Sat 2025-01-11 10:52:07 UTC
                 RTC time: Sat 2025-01-11 10:52:07
                Time zone: Asia/Tehran (+0330, +0330)
System clock synchronized: no
              NTP service: inactive

Son iki satır her şeyi söylüyor. Eğer System clock synchronized: no ise, saatiniz serbestçe drift yapıyor demektir. Normal bir fiziksel sunucuda saat senkronizasyon olmadan günde birkaç yüz milisaniyeden birkaç saniyeye kadar geri veya ileri gider. Sanal makinede bu sayı daha kötüdür, çünkü konuk zamanı hipervizörden alır ve hipervizör yoğunsa sapma birkaç günde onlarca saniyeye ulaşabilir.

Yanlış saat neden API imzasını geçersiz kılar

Çoğu imzalı API (AWS Signature V4, ödeme geçitlerinde HMAC imzası, exp ve iat ile OAuth) bir zaman tolerans penceresine sahiptir. AWS'de bu pencere 15 dakikadır. Sunucu saatiniz 16 dakika geriyse, her istek RequestTimeTooSkewed ile reddedilir. 16 dakika ileriyse, aynı şey olur ama farklı mesajla.

JWT'de durum daha kötüdür. Token'ı veren sunucu onu iat (veriliş zamanı) ile imzalar ve tüketen sunucu kendi saatiyle karşılaştırır. Tüketen sunucunun saati geriyse, token "gelecekten gelmiş" olur ve reddedilir. Bu hata logda genellikle Token used before issued veya NotBefore claim is in the future şeklinde görünür ve çoğu kişi JWT kütüphanesine yönelir, oysa sorun chronyd'dedir.

SSL sertifikası ve saat: gördüğünüz gerçek hata

Sertifika doğrulaması tamamen saate bağlıdır. Sunucu saati sertifikanın notBefore değerinden geriyse, istemci certificate is not yet valid mesajı alır. notAfter değerinden ileriyse, certificate has expired. Her iki hata da tarayıcıda aynı görünür ve kullanıcı sertifikanın bozuk olduğunu düşünür.

Burada hata yapılır: yönetici sertifikayı yeniden düzenler, yeniden kurar, yine hata görür. Çünkü sorun sertifika değildi. Hızlı bir tanı yolu:

openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -dates
date -u

Sunucunuzun UTC tarihi notBefore ile notAfter aralığının dışındaysa, hiçbir sertifika çalışmaz.

Sunucu saat dilimini doğru ayarlayın, sadece saati değil

İki kavramı karıştırmayın. Sistem saati (UTC) NTP ile senkronize olmalıdır. Saat dilimi yalnızca bir gösterimdir ve iç hesaplamalara etki etmez. Yani date yazdığınızda +0330 görüyorsanız, iç saat hâlâ UTC'dir ve bu doğrudur.

Saat dilimini ayarlamak için:

timedatectl set-timezone Asia/Tehran
timedatectl set-ntp true
timedatectl status

systemd olmayan daha eski sunucularda eşdeğeri şudur:

ln -sf /usr/share/zoneinfo/Asia/Tehran /etc/localtime
echo "Asia/Tehran" > /etc/timezone
hwclock --systohc

Son satır önemlidir ve çoğu kişi atlar. hwclock --systohc donanım saatini (RTC) sistem saatiyle senkronize eder. Bunu yapmazsanız, sunucu yeniden başlatıldıktan sonra saat önceki değerine döner ve siz ayarların silindiğini düşünürsünüz.

chrony mi systemd-timesyncd mi?

Çoğu modern dağıtımda systemd-timesyncd varsayılan olarak etkindir. Normal bir sunucu için yeterlidir. Ancak sunucunuz sanalsa, ağır yük altındaysa veya saat sık sık sıçrıyorsa, chronyd'yi seçin. Pratik fark: chronyd saati ani sıçrama yerine yavaşça "eğebilir" (slew) ve yüksek gecikmeli ağlarda daha iyi çalışır.

Ölçütsystemd-timesyncdchronyd
Varsayılan kurulumEvet, çoğu dağıtımdaAyrı kurulum gerekir
Yüksek gecikmeli ağda hassasiyetOrtaİyi
Yerel NTP sunucusu desteğiHayırEvet
Sanal makine için uygunlukKabul edilebilirDaha iyi

Seçim bende olsa: API ile çalışan veya merkezi log tutan her sunucuya chronyd kurarım. Bedeli, yönetilmesi gereken bir servis daha olması ve /etc/chrony/chrony.conf yapılandırmasını anlamanız gerekmesidir. Sadece PHP çalıştıran basit bir web sunucusunda systemd-timesyncd'ye dokunmam.

Loglar doğru saat olmadan değersizdir

İki sunucunuz olduğunda ve birinin saati 40 saniye geriyse, merkezi logunuzdaki olay sırası yalan söyler. Sunucu A'da başlayıp sunucu B'de tamamlanan bir istek, Kibana veya Loki'de ters gösterilir. Senkronize olmayan loglarla dağıtık bir hatayı ayıklamak neredeyse imkânsızdır.

Her servisin nereye log yazdığını ve zamanları nasıl karşılaştırabileceğinizi anlamak için Linux log konumu: Her servis nereye yazar? iyi bir referanstır. Servisleri systemd ile yönetiyorsanız, systemd'de unit dosyası: Bölümler, yeniden başlatma ve bağımlılık başlatma sırasını ve zaman servisine bağımlılığı nasıl ayarlayacağınızı gösterir.

Konteynerlerde yaygın bir hata

Konteynerin kendi saati yoktur; saati ana makinenin çekirdeğinden alır. Yani ana makinenin saati yanlışsa, tüm konteynerler yanlıştır. Ancak burada bir tuzak var: bazı imajlar kendi içlerinde /etc/localtime bulundurur ve bunu ana makineden mount etmez. Sonuç olarak konteyner içinde date UTC gösterir, dışarıda +0330. Bu tutarsızlık uygulama logu ile ana makine logunun uyuşmamasına neden olur.

Çözüm basittir, ancak bilinçli yapılmalıdır:

docker run -v /etc/localtime:/etc/localtime:ro -v /etc/timezone:/etc/timezone:ro ...

Veya docker-compose.yml içinde:

environment:
  - TZ=Asia/Tehran

TZ değişkeni yalnızca onu okuyan uygulamalara etki eder. Sistem saatinin kendisine etki etmez. Bu farkı çoğu kişi bilmez ve TZ ayarlayarak sorunun çözüldüğünü düşünür.

Saatin gerçekten senkronize olup olmadığını nasıl anlarız

Üç komut, üç güven seviyesi:

  1. timedatectl — genel durum ve NTP'nin etkin olup olmadığı.
  2. chronyc tracking — referans sunucuya göre mevcut offset miktarı, milisaniye cinsinden.
  3. chronyc sources -v — NTP sunucularının listesi ve her birine bağlantı durumu.

chronyc tracking çıktısı şuna benzer:

Reference ID    : A29FC87B (time.cloudflare.com)
System time     : 0.000034 seconds fast of NTP time
Last offset     : +0.000021 seconds
RMS offset      : 0.000089 seconds

System time birkaç yüz milisaniyeden fazlaysa, senkronizasyon henüz tamamlanmamış veya NTP sunucunuz erişilebilir değil demektir. 50 milisaniyenin altındaki değer çoğu uygulama için yeterlidir. Finansal işlemler veya dağıtık sistemler için 10 milisaniyenin altını hedefleyin.

İran'da sık karşılaştığımız bir nokta: pool.ntp.org gibi genel NTP sunucularına erişim bazen bazı veri merkezlerinden filtrelenir veya yavaştır. chronyc sources hiçbir sunucunun reachable olmadığını gösteriyorsa, yerel bir NTP sunucusu veya ntp.irancell.ir sunucularını kullanın. NTP portu 123/udp'dir ve güvenlik duvarınız bunu kapatmışsa hiçbir senkronizasyon gerçekleşmez. Portlara hızlıca göz atmak ve hangilerinin açık olması gerektiğini görmek için Yaygın servis portları referansı ve açık olmaması gereken portlar sayfasına bakın.

Ayarları kendi sunucularınıza uygulayın

Özel sunucuda çalışıyorsanız, zaman ve güvenlik duvarı ayarlarına tam erişiminiz vardır ve yerel bir NTP sunucusu da kurabilirsiniz. Özel sunucu üzerinde bu daha kolaydır çünkü çekirdek ve ağ üzerinde tam kontrole sahipsiniz. Bulut sunucu üzerinde de aynı ayarlar uygulanır, ancak bazı hipervizörlerin konuk saatini ana makineden çektiğini ve iki zaman kaynağının çatışmaması için konuk içindeki senkronizasyonu devre dışı bırakmanız veya ayarlamanız gerektiğini unutmayın.

Sunucuyu yeni kurduysanız ve baştan doğru yapılandırmak istiyorsanız, Sunucu Linux dağıtımı seçimi: Pratik ve lafı uzatmayan rehber hangi dağıtımın hangi zaman aracını varsayılan olarak bulundurduğunu anlamanıza yardımcı olur. Ve yönetilen bir hosting üzerinde çalışıyorsanız ve root erişiminiz yoksa, Linux hosting ServerNet'in temel zaman ayarları yapılmış bir seçenektir ve yalnızca uygulamanızın doğru saat dilimini okuduğundan emin olmanız gerekir.

Pratikte sık gördüğüm son bir nokta: her saat değişikliğinden sonra zamana bağlı servisleri yeniden başlatın. Veritabanları, kuyruklar ve bazı uygulamalar zamanı bellekte önbelleğe alır ve yeniden başlatılana kadar eski değeri tutar. Basit bir systemctl restart saatler süren faydasız hata ayıklamayı önler.

Sık sorulan sorular

Sunucu yeniden başlatıldıktan sonra saat neden önceki durumuna döner?

Çünkü donanım saati (RTC) sistem saatiyle senkronize edilmemiştir. Her değişiklikten sonra değerin RTC'ye kaydedilmesi için hwclock --systohc komutunu çalıştırın. Bunu yapmazsanız, sunucu bir sonraki önyüklemede donanımdan eski değeri okur.

Konteyner için TZ=Asia/Tehran ayarlamak yeterli mi?

Hayır. TZ değişkeni yalnızca onu okuyan uygulamalara etki eder ve sistem saatine etkisi yoktur. Konteynerin saati ana makinenin çekirdeğinden gelir. /etc/localtime ve /etc/timezone dosyalarının da doğru olmasını istiyorsanız, bunları konteynere read-only olarak mount etmelisiniz.

Sunucu saatinin gerçek zamandan ne kadar farklı olduğunu nasıl anlarım?

chronyc tracking komutu mevcut offset değerini saniye cinsinden gösterir. chronyd kurulu değilse, yalnızca farkı raporlayan ve saati değiştirmeyen ntpdate -q pool.ntp.org kullanabilirsiniz. 50 milisaniyenin altındaki değer çoğu uygulama için kabul edilebilir.

Sunucu saat dilimini UTC mi yoksa Asia/Tehran mı yapmalıyım?

Sunucu için UTC'yi öneririm. Loglar, veritabanı ve servisler arası iletişim UTC ile daha basit ve belirsizlik olmadan çalışır. Yerel saat dilimini gösterim katmanında (ön yüz veya raporlama) uygulayın. Yerel olmak zorundaysanız, en azından bir kümedeki tüm sunucuların aynı saat dilimine sahip olduğundan emin olun.

Bu sayfa yardımcı oldu mu?