Server produksi kamu penuh karena file log tidak pernah dibersihkan, dan kamu baru sadar setelah aplikasinya down. Backup database terakhir ternyata dijalankan dua minggu lalu karena kamu lupa. Dua masalah ini punya akar yang sama: tidak ada yang menjalankan tugas itu secara otomatis. Di Linux, alat untuk itu sudah terpasang sejak lama — namanya cron.

Apa itu cron dan crontab

Cron adalah daemon yang berjalan di latar belakang dan mengeksekusi perintah sesuai jadwal. Kamu menulis jadwal itu di sebuah file bernama crontab, lalu cron membacanya ulang setiap menit. Setiap pengguna bisa punya crontab sendiri, jadi pekerjaan root dan pekerjaan user biasa hidup terpisah.

Membuka dan mengedit crontab

bash
# lihat isi crontab user yang sedang login
crontab -l

# buka editor untuk mengedit crontab
crontab -e

# hapus seluruh crontab user
crontab -r

Saat pertama kali menjalankan crontab -e, sistem menanyakan editor mana yang mau kamu pakai. Pilih nano kalau belum terbiasa dengan vim. Kalau sudah terlanjur memilih editor yang tidak kamu suka, ubah lewat variabel EDITOR.

bash
export EDITOR=nano

Anatomi sebuah baris crontab

Setiap baris yang bukan komentar terdiri dari lima kolom waktu diikuti satu perintah. Urutannya: menit, jam, hari dalam bulan, bulan, hari dalam minggu.

bash
# ┌───────────── menit (0-59)
# │ ┌──────────── jam (0-23)
# │ │ ┌────────── hari dalam bulan (1-31)
# │ │ │ ┌──────── bulan (1-12)
# │ │ │ │ ┌───── hari dalam minggu (0-7, 0 dan 7 = Minggu)
# │ │ │ │ │
# * * * * * /path/ke/perintah

Tanda bintang berarti “setiap nilai”, jadi * * * * * artinya tiap menit, tiap jam, tiap hari. Koma memisahkan daftar nilai, garis miring menandakan interval, dan tanda hubung menandakan rentang.

bash
# setiap menit
* * * * * /home/user/script.sh

# setiap hari jam 03:30
30 3 * * * /usr/local/bin/backup.sh

# setiap 15 menit
*/15 * * * * /usr/bin/checker

# Senin-Jumat jam 09:00
0 9 * * 1-5 /usr/bin/morning-report

# tanggal 1 setiap bulan, jam 00:00
0 0 1 * * /usr/bin/billing

Bingung dengan ekspresi seperti */15 atau 1-5? Tempel di crontab.guru. Situs itu menerjemahkan ekspresi cron ke bahasa manusia, jadi kamu tidak perlu menghafal semua aturannya.

String khusus: @daily, @reboot, dan lainnya

Cron punya beberapa kata pengganti untuk jadwal umum. @reboot menjalankan perintah sekali setiap sistem boot. @daily sama dengan 0 0 * * *, @weekly sama dengan 0 0 * * 0, dan @hourly sama dengan 0 * * * *.

bash
@reboot /usr/local/bin/start-app.sh
@daily  /usr/local/bin/cleanup.sh
@hourly /usr/local/bin/ping-check.sh

Output, log, dan MAILTO

Default-nya, output cron job dikirim lewat email ke pemilik crontab. Kalau tidak ada mail server terpasang, pesan itu menumpuk di mailbox lokal dan jarang ada yang membaca. Karena itu hampir semua orang mengarahkan output ke file log atau membuangnya ke /dev/null.

bash
# simpan output ke file log (mode append)
0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

# buang semua output
0 3 * * * /usr/local/bin/backup.sh > /dev/null 2>&1

Angka 2>&1 menggabungkan stderr ke stdout, jadi pesan error ikut tertulis atau ikut dibuang. Tanpa itu, error tetap berusaha dikirim lewat email.

Environment: alasan cron terasa tidak jalan

Ini jebakan nomor satu. Script jalan sempurna saat kamu eksekusi manual, tapi tidak jalan di cron. Penyebabnya hampir selalu PATH: cron memakai PATH minimal seperti /usr/bin:/bin, sedangkan shell interaktifmu memuat banyak path dari .bashrc dan .profile.

Cron tidak membaca .bashrc maupun .profile. Kalau script-mu memanggil pg_dump, python3, atau node tanpa path lengkap, cron bisa gagal menemukannya. Solusinya: tulis path absolut untuk setiap perintah di dalam script, atau setel PATH di baris paling atas crontab.

bash
# setel PATH di baris atas crontab
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# atau panggil perintah dengan path lengkap
0 3 * * * /usr/bin/pg_dump myapp > /backup/myapp.sql

Studi kasus: backup PostgreSQL tiap jam 2 pagi

Contoh nyata yang sering saya pakai: dump database PostgreSQL setiap malam plus rotasi 7 hari. Kalau belum pernah menyentuh PostgreSQL, baca dulu panduan PostgreSQL di blog ini. Kalau script Bash-nya masih terasa asing, ada juga panduan Bash scripting yang bisa kamu buka di tab lain.

bash
#!/bin/bash
# /usr/local/bin/db-backup.sh

DB="myapp"
BACKUP_DIR="/var/backups/postgres"
RETENTION_DAYS=7

mkdir -p "$BACKUP_DIR"
STAMP=$(date +%Y%m%d_%H%M%S)

/usr/bin/pg_dump -Fc "$DB" > "$BACKUP_DIR/${DB}_${STAMP}.dump"

# hapus backup yang lebih tua dari batas retensi
find "$BACKUP_DIR" -name "${DB}_*.dump" -mtime +$RETENTION_DAYS -delete

Setelah script tersimpan, beri izin eksekusi lalu daftarkan ke crontab. Output diarahkan ke file log supaya gampang dicek besok paginya.

bash
chmod +x /usr/local/bin/db-backup.sh
crontab -e
# tambahkan baris ini:
0 2 * * * /usr/local/bin/db-backup.sh >> /var/log/db-backup.log 2>&1

Cron system-wide: /etc/crontab dan /etc/cron.d

Selain crontab per-user, ada jadwal tingkat sistem. File /etc/crontab punya satu kolom tambahan: nama pengguna yang menjalankan perintah. Format yang sama dipakai file-file di /etc/cron.d. Lalu ada empat direktori — /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly, /etc/cron.monthly — yang otomatis menjalankan script di dalamnya.

bash
# /etc/crontab — kolom ke-6 adalah user
17 *  * * *  root  cd / && run-parts --report /etc/cron.hourly
25 6  * * *  root  test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.daily; }

Testing dan debugging

Jangan menunggu jam 2 pagi untuk tahu job-mu jalan atau tidak. Uji script dengan environment yang meniru cron: kosongkan environment pakai env -i, lalu setel PATH minimal.

bash
# tiru environment cron
env -i PATH=/usr/bin:/bin /bin/bash /usr/local/bin/db-backup.sh

Kalau dengan env -i script jalan tapi di cron tetap diam, cek log sistem untuk memastikan cron benar-benar mengeksekusinya.

bash
# Debian/Ubuntu
grep CRON /var/log/syslog | tail -20

# distro berbasis systemd (Fedora, Arch, CentOS)
journalctl -u cron -n 20

Jebakan lain yang sering bikin pusing

Tanda persen (%) punya arti khusus di crontab: ia diubah menjadi baris baru. Perintah yang memakai format tanggal seperti date +%Y%m%d harus ditulis date +\%Y\%m\%d, atau lebih aman dipindah ke script terpisah. Lalu, cron tidak menunggu job sebelumnya selesai. Kalau backup-mu bisa memakan waktu lebih lama dari intervalnya, dua instance bisa berjalan bersamaan — pakai flock untuk mencegahnya. Terakhir, cron mengikuti timezone sistem, bukan timezone yang kamu setel di shell.

Kalau butuh lebih dari ini: systemd timer

Untuk jadwal presisi detik, dependensi antar unit, atau integrasi dengan journald, coba systemd timer. Banyak distro modern mulai mengarahkan penggunanya ke sana, tapi cron tetap alat paling sederhana untuk kebanyakan kebutuhan harian. Kalau kamu sudah terbiasa menjalankan aplikasi Python sebagai service systemd, konsep timernya tidak akan terasa asing.

Kenapa cron job saya tidak berjalan padahal sudah saya set?

Tiga penyebab paling sering: PATH cron yang terbatas sehingga perintah tidak ditemukan (pakai path absolut), file crontab tidak diakhiri baris baru, atau daemon cron yang mati (cek dengan systemctl status cron). Jalankan script dengan env -i PATH=/usr/bin:/bin /bin/bash script.sh untuk meniru environment cron dan melihat errornya langsung.

Bagaimana cara menjalankan cron job setiap 5 menit?

Pakai */5 di kolom menit: */5 * * * * /path/ke/script.sh. Artinya “setiap nilai yang habis dibagi 5”, yaitu menit 0, 5, 10, 15, dan seterusnya.

Apa bedanya crontab -e dengan mengedit /etc/crontab?

crontab -e mengedit jadwal milik pengguna yang sedang login dan menyimpannya per-user. File /etc/crontab adalah jadwal tingkat sistem dengan satu kolom tambahan untuk menentukan user yang menjalankan perintah. Untuk kebutuhan pribadi pakai crontab -e; untuk jadwal yang harus jalan terlepas siapa yang login, taruh di /etc/cron.d.