Configure Linux cron jobs and system task scheduling with best practices

Beginner 25 min Apr 03, 2026 18 views
Ubuntu 24.04 Ubuntu 22.04 Debian 12 AlmaLinux 9 Rocky Linux 9 Fedora 41

Learn to configure cron jobs and systemd timers for automated task scheduling on Linux systems with proper logging, security, and troubleshooting techniques.

Prerequisites

  • Root or sudo access
  • Basic command line knowledge
  • Text editor (nano/vim)

What this solves

Cron jobs automate repetitive system tasks like backups, log rotation, system maintenance, and application updates. This tutorial shows you how to configure user and system cron jobs, understand cron syntax, implement proper logging and security, and use modern systemd timers as an alternative scheduling solution.

Understanding cron and crontab syntax

Cron uses a specific time format with five fields representing minute, hour, day of month, month, and day of week. Each field accepts numbers, ranges, lists, and special characters for flexible scheduling.

Note: The cron format is: minute (0-59) hour (0-23) day (1-31) month (1-12) weekday (0-7, where 0 and 7 are Sunday).

Here are common cron syntax examples:

ScheduleCron ExpressionDescription
Every minute *Runs every minute of every day
Daily at 3 AM0 3 *Runs at 03:00 every day
Weekly on Sunday0 2 0Runs at 02:00 every Sunday
Monthly on 1st0 0 1 Runs at midnight on the 1st of each month
Every 15 minutes/15 *Runs every 15 minutes
Weekdays at 9 AM0 9 1-5Runs at 09:00 Monday through Friday

Special strings can replace the five-field format:

  • @reboot - Run once at startup
  • @yearly or @annually - Run once a year (0 0 1 1 *)
  • @monthly - Run once a month (0 0 1 )
  • @weekly - Run once a week (0 0 0)
  • @daily or @midnight - Run once a day (0 0 *)
  • @hourly - Run once an hour (0 )

Step-by-step configuration

Verify cron service is running

First, ensure the cron daemon is installed and running on your system.

sudo systemctl status cron
sudo systemctl enable --now cron
sudo systemctl status crond
sudo systemctl enable --now crond

Create your first user cron job

Use crontab -e to edit your personal cron table. This opens your default editor with your current cron jobs.

crontab -e

Add a simple backup job that runs daily at 2 AM:

# Daily backup at 2 AM
0 2   * /usr/bin/rsync -av /home/user/documents/ /backup/documents/ >> /var/log/backup.log 2>&1

System update check every Sunday at 1 AM

0 1 0 /usr/bin/apt list --upgradable >> /var/log/updates.log 2>&1

Disk usage report every Monday at 8 AM

0 8 1 /usr/bin/df -h | /usr/bin/mail -s "Disk Usage Report" admin@example.com

Set up proper environment variables

Cron jobs run with a minimal environment. Set necessary variables at the top of your crontab to ensure commands find required paths and configurations.

SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=admin@example.com
HOME=/home/user

Your cron jobs go below these environment settings

0 2 * /home/user/scripts/backup.sh /30 * /usr/local/bin/monitor_disk.py

Create system-wide cron jobs

System cron jobs go in /etc/crontab or /etc/cron.d/ directory. These require specifying the user account to run as.

sudo nano /etc/cron.d/system-maintenance
# System maintenance cron jobs
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=root

Clean temporary files daily at 3 AM as root

0 3 * root /usr/bin/find /tmp -type f -atime +7 -delete

Rotate logs weekly on Sunday at 4 AM as root

0 4 0 root /usr/sbin/logrotate /etc/logrotate.conf

Update package database daily at 5 AM as root

0 5 * root /usr/bin/apt update > /var/log/apt-update.log 2>&1

Use predefined cron directories

Linux provides convenient directories for common schedules. Place executable scripts in these directories instead of managing crontab entries.

ls -la /etc/cron.hourly/
ls -la /etc/cron.daily/
ls -la /etc/cron.weekly/
ls -la /etc/cron.monthly/

Create a daily system cleanup script:

sudo nano /etc/cron.daily/cleanup
#!/bin/bash

Daily system cleanup script

Clean package cache

apt-get clean

Remove old kernels (keep 2 latest)

apt-get autoremove -y

Clean journal logs older than 30 days

journalctl --vacuum-time=30d

Update locate database

updatedb echo "$(date): System cleanup completed" >> /var/log/cleanup.log

Make the script executable:

sudo chmod 755 /etc/cron.daily/cleanup

Configure logging and monitoring

Set up comprehensive logging to track cron job execution and troubleshoot issues effectively.

sudo nano /etc/rsyslog.d/50-cron.conf
# Enable cron logging
cron.*    /var/log/cron.log
sudo systemctl restart rsyslog
sudo systemctl restart cron
sudo nano /etc/rsyslog.conf

Uncomment or add this line:

cron.*    /var/log/cron
sudo systemctl restart rsyslog
sudo systemctl restart crond

Implement cron job security practices

Control who can use cron and secure cron job execution with proper file permissions and access controls.

sudo nano /etc/cron.allow
root
user1
backup
monitoring

Set proper permissions on cron files:

sudo chmod 600 /etc/cron.allow
sudo chmod 600 /etc/crontab
sudo chmod 700 /etc/cron.d/
sudo chmod 700 /var/spool/cron/
Never use chmod 777. Cron files contain sensitive scheduling information and should only be readable by root and authorized users. Incorrect permissions can allow unauthorized access to modify system tasks.

Configure systemd timers as cron alternative

Create a systemd service unit

Systemd timers provide more advanced scheduling options and better logging than traditional cron. Start by creating a service unit for your task.

sudo nano /etc/systemd/system/backup.service
[Unit]
Description=Daily backup service
Wants=backup.timer

[Service]
Type=oneshot
User=backup
ExecStart=/usr/local/bin/backup-script.sh
StandardOutput=journal
StandardError=journal

Create the corresponding timer unit

The timer unit defines when and how often the service runs, with more flexible options than cron syntax.

sudo nano /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily
Requires=backup.service

[Timer]
OnCalendar=daily
Persistent=true
RandomizedDelaySec=1800

[Install]
WantedBy=timers.target

Enable and start the timer:

sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
sudo systemctl status backup.timer

Advanced systemd timer scheduling

Systemd timers support complex scheduling patterns and multiple trigger conditions.

sudo nano /etc/systemd/system/monitoring.timer
[Unit]
Description=System monitoring every 15 minutes
Requires=monitoring.service

[Timer]

Run every 15 minutes

OnCalendar=*:0/15

Run 2 minutes after boot

OnBootSec=2min

Catch up missed runs

Persistent=true

Spread load randomly within 30 seconds

RandomizedDelaySec=30

Prevent overlapping runs

OnUnitActiveSec=15min [Install] WantedBy=timers.target

Verify your setup

Test your cron jobs and systemd timers to ensure they work correctly and troubleshoot any issues.

# List current user cron jobs
crontab -l

List all system cron jobs

sudo cat /etc/crontab ls -la /etc/cron.d/

Check cron service status

sudo systemctl status cron # Ubuntu/Debian sudo systemctl status crond # RHEL/CentOS

View cron logs

sudo tail -f /var/log/cron.log # Ubuntu/Debian sudo tail -f /var/log/cron # RHEL/CentOS

List active systemd timers

sudo systemctl list-timers

Check specific timer status

sudo systemctl status backup.timer

View timer logs

sudo journalctl -u backup.timer -u backup.service

Test cron job execution

Create a simple test job to verify cron is working properly.

crontab -e

Add a test job that runs every minute:

# Test cron job - remove after testing
    * echo "$(date): Cron test successful" >> /tmp/crontest.log

Wait a few minutes, then check the output:

cat /tmp/crontest.log

Remove the test job after verification:

crontab -e

Delete the test line and save

Common issues

SymptomCauseFix
Cron job doesn't runCron service not runningsudo systemctl enable --now cron (or crond)
Script not foundMissing PATH in cron environmentUse full paths to commands or set PATH in crontab
Permission deniedIncorrect script permissionschmod 755 script.sh and check ownership
No email notificationsMail system not configuredInstall mailutils: sudo apt install mailutils
Environment variables missingCron runs with minimal environmentSet variables at top of crontab or source .bashrc
Job runs but fails silentlyNo output redirectionAdd >> /var/log/jobname.log 2>&1 to capture output
Systemd timer not startingService unit missing or invalidsystemctl status unit.service to check service
Timer shows inactiveTimer not enabledsudo systemctl enable --now timer.timer

Security considerations and best practices

Follow these security practices when implementing automated tasks:

  • Use dedicated service accounts: Create specific users for different types of jobs instead of running everything as root
  • Implement log rotation: Configure log rotation to prevent cron logs from filling disk space
  • Set resource limits: Use systemd or ulimit to prevent runaway processes from consuming system resources
  • Validate input: Always sanitize input and validate file paths in your scheduled scripts
  • Monitor execution: Set up system monitoring to track job success and failure rates
  • Use file locking: Implement flock or similar mechanisms to prevent overlapping job execution
  • Secure script storage: Store scripts in protected directories with appropriate permissions (755 for directories, 644 for scripts)
Note: For backup automation specifically, consider using systemd timers with rsync for more reliable and monitorable backup processes.

Next steps

Automated install script

Run this to automate the entire setup

#cron #crontab #scheduling #automation #systemd-timers

Need help?

Don't want to manage this yourself?

We handle infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.

Talk to an engineer