Tutorial

Cron Jobs Explained: Schedule Tasks on Linux Like a Pro

April 04, 2026

Back to Blog

Automation is the backbone of effective server administration. Whether you need to run daily backups, rotate logs every week, clear temporary files, or check disk usage every hour, doing these tasks manually is tedious and error-prone. Linux cron jobs solve this problem by letting you schedule commands to run automatically at specific times, dates, or intervals — reliably and silently in the background.

This guide will take you from cron basics to advanced scheduling patterns, with practical examples for every common use case. By the end, you will be able to automate virtually any recurring task on your Linux server.

What Is Cron?

Cron is a time-based job scheduler built into virtually every Unix and Linux system. The cron daemon (crond or cron) runs continuously in the background and checks every minute whether any scheduled jobs need to be executed. Each user on a system can have their own crontab (cron table) — a file that lists commands and their schedules.

Cron Daemon
Reads Crontab
Checks Time
Executes Command

The name "cron" comes from the Greek word chronos, meaning time. It has been a core part of Unix systems since the 1970s, making it one of the most battle-tested tools in the Linux ecosystem. The modern implementation on most Ubuntu systems is provided by the cron package (Vixie cron), which adds features like per-user crontabs and environment variable support.

Understanding Crontab Syntax

The crontab file uses a specific five-field syntax to define when a job should run. Each line in a crontab represents one scheduled job and follows this format:

┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 7, Sun=0 or 7)
│ │ │ │ │
* * * * * command_to_execute
FieldAllowed ValuesSpecial CharactersExample
Minute0-59* , - /30 = at minute 30
Hour0-23* , - /14 = at 2 PM
Day of Month1-31* , - /1 = 1st of month
Month1-12 or JAN-DEC* , - /6 = June
Day of Week0-7 or SUN-SAT* , - /1 = Monday

Special Characters Explained

* (Asterisk)

Matches every possible value. * * * * * means every minute of every hour of every day.

, (Comma)

Specifies a list of values. 1,15 in the day field means the 1st and 15th of the month.

- (Hyphen)

Defines a range. 9-17 in the hour field means every hour from 9 AM to 5 PM.

/ (Slash)

Specifies step values. */5 in the minute field means every 5 minutes.

Working with Crontab

Each user manages their crontab using the crontab command. Here are the essential operations:

# Edit your crontab (opens in default editor)
$ crontab -e

# List your current cron jobs
$ crontab -l

# Remove all your cron jobs (use with caution!)
$ crontab -r

# Edit crontab for another user (requires root)
$ sudo crontab -u www-data -e

# List cron jobs for another user
$ sudo crontab -u www-data -l
Be Careful with crontab -r
The -r flag removes your entire crontab instantly without confirmation. It is dangerously close to -e on the keyboard. Many admins add the EDITOR=nano environment variable and always review their crontab with crontab -l before making changes.

Special Scheduling Strings

Cron provides convenient shortcut strings for common schedules. These are easier to read and less error-prone than the five-field syntax:

StringEquivalentDescription
@rebootRun at startupExecutes once when the system boots
@yearly0 0 1 1 *January 1st at midnight
@monthly0 0 1 * *First day of each month at midnight
@weekly0 0 * * 0Every Sunday at midnight
@daily0 0 * * *Every day at midnight
@hourly0 * * * *At the start of every hour
# Start a Node.js application on boot
@reboot /usr/bin/node /home/app/server.js &

# Run daily database backup at midnight
@daily /home/scripts/backup-db.sh

# Renew SSL certificates monthly
@monthly /usr/bin/certbot renew --quiet

Practical Cron Job Examples

Let us look at real-world cron jobs you will commonly use on a production server. Each example includes the crontab entry and an explanation of when it runs.

Database Backups

# Daily MySQL backup at 2:00 AM
0 2 * * * /usr/bin/mysqldump -u root --all-databases | gzip > /backups/mysql/db_$(date +\%Y\%m\%d).sql.gz

# Daily PostgreSQL backup at 2:30 AM
30 2 * * * /usr/bin/pg_dumpall -U postgres | gzip > /backups/pg/all_$(date +\%Y\%m\%d).sql.gz

# Weekly full backup on Sunday at 3:00 AM
0 3 * * 0 /home/scripts/full-backup.sh >> /var/log/backup.log 2>&1
Note on Percent Signs
In crontab, the % character has special meaning (it creates a newline). You must escape it with a backslash (\%) when using it in commands like date +\%Y\%m\%d. This is one of the most common cron pitfalls and does not apply when running the same command manually in a terminal.

Log Rotation and Cleanup

# Delete log files older than 30 days, every Sunday at 4 AM
0 4 * * 0 /usr/bin/find /var/log/app/ -name "*.log" -mtime +30 -delete

# Compress logs older than 7 days, daily at 3:30 AM
30 3 * * * /usr/bin/find /var/log/app/ -name "*.log" -mtime +7 ! -name "*.gz" -exec gzip {} \;

# Clear /tmp files older than 48 hours, every 6 hours
0 */6 * * * /usr/bin/find /tmp -type f -atime +2 -delete 2>/dev/null

Monitoring and Alerts

# Check disk usage every 15 minutes
*/15 * * * * /home/scripts/check-disk.sh

# Monitor service health every 5 minutes
*/5 * * * * /usr/bin/systemctl is-active --quiet nginx || /usr/bin/systemctl restart nginx

# Send daily server report at 8:00 AM
0 8 * * * /home/scripts/daily-report.sh | mail -s "Server Report" [email protected]

Application Maintenance

# Run Laravel scheduler every minute
* * * * * cd /var/www/myapp && /usr/bin/php artisan schedule:run >> /dev/null 2>&1

# Clear application cache daily at 4 AM
0 4 * * * cd /var/www/myapp && /usr/bin/php artisan cache:clear >> /dev/null 2>&1

# WordPress cron every 15 minutes (disable wp-cron.php)
*/15 * * * * cd /var/www/wordpress && /usr/bin/php wp-cron.php >> /dev/null 2>&1

# Renew SSL certificates twice daily
0 3,15 * * * /usr/bin/certbot renew --quiet --deploy-hook "systemctl reload nginx"

Handling Cron Output

By default, cron sends any output (stdout and stderr) from a job as an email to the user who owns the crontab. On most servers without a local mail transport agent, this means the output simply gets lost. Proper output handling is essential for debugging and auditing.

Redirecting Output to a Log File

# Log both stdout and stderr to a file
0 2 * * * /home/scripts/backup.sh >> /var/log/cron-backup.log 2>&1

# Log stdout and stderr to separate files
0 2 * * * /home/scripts/backup.sh >> /var/log/backup.log 2>> /var/log/backup-error.log

# Discard all output (silent execution)
*/5 * * * * /home/scripts/healthcheck.sh > /dev/null 2>&1

# Keep errors only (discard normal output)
0 3 * * * /home/scripts/cleanup.sh > /dev/null

Using the MAILTO Variable

# Send cron output to a specific email
[email protected]

# Disable email notifications entirely
MAILTO=""

# Send to multiple recipients
[email protected],[email protected]

Debugging Cron Jobs

Cron jobs that work perfectly in a terminal but fail silently when scheduled are one of the most frustrating problems in Linux administration. Here are the most common causes and how to diagnose them.

Problem 1: PATH Issues

Cron runs with a minimal environment. The PATH variable is typically limited to /usr/bin:/bin, which means commands you normally use might not be found.

# BAD: Relies on PATH to find commands
0 2 * * * mysqldump mydb > /backups/db.sql

# GOOD: Use absolute paths for ALL commands
0 2 * * * /usr/bin/mysqldump mydb > /backups/db.sql

# ALTERNATIVE: Set PATH at the top of your crontab
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
0 2 * * * mysqldump mydb > /backups/db.sql
Golden Rule: Always Use Absolute Paths
The number one reason cron jobs fail is missing PATH. Always use the full path to executables. You can find the full path of any command with which command_name or type -a command_name.

Problem 2: Environment Variables

Cron does not load your shell profile (.bashrc, .profile, etc.). Any environment variables your script depends on will not be available.

# Set variables directly in crontab
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
HOME=/root
NODE_ENV=production

# Or source your profile in the command
0 3 * * * . /root/.profile && /home/scripts/deploy.sh

Problem 3: Permission Issues

# Check if the script is executable
$ ls -la /home/scripts/backup.sh
-rw-r--r-- 1 root root 1024 Mar 17 10:00 /home/scripts/backup.sh

# Make it executable
$ chmod +x /home/scripts/backup.sh

# Verify
$ ls -la /home/scripts/backup.sh
-rwxr-xr-x 1 root root 1024 Mar 17 10:00 /home/scripts/backup.sh

Checking the Cron Log

The system cron log records when jobs are started and if there were any errors loading crontabs.

# Ubuntu/Debian — cron logs go to syslog
$ grep CRON /var/log/syslog | tail -20
Mar 17 02:00:01 server CRON[12345]: (root) CMD (/home/scripts/backup.sh)
Mar 17 02:00:01 server CRON[12346]: (www-data) CMD (cd /var/www && php artisan schedule:run)

# Or use journalctl
$ journalctl -u cron --since "1 hour ago"

Environment Variables in Crontab

You can define environment variables at the top of your crontab. These apply to all jobs defined after them.

# A well-configured crontab
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
[email protected]
HOME=/root

# Database backups
0 2 * * * /home/scripts/backup-mysql.sh >> /var/log/cron/mysql-backup.log 2>&1
30 2 * * * /home/scripts/backup-postgres.sh >> /var/log/cron/pg-backup.log 2>&1

# Cleanup
0 4 * * 0 /home/scripts/cleanup-old-backups.sh >> /var/log/cron/cleanup.log 2>&1

# Monitoring
*/5 * * * * /home/scripts/healthcheck.sh > /dev/null 2>&1

System-Wide Cron Directories

In addition to per-user crontabs, Linux provides system-wide cron directories for different schedules:

DirectoryScheduleUsage
/etc/cron.d/Custom scheduleSystem-level cron jobs with user field
/etc/cron.hourly/Every hourDrop executable scripts here
/etc/cron.daily/Once dailyLogrotate, man-db, etc.
/etc/cron.weekly/Once weeklyfstrim, man-db rotation
/etc/cron.monthly/Once monthlyQuota reports, cleanup tasks
Difference Between /etc/cron.d/ and User Crontabs
Files in /etc/cron.d/ follow a slightly different format — they include a user field after the time specification: * * * * * root /path/to/command. Files in the hourly/daily/weekly/monthly directories are simply executable scripts with no special format. The system's anacron or run-parts runs them.

Cron vs Systemd Timers

Modern Linux distributions offer systemd timers as an alternative to cron. While both achieve the same goal, they have different strengths:

FeatureCronSystemd Timers
Ease of setupSimpleModerate
LoggingBasic (syslog)journalctl
DependenciesNoneAfter=, Requires=
Missed job handlingSkippedPersistent=true
Sub-second precisionNo (1 min minimum)Yes
Resource controlNonecgroups, CPU/Memory limits
UniversalityEvery Unix/Linuxsystemd only
Per-user supportBuilt-insystemd --user

For simple scheduled tasks, cron remains the easiest and most portable choice. Systemd timers are better when you need dependency management, persistent scheduling (catching up on missed runs), or fine-grained resource control. Many systems use both side by side.

Cron Security Best Practices

Cron jobs run with the privileges of the user who owns the crontab. This makes security an important consideration, especially for root cron jobs.

  • Use absolute paths for all commands and scripts in crontabs
  • Set restrictive permissions on cron scripts (700 or 750)
  • Never store passwords directly in crontab entries — use config files with restricted permissions
  • Use /etc/cron.allow and /etc/cron.deny to control which users can create cron jobs
  • Log all cron job output to files for auditing
  • Review crontabs regularly: for user in $(cut -f1 -d: /etc/passwd); do crontab -u $user -l 2>/dev/null; done
  • Ensure scripts called by cron cannot be modified by unprivileged users
  • Use lock files to prevent overlapping executions of long-running jobs

Preventing Overlapping Executions

If a cron job takes longer than its interval, multiple instances can run simultaneously, causing resource exhaustion or data corruption. Use flock to prevent this:

# Use flock to ensure only one instance runs at a time
*/5 * * * * /usr/bin/flock -n /tmp/backup.lock /home/scripts/backup.sh

# With a timeout (wait up to 60 seconds for the lock)
*/5 * * * * /usr/bin/flock -w 60 /tmp/import.lock /home/scripts/import.sh

Quick Reference: Common Schedules

ScheduleCrontab ExpressionDescription
Every minute* * * * *Runs 1,440 times per day
Every 5 minutes*/5 * * * *Runs 288 times per day
Every 15 minutes*/15 * * * *Runs 96 times per day
Every hour0 * * * *At the start of each hour
Every 6 hours0 */6 * * *At 00:00, 06:00, 12:00, 18:00
Twice daily0 3,15 * * *At 3:00 AM and 3:00 PM
Daily at 2 AM0 2 * * *Once per day
Weekdays at 9 AM0 9 * * 1-5Monday through Friday
Weekends at noon0 12 * * 6,0Saturday and Sunday
First day of month0 0 1 * *Midnight on the 1st
Every quarter0 0 1 1,4,7,10 *Jan 1, Apr 1, Jul 1, Oct 1
Last day of month0 0 28-31 * * [ $(date +\%d -d tomorrow) -eq 1 ] &&Requires conditional check

Visual Cron Management with Panelica

While the command line gives you full control over cron jobs, managing them across multiple users on a shared server can become complex. Panelica includes a built-in cron job manager that provides a visual interface for creating and managing scheduled tasks.

Visual
Point-and-click schedule builder with preset patterns
Per-User
Each user manages their own cron jobs securely

With Panelica, you can create, edit, pause, and delete cron jobs through a web interface. Each user sees only their own jobs (enforced by RBAC), and administrators can manage jobs for any user. The visual scheduler eliminates syntax errors and provides human-readable descriptions of each schedule. Jobs can be paused without deleting them, and execution logs are available directly in the panel.

Key Takeaway
Cron is one of the most fundamental tools in a Linux administrator's toolkit. Master the five-field syntax, always use absolute paths, handle output properly, and use flock to prevent overlapping executions. Whether you manage cron through the command line or a visual interface, the ability to automate recurring tasks is what separates efficient server administration from constant manual intervention.
Share: