Scheduled Tasks: Cron and systemd Timers
Schedule tasks with cron and systemd timers. Crontab syntax, common patterns, logging, debugging scheduled jobs.
On this page
Cron is the Linux task scheduler that runs commands at specific times. Every backup, every cleanup script, every report generation runs on cron. Master cron and you automate your entire infrastructure. Crontab syntax is intimidating at first, but becomes intuitive.
Cron Overview
- Cron daemon (crond) runs in background
- Checks crontab files every minute
- Executes matching scheduled tasks
- Each user has separate crontab
- Root crontab has highest privilege
Crontab Syntax
MIN HOUR DOM MON DOW COMMAND
0 0 1 1 * /usr/bin/backup.sh # Run at 12:00am on Jan 1
| Field | Range | Meaning |
|---|---|---|
| MIN | 0-59 | Minute (0=00, 30=30th minute) |
| HOUR | 0-23 | Hour (0=midnight, 12=noon) |
| DOM | 1-31 | Day of month |
| MON | 1-12 | Month (1=Jan, 12=Dec) |
| DOW | 0-6 | Day of week (0=Sun, 6=Sat) |
Create and Edit Crontabs
# View current crontab
crontab -l
# Edit crontab (opens editor)
crontab -e
# Edit another user's crontab (as root)
crontab -u www-data -e
# Remove all cron jobs
crontab -r
# View system crontabs
ls -la /etc/cron.d/
Common Patterns
# Every minute
* * * * * /usr/bin/script.sh
# Every hour at :00
0 * * * * /usr/bin/hourly.sh
# Every day at 2:30 AM
30 2 * * * /usr/bin/daily.sh
# Every Monday at 6 PM
0 18 * * 1 /usr/bin/weekly.sh
# Every 1st of month at midnight
0 0 1 * * /usr/bin/monthly.sh
# Every 15 minutes
*/15 * * * * /usr/bin/frequent.sh
Practical Examples
# Backup database daily at 3 AM
0 3 * * * /usr/local/bin/backup-db.sh >> /var/log/backup.log 2>&1
# Clean old logs weekly (Sunday at 4 AM)
0 4 * * 0 find /var/log -name "*.log" -mtime +30 -delete
# Renewal SSL certificates (2 AM daily)
0 2 * * * certbot renew --quiet
# Check disk space every 6 hours
0 */6 * * * /usr/bin/check-disk.sh | mail -s "Disk Report" admin@example.com
systemd Timers
Modern alternative to cron (better for complex tasks):
# Create timer unit: /etc/systemd/system/backup.timer
[Unit]
Description=Daily backup timer
Requires=backup.service
[Timer]
OnCalendar=daily
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.target
# Create service unit: /etc/systemd/system/backup.service
[Unit]
Description=Backup script
After=network.target
[Service]
ExecStart=/usr/local/bin/backup.sh
Type=oneshot
# Enable and start
systemctl enable backup.timer
systemctl start backup.timer
Debug Cron Jobs
# Cron logs are in syslog
tail -100 /var/log/syslog | grep CRON
# Check if cron ran (shows output)
grep CRON /var/log/syslog | tail -20
# Debug: test script manually first
/usr/bin/script.sh
# Add logging to script
#!/bin/bash
echo "$(date) - Starting backup" >> /var/log/backup.log
# ... commands ...
echo "$(date) - Backup complete" >> /var/log/backup.log
Best Practices
- Use absolute paths: Don't rely on $PATH in cron. Use /usr/bin/python3 not python3
- Redirect output: Send stdout/stderr to log files. Use
>> /var/log/task.log 2>&1 - Set timeout: Long-running tasks should have timeout (use timeout command)
- Email alerts: Pipe output to mail if task fails. MAILTO=admin@example.com at top of crontab
- Avoid peak times: Don't schedule backups during business hours
- Test first: Always test script manually before adding to cron
Cron runs without a terminal. No $PATH, no HOME directory context, no environment variables. What works in your shell may fail in cron. Always use absolute paths and log output.
Related: systemd basics | Bash scripting | Process management | Log rotation
Need a developer-friendly server?
Use an UnderHost Cloud VPS for SSH, Git, Node.js, Python, Laravel, Docker, cron, and custom development workflows.





















