You know that feeling when you realize you've been doing the same boring task every single day — and it could have been automated the whole time?

That's what cron is for.

Cron is Linux's built-in task scheduler. It runs commands, scripts, or programs automatically at specific times — daily, hourly, every Monday, the 1st of each month, whatever you need. Once you set it up, you forget about it and it just works.

If you've followed our Linux Terminal Basics and SSH Beginner's Guide, cron is the natural next step — it turns you from someone who uses Linux into someone who automates Linux.

What Is Cron, Really?

Think of cron as a robot alarm clock. You tell it: "wake up at 3 AM every day and run this backup script." It does exactly that — no complaints, no forgetting, no "I was too busy."

It's been part of Unix-like systems since the 1970s and is still the standard way to schedule tasks on Linux servers, Raspberry Pis, and even macOS.

The name "cron" comes from the Greek word chronos (time). The program that runs in the background checking the schedule is called cron (the daemon), and each scheduled task is called a cron job.

Your First Cron Job in 60 Seconds

Open your terminal and type:

crontab -e

If this is your first time, it'll ask which editor to use. Pick nano (usually option 1) — it's the easiest for beginners.

Add this line at the bottom:

*/5 * * * * echo "I'm learning cron!" >> ~/cron-test.log

Save and exit (Ctrl+O, Enter, Ctrl+X in nano). That's it — you just created your first cron job. Every 5 minutes, it appends "I'm learning cron!" to a log file in your home directory.

Wait 5 minutes, then check:

cat ~/cron-test.log
# Output:
# I'm learning cron!
# I'm learning cron!

It ran. Congratulations — you've automated something.

Understanding Cron Syntax

That */5 * * * * looks like alien code at first glance. Here's what each position means:

*    *    *    *    *    command_to_run
│    │    │    │    │
│    │    │    │    └── Day of week (0-7, 0 and 7 = Sunday)
│    │    │    └────── Month (1-12)
│    │    └─────────── Day of month (1-31)
│    └──────────────── Hour (0-23)
└───────────────────── Minute (0-59)

A * means "every." So * * * * * means "every minute of every hour of every day..." — basically, constantly.

Here's a cheat sheet for the most common schedules:

Schedule Cron Syntax Meaning
Every minute * * * * * Runs 1,440 times per day — rarely useful!
Every 15 minutes */15 * * * * Good for health checks
Every hour 0 * * * * At the top of every hour
Daily at 3 AM 0 3 * * * Classic backup time
Daily at 9 AM 0 9 * * * Morning report or email
Weekdays at 9 AM 0 9 * * 1-5 Monday through Friday
Every Sunday at 3 AM 0 3 * * 0 Weekly cleanup
1st of month at midnight 0 0 1 * * Monthly billing or reports
At reboot @reboot Run once when the system starts

How the Fields Work Together

A few more examples to solidify the concept:

# Run at 8:30 AM every day
30 8 * * * /home/user/morning-report.sh

# Run at 11:45 PM every Saturday
45 23 * * 6 /home/user/weekend-cleanup.sh

# Run every 2 hours (at :00 of even hours)
0 */2 * * * /usr/local/bin/health-check.sh

# Run on Jan 1st at midnight (annual report)
0 0 1 1 * /opt/scripts/yearly-summary.sh

The key insight: minute and hour control the time, the other three control the date.

Managing Your Cron Jobs

Once you start creating cron jobs, you'll need to manage them. Here are the essential commands:

crontab -e     # Edit your cron jobs
crontab -l     # List all your cron jobs
crontab -r     # Remove ALL your cron jobs (careful!)

To edit someone else's cron jobs (as root):

crontab -u username -e   # Edit another user's crontab

Each user on the system has their own crontab. Your jobs run with your permissions — so a backup script that runs as your user can only access files you own, unless you use sudo inside the script.

Real-World Cron Job Examples

1. Automated Database Backup (Daily at 3 AM)

0 3 * * * /home/user/scripts/backup-db.sh >> /var/log/backup.log 2>&1

The >> /var/log/backup.log 2>&1 part is important — it saves both normal output AND error messages to a log file. Without this, you'd never know if the job failed.

Here's what a simple backup script might look like:

#!/bin/bash
# backup-db.sh — dump a MySQL database and keep the last 7 copies

DB_NAME="myapp"
BACKUP_DIR="/backups/db"
DATE=$(date +%Y-%m-%d)

mkdir -p "$BACKUP_DIR"
mysqldump "$DB_NAME" > "$BACKUP_DIR/$DB_NAME-$DATE.sql"

# Delete backups older than 7 days
find "$BACKUP_DIR" -name "*.sql" -mtime +7 -delete

echo "[$(date)] Backup complete: $DB_NAME-$DATE.sql"

2. Disk Space Monitor (Every Hour)

0 * * * * /home/user/scripts/check-disk.sh
#!/bin/bash
# check-disk.sh — send an alert if disk usage exceeds 90%

USAGE=$(df / | tail -1 | awk '{print $5}' | sed 's/%//')

if [ "$USAGE" -gt 90 ]; then
    echo "WARNING: Disk usage at ${USAGE}% on $(hostname)" | \
        mail -s "Disk Alert" admin@example.com
fi

This is a classic cron use case — monitor something, alert when something's wrong. Cron doesn't just run tasks; it can be your early warning system.

3. Update Package Lists (Weekly)

0 4 * * 0 sudo apt update && sudo apt upgrade -y >> /var/log/apt-updates.log

Run this on a Sunday at 4 AM, and your server keeps itself updated. The -y flag auto-confirms — use it cautiously in production!

4. Clean Up Temporary Files (Daily at Midnight)

0 0 * * * find /tmp -type f -mtime +7 -delete 2>/dev/null

This deletes files in /tmp that are older than 7 days. Simple, silent, effective — the perfect cron job.

Special Shortcut Notations

Instead of writing five-field schedules, cron supports these human-readable shortcuts:

Shortcut Equivalent To Use Case
@reboot (runs once at boot) Start services, mount drives
@yearly 0 0 1 1 * Annual reporting
@monthly 0 0 1 * * Billing, archiving
@weekly 0 0 * * 0 Cleanups, updates
@daily 0 0 * * * Backups, log rotation
@hourly 0 * * * * Health checks

Example:

@reboot /home/user/scripts/start-my-app.sh
@daily  /home/user/scripts/backup.sh

These are easier to read but less flexible — you can't say "daily at 5 AM" with @daily (it runs at midnight). Use the full five-field syntax when you need precise control.

System-Wide Cron vs. User Cron

So far we've used crontab -e, which edits your user's cron jobs. But Linux also has system-wide cron directories:

ls /etc/cron.*
# /etc/cron.d/       — custom cron files (with a username field)
# /etc/cron.daily/   — scripts here run once per day (via anacron)
# /etc/cron.hourly/  — scripts here run once per hour
# /etc/cron.weekly/  — scripts here run once per week
# /etc/cron.monthly/ — scripts here run once per month

These are managed by the system, not individual users. You can drop a script into /etc/cron.daily/ (make it executable with chmod +x), and it'll run automatically as root.

When to use which:

  • User crontab (crontab -e): Your personal projects, scripts in your home directory
  • System directories (/etc/cron.*): Server-wide tasks that need root privileges

Debugging Cron Jobs: The 3 Most Common Problems

Cron can be frustrating when things don't work. Here's what goes wrong 90% of the time:

Problem 1: PATH Is Different

Cron runs with a minimal PATH. Commands that work in your terminal might not be found by cron.

Fix: Always use absolute paths in cron jobs:

# ❌ BAD — python might not be found
0 3 * * * python /home/user/backup.py

# ✅ GOOD — full path to the exact Python you want
0 3 * * * /usr/bin/python3 /home/user/backup.py

Find the full path of any command with which:

which python3
# /usr/bin/python3

Problem 2: No Output, No Clue

If a cron job fails silently, you'll never know.

Fix: Always log output:

0 3 * * * /home/user/backup.sh >> /var/log/backup.log 2>&1

The >> appends stdout, and 2>&1 redirects stderr to the same place. Now errors won't be silent.

Problem 3: Script Permissions

Your script runs fine manually but fails in cron — probably a permissions issue.

Fix: Make sure the script is executable:

chmod +x /home/user/backup.sh

And test it the same way cron runs it:

env -i HOME=$HOME /bin/bash -c "/home/user/backup.sh"

The env -i strips the environment (like cron does), revealing any hidden dependencies.

Cron + SSH: The Power Combo

Once you've mastered SSH (covered in our SSH Beginner's Guide), you unlock a powerful pattern: cron jobs that act on remote servers.

# Daily: pull remote database backup to local machine
0 4 * * * scp user@remote-server:/backups/latest.sql /local/backups/

Or the reverse — run a command on a remote server from your local cron:

# Check if remote web server is responding
*/5 * * * * ssh monitor@web-server "curl -s -o /dev/null -w '%{http_code}' http://localhost" >> /var/log/health.log

This is how small teams set up monitoring without paying for SaaS tools — just cron, SSH, and a few lines of bash.

Best Practices Cheat Sheet

Practice Why
Use absolute paths Avoids PATH issues
Always log output (>> file 2>&1) Cron emails are unreliable on modern systems
Add comments (# what this does) You won't remember in 6 months
Don't overlap jobs Use a lock file if a job might run longer than its interval
Test with */5 first Verify it works at high frequency, then switch to the real schedule
Use MAILTO="" to suppress email Add MAILTO="" at the top of crontab if cron keeps emailing root
Non-zero exit = cron sends mail Return 0 on success, non-zero signals failure

Here's a well-structured crontab example that follows all best practices:

# ── My Cron Jobs ──────────────────────────────────────
MAILTO=""
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin

# Daily database backup at 3:00 AM
0 3 * * * /home/user/scripts/backup-db.sh >> /var/log/backup.log 2>&1

# Check disk space every hour
0 * * * * /home/user/scripts/check-disk.sh >> /var/log/disk-check.log 2>&1

# Clean up temp files every Sunday at 2 AM
0 2 * * 0 /home/user/scripts/cleanup.sh >> /var/log/cleanup.log 2>&1

Quick Reference: Build Your Own Cron Schedule

Use this table to construct any schedule. Find your desired frequency, copy the five-field expression:

I want it to run... Minute Hour Day Month Weekday
Every 5 minutes */5 * * * *
Every 30 minutes */30 * * * *
Every hour at :15 15 * * * *
Twice a day (9am, 5pm) 0 9,17 * * *
Daily at 3 AM 0 3 * * *
Weekdays at 8 AM 0 8 * * 1-5
Weekends at midnight 0 0 * * 0,6
Every Monday at 6 AM 0 6 * * 1
1st and 15th at noon 0 12 1,15 * *
Once a year (Jan 1) 0 0 1 1 *

What's Next?

Cron is the foundation of Linux automation. Once you're comfortable scheduling tasks, the next natural step is automating with Python — where you can write richer, more intelligent scripts than bash alone.

Check out:

Set up your first cron job today. Pick something small — a daily log, a disk space check, a "good morning" file. The habit of automating repetitive work is more valuable than any single cron job.