How to Set Up Cron Jobs on Linux (crontab Guide)
Complete guide to setting up cron jobs on Linux using crontab. Covers cron syntax, environment variables, logging, system vs user crontab, and debugging.
Prerequisites
- Linux server (Ubuntu, Debian, CentOS, etc.)
- Terminal access
- A text editor (nano, vim)
In this guide
What Is Cron?
Cron is the standard job scheduler on Unix-like systems. The cron daemon (crond) runs in the background and checks every minute for tasks to execute. Tasks are defined in crontab (cron table) files.
Every Linux distribution includes cron by default. It's the foundation that most other scheduling tools build on.
Quick Start: crontab -e
Edit your crontab:
crontab -eThis opens your user's crontab in the default editor. Add a line:
*/5 * * * * echo "Hello from cron" >> /tmp/cron.log 2>&1Save and exit. Your job is now scheduled.
List your crontab:
crontab -lRemove your crontab (all jobs):
crontab -rCron Expression Syntax
A cron expression has 5 fields:
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-7, 0 and 7 = Sunday)
│ │ │ │ │
* * * * * commandSpecial characters:
*— any value,— list:1,3,5-— range:1-5/— step:*/5(every 5)
Examples:
*/5 * * * *— Every 5 minutes0 9 * * 1-5— Weekdays at 9 AM0 0 1,15 * *— 1st and 15th of each month at midnight
Special Strings
Most cron implementations support shorthand strings:
@reboot— Run once at startup@hourly— Same as0 * * * *@daily(or@midnight) — Same as0 0 * * *@weekly— Same as0 0 * * 0@monthly— Same as0 0 1 * *@yearly(or@annually) — Same as0 0 1 1 *
@reboot /opt/myapp/start.sh
@daily /opt/myapp/backup.shCommon Cron Expressions
* * * * *— Every minute*/5 * * * *— Every 5 minutes*/15 * * * *— Every 15 minutes0 * * * *— Every hour0 0 * * *— Daily at midnight0 9 * * *— Daily at 9 AM0 9 * * 1-5— Weekdays at 9 AM0 0 * * 0— Every Sunday at midnight0 0 1 * *— First day of every month0 0 1 1 *— January 1st at midnight
Every weekday at 9:00 AM
Next runs (UTC):
Mon, May 18, 2026 09:00
Tue, May 19, 2026 09:00
Wed, May 20, 2026 09:00
System Crontab vs User Crontab
User crontab (crontab -e):
- Per-user schedule
- Stored in
/var/spool/cron/crontabs/ - Commands run as that user
- No user field in the entry
System crontab (/etc/crontab):
- System-wide schedule
- Includes a user field between the time and command
- Requires root to edit
# /etc/crontab format (note the user field)
*/5 * * * * root /opt/scripts/cleanup.sh
0 2 * * * backup /opt/scripts/backup.shCron directories:
/etc/cron.d/— Drop-in cron files (system crontab format)/etc/cron.hourly/— Scripts run every hour/etc/cron.daily/— Scripts run daily/etc/cron.weekly/— Scripts run weekly/etc/cron.monthly/— Scripts run monthly
Environment Variables
Cron runs with a minimal environment — your .bashrc, .profile, and PATH are NOT loaded. This is the #1 cause of "works in terminal but not in cron" issues.
Set variables in your crontab:
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=admin@example.com
SHELL=/bin/bash
*/5 * * * * /opt/myapp/task.shOr source your profile in the command:
*/5 * * * * . $HOME/.profile; /opt/myapp/task.shMAILTO: Set this to receive email notifications of cron output. Set MAILTO="" to suppress emails.
Output & Logging
By default, cron emails any output to the user. For better logging:
Redirect to a log file:
*/5 * * * * /opt/myapp/task.sh >> /var/log/myapp-cron.log 2>&1>>appends stdout to the file2>&1redirects stderr to stdout
Discard output:
*/5 * * * * /opt/myapp/task.sh > /dev/null 2>&1Log with timestamps:
*/5 * * * * /opt/myapp/task.sh 2>&1 | while read line; do echo "$(date '+\%Y-\%m-\%d \%H:\%M:\%S') $line"; done >> /var/log/cron.logCheck cron's own log:
grep CRON /var/log/syslog # Ubuntu/Debian
journalctl -u cron # systemd
grep cron /var/log/cron # CentOS/RHELDebugging: "Why Is My Cron Job Not Running?"
Checklist for debugging:
1. Is cron running?
systemctl status cron # or crond on CentOS2. Is the crontab installed?
crontab -l3. Is the PATH correct?
Use full paths to all binaries: /usr/bin/python3 not just python3
4. Are permissions correct?
Scripts must be executable: chmod +x /opt/myapp/task.sh
5. Check cron logs:
grep CRON /var/log/syslog | tail -206. Check for errors by redirecting output:
*/5 * * * * /opt/myapp/task.sh >> /tmp/cron-debug.log 2>&17. Is the user allowed to use cron?
Check /etc/cron.allow and /etc/cron.deny.
Production Tips
Lock files to prevent overlapping:
*/5 * * * * flock -n /tmp/myapp.lock /opt/myapp/task.shflock -n exits immediately if the lock is held, preventing overlapping runs.
Timeouts:
0 2 * * * timeout 3600 /opt/myapp/backup.shKills the job after 1 hour if it's still running.
Monitoring: Ping a health check service on success:
0 * * * * /opt/myapp/task.sh && curl -s https://hc-ping.com/uuid > /dev/nullCentralized logging: Use logger to send output to syslog:
*/5 * * * * /opt/myapp/task.sh 2>&1 | logger -t myapp-cron