Bir sunucuyu ayakta tutmanın büyük bölümü, aslında düzenli aralıklarla tekrar eden küçük işlerden ibarettir: her gece veritabanının yedeğini almak, saat başı log dosyalarını temizlemek, dakikada bir çalışması gereken bir kuyruk işleyicisini tetiklemek ya da SSL sertifikasını süresi dolmadan yenilemek. Bu işleri elle yapmayı hayal bile edemezsiniz; işte tam bu noktada cron devreye girer. Cron, Linux ve diğer Unix türevi sistemlerde arka planda sessizce çalışan, belirlediğiniz zaman çizelgesine göre komutları otomatik olarak yürüten bir zamanlayıcı servistir.
Bu rehberde cron'un çalışma mantığını, crontab komutuyla görev tanımlamayı, çoğu kişinin gözünü korkutan beş alanlı zaman söz dizimini, @daily gibi hazır kısayolları, en sık karşılaşılan PATH ve ortam değişkeni sorunlarını, çıktı yönlendirmeyi ve loglamayı adım adım öğreneceksiniz. Sonunda da cron'a modern bir alternatif olan systemd timer yapısına kısaca bakacağız. Örnekler Ubuntu ve Debian tabanlı sistemler baz alınarak yazıldı, ancak neredeyse tamamı CentOS, AlmaLinux ve Rocky Linux'ta da aynı biçimde çalışır.
Cron Nedir ve Nasıl Çalışır?#
Cron, aslında iki parçadan oluşan bir sistemdir. Birincisi cron (bazı dağıtımlarda crond) adı verilen, açılışta başlayıp sürekli çalışan arka plan servisidir (daemon). İkincisi ise bu servise "hangi komutu, ne zaman çalıştıracağını" söyleyen crontab dosyalarıdır. Cron servisi her dakika uyanır, tanımlı tüm zamanlamaları kontrol eder ve o anki tarih-saate uyan görevleri çalıştırır.
Cron'un dakikadan daha ince bir çözünürlüğü yoktur; yani "her 30 saniyede bir çalışsın" gibi bir tanım doğrudan yapılamaz. En sık kullanım aralığı dakika, saat ve gündür. Sistemde birden fazla crontab bulunur:
- Kullanıcı crontab'ları: Her kullanıcının kendine ait, o kullanıcının yetkileriyle çalışan görev listesi. Sıradan işleriniz için en çok bunu kullanırsınız.
- Sistem crontab'ı:
/etc/crontabve/etc/cron.d/dizinindeki dosyalar. Bunlar ek olarak hangi kullanıcı adına çalışacağını belirten bir alan içerir. - Hazır dizinler:
/etc/cron.hourly,/etc/cron.daily,/etc/cron.weeklyve/etc/cron.monthly. Bu klasörlere koyduğunuz çalıştırılabilir betikler, ismine uygun aralıkla otomatik yürütülür.
Servisin çalışıp çalışmadığını kontrol etmek için:
systemctl status cron # Debian/Ubuntu
systemctl status crond # CentOS/AlmaLinux/Rocky
Servis pasifse sudo systemctl enable --now cron komutuyla hem başlatabilir hem de açılışta otomatik başlamasını sağlayabilirsiniz. Temel systemctl ve servis yönetimi komutlarına yabancıysanız temel Linux komutları rehberimiz iyi bir başlangıç noktası olacaktır.
Crontab'ı Düzenlemek: crontab -e ve -l#
Kendi kullanıcı crontab'ınızı düzenlemenin yolu tek bir komuttan geçer:
crontab -e
Bu komut, o an oturum açtığınız kullanıcının crontab dosyasını varsayılan metin düzenleyicide (genellikle nano veya vim) açar. İlk kez çalıştırdığınızda hangi editörü kullanmak istediğinizi sorabilir; yeni başlıyorsanız nano'yu seçmeniz en rahatıdır. Değişikliği kaydedip çıktığınızda cron, dosyayı otomatik olarak devreye alır; ayrıca bir servisi yeniden başlatmanız gerekmez.
Sık kullanacağınız diğer seçenekler şunlardır:
crontab -l— Mevcut crontab içeriğini ekrana basar, hiçbir şeyi değiştirmez. Neyin tanımlı olduğunu görmek için ideal.crontab -r— Dikkat: tüm crontab'ı siler ve onay sormaz. Yanlışlıkla-eyerine-ryazmak yaygın bir kazadır.crontab -u kullanici -e— Başka bir kullanıcının crontab'ını düzenler (root yetkisi gerekir).
Crontab dosyasının biçimi basittir: # ile başlayan satırlar yorumdur ve dikkate alınmaz; her görev tek bir satırda tanımlanır. Bir satır, zamanlama alanları ile onu takip eden komuttan oluşur:
# dakika saat gün ay haftanın-günü komut
30 3 * * * /usr/local/bin/yedek-al.sh
Yukarıdaki örnek, her gün saat 03:30'da /usr/local/bin/yedek-al.sh betiğini çalıştırır. Şimdi bu satırın kalbindeki beş alanı yakından inceleyelim.
5 Alanlı Söz Dizimi#
Her cron satırının başında, boşlukla ayrılmış beş zaman alanı bulunur. Bu alanların sırası ve alabileceği değerler aşağıdaki gibidir.
| Alan | Anlamı | İzin verilen değerler |
|---|---|---|
| 1 | Dakika | 0–59 |
| 2 | Saat | 0–23 (24 saat biçimi) |
| 3 | Ayın günü | 1–31 |
| 4 | Ay | 1–12 (veya jan–dec) |
| 5 | Haftanın günü | 0–7 (0 ve 7 = Pazar, veya sun–sat) |
Her alanda kullanabileceğiniz özel karakterler işi çok esnek hâle getirir:
*— "her değer" anlamına gelir. Saat alanında*yazmak "her saat" demektir.,— Birden çok değeri listeler. Saat alanında8,12,18sabah 8, öğlen 12 ve akşam 6'yı ifade eder.-— Aralık belirtir. Gün alanında1-5Pazartesi'den Cuma'ya demektir./— Adım değeri verir. Dakika alanında*/15"her 15 dakikada bir" anlamına gelir.
Aşağıdaki tablo, en çok ihtiyaç duyacağınız zamanlama örneklerini bir arada gösterir:
| Cron ifadesi | Anlamı |
|---|---|
* * * * * | Her dakika |
*/5 * * * * | Her 5 dakikada bir |
0 * * * * | Her saat başı (dakika 0'da) |
0 3 * * * | Her gün saat 03:00 |
30 2 * * 0 | Her Pazar saat 02:30 |
0 0 1 * * | Her ayın 1'inde gece yarısı |
0 9 * * 1-5 | Hafta içi her gün saat 09:00 |
*/10 8-18 * * * | 08:00–18:00 arası her 10 dakikada bir |
Burada çok kişiyi tuzağa düşüren bir ayrıntı var: ayın günü (3. alan) ile haftanın günü (5. alan) aynı satırda birlikte belirtildiğinde (yani ikisi de * değilse) cron bunları "VE" ile değil "VEYA" ile birleştirir. Yani 0 0 1 * 1 ifadesi "yalnızca 1'ine denk gelen Pazartesi" değil, "her ayın 1'inde veya her Pazartesi" anlamına gelir ve haftada bir mutlaka tetiklenir. İki koşulu gerçekten kesiştirmek isterseniz, kontrolü betiğin içine taşımanız (örneğin gün numarasını sınamanız) gerekir.
Yazdığınız bir ifadeden emin olamadığınızda, satırı test etmeden önce anlamını insan diline çeviren çevrimiçi araçlarımıza göz atabilir ya da ifadeyi bir kâğıda çıkararak alan alan doğrulayabilirsiniz.
Özel Dizeler: @daily, @reboot ve Diğerleri#
Sık kullanılan zamanlamaları beş alanla yazmak yerine, cron'un okunması kolay kısayol dizelerini kullanabilirsiniz. Bunlar zamanlama alanlarının tamamının yerini alır:
| Kısayol | Eşdeğeri | Anlamı |
|---|---|---|
@yearly / @annually | 0 0 1 1 * | Yılda bir, 1 Ocak gece yarısı |
@monthly | 0 0 1 * * | Her ayın 1'inde gece yarısı |
@weekly | 0 0 * * 0 | Her Pazar gece yarısı |
@daily / @midnight | 0 0 * * * | Her gün gece yarısı |
@hourly | 0 * * * * | Her saat başı |
@reboot | — | Sunucu her yeniden başladığında bir kez |
Örneğin gece yarısı çalışan bir günlük temizlik betiği şöyle sadeleşir:
@daily /usr/local/bin/gunluk-temizlik.sh
@reboot özellikle işe yarar: sistem her açıldığında bir defa çalışması gereken işler (örneğin bir uygulama sunucusunu ayağa kaldırmak veya bir tünel bağlantısı kurmak) için idealdir. Ancak @reboot görevlerinin sistem servisleri tam oturmadan önce tetiklenebileceğini unutmayın; kritik servis bağımlılıkları için ilerideki systemd timer yaklaşımı daha sağlamdır.
PATH ve Ortam Sorunu#
Cron'la uğraşan herkesin er ya da geç çarptığı duvar şudur: komut terminalde kusursuz çalışır, ama tıpatıp aynısı cron içinde çalışmaz. Sebep neredeyse hiç değişmez. Terminale girdiğinizde kabuk; ~/.bashrc, ~/.profile ve /etc/profile gibi dosyaları okur, PATH'i zenginleştirir, alias'ları ve ortam değişkenlerini yükler. Cron ise görevi bunların hiçbiri olmadan, çıplak bir ortamda başlatır. Kullanıcı crontab'larında PATH çoğunlukla yalnızca /usr/bin:/bin gibi kısacık bir listeye iner.
Bu yüzden terminalde php yazınca çalışan komut, cron içinde "command not found" hatası verebilir. Çözümü basittir: komutları tam yol (mutlak yol) ile yazın.
# Yanlış — cron php'yi bulamayabilir
0 2 * * * php /var/www/site/artisan schedule:run
# Doğru — mutlak yol kullanılıyor
0 2 * * * /usr/bin/php /var/www/site/artisan schedule:run
Bir komutun tam yolunu öğrenmek için terminalde which php yazmanız yeterlidir. Alternatif olarak, crontab dosyasının en üstünde PATH değişkenini kendiniz tanımlayabilirsiniz:
PATH=/usr/local/bin:/usr/bin:/bin
SHELL=/bin/bash
0 2 * * * php /var/www/site/artisan schedule:run
Aynı mantık ortam değişkenleri için de geçerlidir. Uygulamanız .env dosyasına veya ~/.bashrc içinde tanımlı bir değişkene güveniyorsa, cron bunu bilmez. Bu durumda betiğinizin içinde gerekli değişkenleri açıkça export edin ya da betiğin başında ilgili dosyayı source ile yükleyin:
#!/bin/bash
source /home/kullanici/.profile
export APP_ENV=production
# ... asıl işler ...
Çıktı Yönlendirme ve Loglama#
Varsayılan olarak cron, çalıştırdığı bir görevin ekrana bastığı her şeyi (standart çıktı ve hata çıktısı) yakalar ve görevin sahibine e-posta olarak göndermeye çalışır. Sunucularda genellikle yerel posta yapılandırılmadığından bu e-postalar ya kaybolur ya da sistem loglarını şişirir. Bu yüzden çıktıyı bilinçli biçimde yönlendirmek iyi bir alışkanlıktır.
Çıktıyı bir log dosyasına yazmak için >> (ekleme) operatörünü kullanın. 2>&1 eklemesi ise hata çıktısını da aynı dosyaya yönlendirir:
0 3 * * * /usr/local/bin/yedek-al.sh >> /var/log/yedek.log 2>&1
Görevin çıktısıyla hiç ilgilenmiyorsanız, her şeyi "çöp kutusu"na göndererek e-posta bildirimlerini tamamen susturabilirsiniz:
*/10 * * * * /usr/local/bin/kuyruk-isle.sh > /dev/null 2>&1
Kritik görevler için sadece hataları loglamak, log dosyasının gereksiz büyümesini önler. Aşağıdaki örnekte normal çıktı atılır, yalnızca hatalar dosyaya yazılır:
0 4 * * * /usr/local/bin/db-yedek.sh > /dev/null 2>> /var/log/yedek-hata.log
İpucu: Log dosyalarının zamanla dev boyutlara ulaşmaması için
logrotateile döndürme kuralı tanımlayın veya betiğinizin başına bir tarih damgası ekleyin. Bu, bir sorun çıktığında hangi çalıştırmada ne olduğunu geriye dönük izlemenizi kolaylaştırır. Düzenli veritabanı yedekleri gibi kritik işlerde loglama, bir gün mutlaka hayat kurtarır; yedekleme stratejisi için WordPress yedekleme rehberimizdeki prensipler diğer uygulamalara da uyarlanabilir.
Sık Yapılan Hatalar ve Sorun Giderme#
Cron görevleriniz sessizce çalışmıyorsa, sırayla şu noktaları kontrol edin. Bu liste, gerçek hayatta karşılaşılan sorunların büyük çoğunluğunu kapsar.
- Mutlak yol kullanmamak. Hem komutun kendisini hem de içinde geçen dosya yollarını tam yol ile yazın. Cron'un çalışma dizini genellikle kullanıcının ana dizinidir,
~/betiklergibi göreli yollara güvenmeyin. - Betiğin çalıştırma izni olmaması. Bir
.shbetiğini doğrudan yol vererek çağırıyorsanız,chmod +x /usr/local/bin/yedek-al.shile çalıştırma iznini verdiğinizden emin olun. Dosya izinleri konusunda ayrıntı için yine temel Linux komutları rehberine bakabilirsiniz. - Yüzde işareti (
%) sorunu. Cron, komut satırındaki işlenmemiş%karakterini satır sonu (yeni satır) olarak yorumlar; ilk%'den sonrasını da komuta standart girdi olarak besler. Bu yüzdendate +\%Y-\%m-\%dgibi ifadelerde%işaretlerini ters bölü (\) ile kaçırmanız gerekir, aksi hâlde komut beklenmedik biçimde bölünür. - Zaman dilimi karışıklığı. Cron, sistemin saat dilimini kullanır. Sunucunuz UTC ise, "gece 3" yerel saatinizde başka bir vakte denk gelebilir.
timedatectlile sunucunun saat dilimini kontrol edin. - Görevin çalışıp çalışmadığını doğrulamak. Sistem loglarında cron kayıtlarını inceleyin: Debian/Ubuntu'da
grep CRON /var/log/syslog, systemd tabanlı sistemlerdejournalctl -u cron(veyacrond) komutları görevlerin ne zaman tetiklendiğini gösterir. - Betiği daraltılmış bir ortamda test etmek. Bir görev terminalde çalışıp cron'da çalışmıyorsa, sorunun kaynağı neredeyse her zaman ortam farkıdır. Betiği
env -i /bin/bash -c '/usr/local/bin/betik.sh'ile neredeyse boş bir ortamda çağırırsanız,PATHve değişken bağımlılıklarını cron'unkinden bile sert biçimde ortaya çıkarır; burada çalışan bir betik cron'da da büyük olasılıkla sorunsuz çalışır.
systemd Timer: Modern Alternatif#
Cron son derece sağlam ve her yerde bulunan bir araç olmakla birlikte, systemd kullanan modern dağıtımlar (Ubuntu, Debian, AlmaLinux, Rocky) daha yetenekli bir alternatif sunar: systemd timer. Cron'a kıyasla birkaç avantajı vardır: görevler journalctl ile birlikte merkezî olarak loglanır, kaçırılan çalıştırmalar sistem kapalıyken bile telafi edilebilir (Persistent=true), bağımlılıklar ve kaynak sınırları tanımlanabilir, saniye hassasiyeti mümkündür.
Bir timer, iki dosyadan oluşur: işi tanımlayan bir .service ve zamanlamayı belirleyen bir .timer. Örneğin her gün 03:00'te bir yedek betiği çalıştırmak için önce servis dosyasını oluşturun:
# /etc/systemd/system/yedek.service
[Unit]
Description=Gunluk yedek gorevi
[Service]
Type=oneshot
ExecStart=/usr/local/bin/yedek-al.sh
Ardından zamanlayıcı dosyasını yazın:
# /etc/systemd/system/yedek.timer
[Unit]
Description=Gunluk yedegi 03:00'te calistir
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.target
Son olarak timer'ı etkinleştirin ve durumunu kontrol edin:
sudo systemctl daemon-reload
sudo systemctl enable --now yedek.timer
systemctl list-timers # Sıradaki tüm timer'ları listeler
Basit, tekil görevler için cron hâlâ en pratik seçenektir; kısa bir satırla işiniz biter. Ancak yeniden denenmesi gereken, sıkı loglama isteyen ya da başka servislere bağımlı karmaşık görevler için systemd timer daha güvenli ve gözlemlenebilir bir zemin sunar. İkisi aynı sunucuda rahatça bir arada yaşayabilir.
Sıkça Sorulan Sorular#
Cron ile crontab arasındaki fark nedir?#
Cron, arka planda çalışıp zamanlanmış görevleri tetikleyen sistem servisinin adıdır. Crontab ise bu servise hangi komutun ne zaman çalışacağını söyleyen yapılandırma dosyasının (ve o dosyayı yöneten crontab komutunun) adıdır. Kısacası cron motordur, crontab ise ona verdiğiniz talimat listesidir.
Cron görevini her 30 saniyede bir çalıştırabilir miyim?#
Cron'un en küçük çözünürlüğü bir dakikadır, bu yüzden doğrudan 30 saniyelik bir aralık tanımlayamazsınız. Pratik bir çözüm, dakikada bir çalışan bir görev tanımlayıp betiğin içinde sleep 30 ile bekleyen ikinci bir çağrı eklemektir. Saniye hassasiyeti gerçekten gerekiyorsa, systemd timer'ın OnUnitActiveSec=30s seçeneği daha temiz bir yol sunar.
Cron görevim neden çalışmıyor?#
En yaygın sebep, komutun veya dosya yollarının mutlak yol ile yazılmamış olması ve cron'un dar PATH ortamıdır. İkinci sırada betiğin çalıştırma izninin olmaması gelir. grep CRON /var/log/syslog veya journalctl -u cron ile görevin gerçekten tetiklenip tetiklenmediğini kontrol edin ve komutu tam yolla yeniden yazın.
crontab -e ile yaptığım değişiklik hemen aktif olur mu?#
Evet. crontab -e ile düzenlemeyi kaydedip çıktığınızda cron servisi dosyayı otomatik olarak yeniden okur; ayrıca herhangi bir servisi yeniden başlatmanıza gerek yoktur. Yeni zamanlama, kaydettikten sonraki ilk uygun dakikada devreye girer.
Cron görevlerinin çıktısını nasıl kaydederim?#
Görev satırının sonuna >> /var/log/gorev.log 2>&1 ekleyerek hem normal çıktıyı hem de hataları belirttiğiniz dosyaya yazabilirsiniz. Çıktıyla ilgilenmiyorsanız > /dev/null 2>&1 ekleyerek e-posta bildirimlerini tamamen susturabilirsiniz. Sadece hataları loglamak için > /dev/null 2>> /var/log/hata.log biçimini kullanın.
Cron ve systemd timer, bir sunucuyu bakımlı ve öngörülebilir tutmanın en temel araçlarıdır; bir kez kurduğunuzda yıllarca sizin yerinize çalışırlar. Bu tür otomasyonların gerçek değeri, root erişimine ve tam denetime sahip olduğunuz bir ortamda ortaya çıkar. Kendi zamanlanmış görevlerinizi özgürce kurmak istiyorsanız, yönetiminiz tamamen sizde olan bir VDS sunucu ya da bulut sunucu çözümü sağlam bir başlangıç noktasıdır. Kurulum ve güvenlik tarafında takıldığınız her adımda, buradaki rehberler ve destek ekibimiz yanınızda.