Otomatisasi pekerjaan berulang di server dengan Cron Jobs dan Systemd Timers: sintaks cron lima kolom, pengalihan output ke file log, hingga pasangan unit service + timer untuk jadwal yang lebih robust. Lengkap dengan studi kasus menjadwalkan skrip backup harian dan jebakan yang sering dialami admin.

Setelah di episode 21 sebelumnya kita membahas monitoring sistem — cara mengamati penggunaan resource, proses yang berjalan, dan log untuk mengetahui kondisi server setiap saat — pada episode kali ini kita akan mengubah perspektif: dari sekadar melihat masalah menjadi mencegah masalah lewat otomatisasi.
Memelihara server itu seperti mengurus sebuah apartemen. Ada rutinitas yang harus dikerjakan tiap hari: membuang sampah, memeriksa lampu, memastikan pintu terkunci, menyalakan penghangat sebelum penghuni bangun. Kalau semua itu dikerjakan manual oleh satu orang, cepat atau lambat ada yang terlewat — dan yang terlewat biasanya justru yang paling penting. Di sinilah task automation berperan: cron dan systemd timers adalah "asisten" yang tidak pernah lupa, tidak pernah sakit, dan tidak pernah libur. Mereka bekerja di latar belakang persis pada waktu yang kalian tentukan, dan mencatat apa yang mereka kerjakan.
Di dunia DevOps, hampir semua operasi rutin — backup database, rotasi log, pembaruan sertifikat TLS, pembersihan direktori tmp, sampai sinkronisasi data antar server — dijalankan oleh scheduler semacam ini. Menguasainya bukan sekadar mempelajari dua perintah, melainkan memahami mental model menjadwalkan pekerjaan dengan benar: kapan menjalankannya, bagaimana melacak hasilnya, dan apa yang terjadi jika gagal.
Pada episode ini kita akan membahas cron terlebih dahulu sebagai pendekatan klasik yang masih mendominasi, lalu systemd timers sebagai alternatif modern yang lebih robust. Kita bandingkan keduanya dalam tabel, praktikkan dengan menjadwalkan skrip backup harian, dan menutup dengan kesalahan umum yang paling sering menjebak admin baru.
Sebelum membahas tool-nya, mari kita pahami mengapa otomatisasi bukan sekadar kemudahan, melainkan keharusan operasional.
Pertama, konsistensi. Sebuah skrip yang dijalankan scheduler setiap hari menghasilkan hasil yang identik dari waktu ke waktu — berbeda dengan tangan manusia yang bisa lengah. Kedua, ketepatan waktu. Skrip pembersihan log yang dijalankan pukul 03.00 pagi saat trafik sepi berbeda dampaknya dengan yang dijalankan manual di jam sibuk. Ketiga, auditability. Scheduler mencatat kapan tugas dijalankan dan apa hasilnya — jejak ini sangat berharga saat kalian harus menjawab pertanyaan "kenapa data hilang di tanggal X?" di kemudian hari.
Bayangkan skenario nyata: database produksi backup-nya mysqldump setiap malam. Suatu hari disk rusak dan tim harus restore data dari backup. Tanpa otomatisasi, backup terakhir mungkin sudah seminggu yang lalu karena "kemarin lupa". Dengan scheduler, backup selalu ada, selalu tepat waktu, dan tinggal di-restore. Itulah perbedaan antara admin yang selalu tenang menghadapi bencana dan admin yang panik.
Cron adalah daemon penjadwal klasik yang sudah menemani Linux sejak era awal Unix. Ia bekerja dengan membaca file bernama crontab (cron table), berisi daftar baris yang masing-masing menentukan kapan sebuah perintah dijalankan.
Ada beberapa lokasi crontab yang perlu kalian kenali:
| Lokasi | Pengguna | Kapan Dieksekusi |
|---|---|---|
crontab -e | Per-user | Perintah cron standar untuk user tertentu |
/etc/crontab | Root (sistem) | Sistem-wide, boleh menambahkan kolom user |
/etc/cron.d/ | Root | File crontab terpisah, sering dipakai oleh package |
/etc/cron.hourly/, /etc/cron.daily/ | Root | Skrip di dalam folder ini dijalankan sesuai jadwal foldernya |
Untuk mengelola crontab milik kalian sendiri, cukup tiga perintah yang paling sering dipakai:
crontab -e # buka crontab milik user saat ini di editor
crontab -l # tampilkan isi crontab saat ini
crontab -r # hapus seluruh crontab (hati-hati!)Inti dari cron adalah sintaks lima kolom. Setiap baris crontab memiliki lima kolom waktu diikuti perintah yang akan dijalankan:
* * * * * /usr/bin/backup.sh
┬ ┬ ┬ ┬ ┬
│ │ │ │ └──── day of week (0-7, 0 & 7 = Minggu)
│ │ │ └────── month (1-12)
│ │ └──────── day of month (1-31)
│ └────────── hour (0-23)
└──────────── minute (0-59)Tanda * berarti "setiap nilai pada kolom tersebut". Kalian juga bisa menulis daftar nilai yang dipisahkan koma (1,15,30), rentang (1-5), dan interval (*/15 = setiap 15). Berikut terjemahan dari pola yang paling sering dipakai:
| Ekspresi | Arti |
|---|---|
* * * * * | Setiap menit |
*/15 * * * * | Setiap 15 menit |
0 3 * * * | Setiap hari pukul 03.00 |
30 5 * * 1 | Setiap Senin pukul 05.30 |
0 2 1 * * | Setiap tanggal 1, pukul 02.00 |
0 0 * * 1-5 | Setiap hari kerja (Senin–Jumat) tengah malam |
Salah satu fakta yang paling sering membuat admin bingung: cron tidak menjalankan perintah dengan environment seperti terminal kalian. Ia tidak memuat ~/.bashrc, tidak punya PATH yang lengkap, dan tidak mewarisi variabel environment dari sesi login. Cron hanya mengeksekusi perintah dengan PATH minimal — biasanya cukup untuk sh, rm, cp, dan sejenisnya, tapi tidak untuk binary yang tinggal di /usr/local/bin/.
Akibatnya, menulis crontab -e lalu mengisi 0 3 * * * mybackup akan menghasilkan error command not found di log — bukan karena perintahnya salah, melainkan karena cron tidak tahu di mana mybackup berada. Solusinya selalu: gunakan path absolut, atau set PATH secara eksplisit di bagian atas crontab.
Masalah kedua adalah output yang tidak pernah terlihat. Ketika skrip cron mencetak output, cron menampungnya dan mengirimnya lewat email lokal — yang di server minimalis sering tidak terpasang (postfix tidak diinstall), sehingga output itu diam-diam hilang. Padahal output itulah satu-satunya jejak bahwa skrip berjalan. Solusinya: arahkan output ke file log secara eksplisit.
0 3 * * * /usr/local/bin/backup.sh
0 3 * * * /usr/local/bin/backup.sh >> /var/log/mycron.log 2>&1Mari kita bedah baris yang ditandai. >> adalah append — menambahkan output ke akhir file tanpa menghapus isi lama (ingat kembali operator redirection dari episode 5). 2>&1 menggabungkan stderr ke stdout, sehingga error pun ikut tercatat di file yang sama. Urutan ini penting: >> /var/log/mycron.log 2>&1 berarti "stdout masuk ke file, lalu stderr ikut ke arah yang sama". Hasilnya, satu file log berisi seluruh jejak eksekusi — mudah di-grep dan tidak ada output yang hilang.
Warning
Selalu tulis path absolut untuk perintah maupun file di dalam crontab. Cron tidak memuat PATH dari shell login, jadi pg_dump atau restic yang tinggal di /usr/local/bin/ tidak akan ditemukan. Tulis /usr/local/bin/pg_dump — atau, yang lebih rapi, definisikan PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin di baris pertama crontab kalian.
Cron sudah berusia puluhan tahun dan tetap bekerja — tetapi ia punya keterbatasan struktural yang terasa di server modern. Di sinilah systemd timers datang sebagai pengganti yang lebih robust.
Apa kelebihannya? Pertama, integrasi dengan journald. Output skrip langsung terekam di journal (journalctl), tidak perlu repot mengalihkan output manual. Kedua, dependensi yang eksplisit. Kalian bisa memastikan timer hanya berjalan setelah network online, atau setelah service lain hidup. Ketiga, trigger yang fleksibel — tidak hanya kalender (OnCalendar), tapi juga monotonic seperti OnBootSec (15 menit setelah boot) atau OnUnitActiveSec (setiap 1 hari setelah eksekusi terakhir). Keempat, missed-run handling: dengan Persistent=true, jika server mati saat jadwal tiba, timer akan menjalankan tugas begitu server hidup kembali — perilaku yang tidak dimiliki cron.
Analoginya: cron itu seperti alarm jam weker yang tetap berbunyi meski kalian sedang tidak di rumah. Systemd timer itu seperti asisten yang tahu jadwal, dan ketika kalian kembali, dia melaporkan "kemarin ada yang terlewat, sudah saya kerjakan".
Seperti semua unit systemd, timer bekerja berpasangan: satu file .service yang mendefinisikan apa yang dikerjakan, dan satu file .timer yang mendefinisikan kapan dikerjakan. Keduanya diletakkan di /etc/systemd/system/:
[Unit]
Description=Daily backup service
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.shPerhatikan beberapa detail penting. Type=oneshot memberitahu systemd bahwa service ini berjalan singkat dan selesai — bukan daemon yang berjalan terus. OnCalendar=*-*-* 03:00:00 adalah ekspresi waktu versi systemd yang setara dengan 0 3 * * * pada cron. Persistent=true menangani kasus server mati saat jadwal tiba. Dan WantedBy=timers.target mengikat timer ke target khusus timer.
Setelah kedua file dibuat, aktifkan dan verifikasi:
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers backup.timerNEXT LEFT LAST PASSED UNIT ACTIVATES
Sat 2026-08-03 03:00:00 WIB 15h 19min left Fri 2026-08-02 03:00:00 WIB 8h ago backup.timer backup.service
Sat 2026-08-03 06:55:45 WIB 19h left n/a n/a fstrim.timer fstrim.service
1 timers listed.Hasil systemctl list-timers akan menunjukkan jadwal berikutnya (NEXT) dan eksekusi terakhir (LAST). Untuk melihat jejak eksekusi service, cukup baca journal:
journalctl -u backup.service -bTip
systemd timers unggul karena jejak eksekusi otomatis tercatat di journald dengan struktur dan timestamp yang rapi. Untuk cron, kalian harus mengatur redirection sendiri (>> log 2>&1) dan menebak-nebak jika lupa. Jika server kalian sudah berbasis systemd — dan semua distro modern menggunakannya sejak episode 14 — tidak ada alasan kuat untuk menolak timers.
Berikut perbandingan ringkas yang bisa menjadi panduan keputusan:
| Aspek | Cron | Systemd Timers |
|---|---|---|
| Sintaks waktu | 5 kolom (0 3 * * *) | OnCalendar / OnBootSec / OnUnitActiveSec |
| Output skrip | Harus dialihkan manual | Otomatis masuk journald |
| Dependensi | Tidak ada | Dideklarasikan di [Unit] |
| Jadwal terlewat saat shutdown | Tidak dikejar | Bisa dikejar dengan Persistent=true |
| Jeda antar eksekusi | Tidak ada (hanya waktu kalender) | OnUnitActiveSec — mudah |
| Environment | PATH minimal | Lingkungan unit yang bisa diatur |
| Kompatibilitas | Semua sistem | Hanya sistem berbasis systemd |
Kapan memakai yang mana? Jika kalian hanya butuh "jalankan ini tiap tengah malam" di sistem yang tidak berbasis systemd (misal Alpine, atau kontainer minimal), cron masih sempurna. Jika kalian mengelola server modern dan ingin jejak log rapi, dependensi jelas, dan jadwal yang tidak mudah terlewat, systemd timers adalah pilihan yang lebih baik.
Saatnya menggabungkan semuanya. Kita akan membuat skrip backup sederhana, lalu menjadwalkannya dengan kedua pendekatan.
Pertama, skrip backup. Skrip ini mengambil dump database PostgreSQL, mengompresinya, menyimpannya di direktori bertanggal, dan membersihkan file yang lebih dari 7 hari — sehingga disk tidak penuh oleh backup tua.
#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR=/srv/backups/daily
mkdir -p "$BACKUP_DIR"
pg_dump -U myapp myapp_db | gzip > "$BACKUP_DIR/myapp-$(date +%F).sql.gz"
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +7 -deletePerhatikan set -euo pipefail di baris kedua — ini memastikan skrip berhenti dan mengembalikan status gagal jika ada langkah yang error. Tanpa ini, kegagalan pg_dump bisa lolos tanpa disadari karena pipeline | gzip masih "sukses". Pastikan file skrip bisa dieksekusi: chmod +x /usr/local/bin/backup.sh.
Setelah skrip siap, jadwalkan. Versi cron — tambahkan ke crontab -e:
0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1Versi systemd timer — dua file yang sama persis seperti pada bagian sebelumnya: backup.service menjalankan skrip, backup.timer menjadwalkannya pukul 03.00 dengan Persistent=true. Keduanya mencapai hal yang sama, tetapi versi systemd memberi kalian jejak journal dan jaminan eksekusi jika server sempat mati.
Caution
Uji skrip secara manual sebelum dijadwalkan. Jalankan sudo /usr/local/bin/backup.sh sekali di terminal dan lihat apakah dump terbentuk. Skrip yang belum pernah dijalankan manual dan langsung masuk cron adalah undangan bagi masalah yang baru ketahuan berminggu-minggu kemudian — persis pola "backup berjalan tapi datanya kosong" yang sering terjadi di dunia nyata.
1. Lupa path absolut. Sudah dibahas: cron tidak memuat PATH penuh. pg_dump, restic, atau skrip di /usr/local/bin tidak akan ditemukan. Gunakan path absolut atau set PATH di awal crontab.
2. Kesalahan kolom menit. 0 3 * * * berarti pukul 03.00 tepat; * 3 * * * berarti setiap menit selama jam 03.00 (60 kali eksekusi!). Perbedaan satu karakter * dan 0 adalah perbedaan antara "sekali sehari" dan "60 kali per jam". Verifikasi selalu dengan crontab -l setelah menulis.
3. Output tidak dialihkan. Tanpa >> log 2>&1, output cron dikirim ke email lokal yang tidak terpasang, lalu hilang. Setiap entry cron di server produksi harus mengarahkan output ke file log.
4. Lupa daemon-reload setelah membuat unit systemd. systemd meng-cache unit yang sudah dikenal. Setelah menulis atau mengubah file .service/.timer, kalian wajib menjalankan systemctl daemon-reload sebelum perintah enable diproses dengan benar.
5. Tidak mengecek apakah timer benar-benar aktif. systemctl enable backup.timer tanpa --now hanya mengaktifkan saat boot berikutnya — timer belum berjalan sekarang. Gunakan enable --now dan verifikasi dengan systemctl list-timers.
Pada episode 22 ini, kalian telah menguasai dua pendekatan task automation di Linux. Kita mulai dari cron: membaca dan mengelola crontab dengan crontab -e, crontab -l, dan crontab -r, memahami sintaks lima kolom, serta mengalihkan output dengan >> /var/log/mycron.log 2>&1 agar setiap eksekusi terekam. Lalu kita beralih ke systemd timers: pasangan unit .service + .timer, ekspresi OnCalendar, Persistent=true, dan keuntungan integrasi dengan journald. Kita membandingkan keduanya dalam tabel, menjadwalkan skrip backup harian, dan menutup dengan jebakan yang paling sering dialami admin.
Poin kunci yang perlu kalian bawa:
menit jam hari-bulan bulan hari-minggu — perhatikan perbedaan 0 vs * pada kolom menit.>> ... 2>&1).Persistent=true.systemctl daemon-reload lalu enable --now.Dengan kemampuan menjadwalkan tugas, kalian sudah siap membahas bahan mentah dari semua otomatisasi tersebut: log. Di episode 23 selanjutnya kita akan membongkar System Logging, Rotation & Auditing — memahami arsitektur /var/log/, mengenal log penting seperti syslog, auth.log, dan boot.log, mengelola rotasi dengan logrotate agar disk tidak penuh, hingga pengenalan rsyslog untuk logging terpusat dan auditd untuk jejak keamanan. Pastikan tetap semangat!