What Cron Is and Why It Matters for Server Administration
If you manage a Linux server, you have almost certainly encountered situations where a task needs to run automatically on a schedule. Perhaps you need daily database backups, weekly log rotations, hourly data synchronisation, or monthly report generation. Running these manually is error-prone, inconsistent, and time-consuming. Cron solves this problem by letting you define scheduled tasks that run automatically without any manual intervention.
Cron is a time-based job scheduler built into Unix and Linux systems. It runs predefined commands or scripts at specified times or intervals, letting you automate repetitive server maintenance tasks reliably. Whether you are running a small VPS or managing multiple production servers, understanding cron is a fundamental skill for anyone responsible for server administration.
Automated tasks that run on schedule are more consistent than manual processes. Manual tasks get skipped when work is busy or forgotten when the administrator is unavailable. A backup script that runs every night at 3am will never be missed because someone went on holiday, whereas a manual backup process often falls by the wayside under pressure.
How Cron Works: The Cron Daemon
Cron operates as a background daemon called cron or crond. This daemon runs continuously, checking the system crontab files and the /etc/cron.d/ directory every minute. When the current time matches a scheduled job's time specification, cron executes the associated command or script.
The daemon starts automatically on most Linux distributions through the system service manager. You can verify that cron is running with:
systemctl status cron
If cron is not running for any reason, start and enable it with:
sudo systemctl start cron
sudo systemctl enable cron
The Crontab Format: How Scheduled Tasks Are Defined
Cron tasks are defined in a crontab, which stands for "cron table". Each user on a Linux system can have their own crontab file containing their scheduled tasks. The system also maintains a set of scheduled tasks in /etc/cron.d/ and the standard directories such as /etc/cron.daily/, /etc/cron.hourly/, /etc/cron.weekly/, and /etc/cron.monthly/.
To edit your own crontab, run:
crontab -e
This opens your crontab file in your default text editor. The first time you run this command, you may be prompted to select an editor. Choose nano or vim based on your preference.
Each line in a crontab follows this format:
* * * * * /path/to/command
The line consists of five time fields followed by the command to execute. The five stars represent, in order: minute, hour, day of month, month, and day of week.
Understanding Cron Schedule Syntax
The cron schedule syntax can seem confusing at first, but it follows a logical pattern once you understand each field.
Field Values and Operators
A specific value such as 30 means "at minute 30" or "on the 30th day". An asterisk * means "every" possible value for that field. A range such as 1-5 means "every value from 1 through 5". A step value such as */15 means "every 15 units".
Common Schedule Examples
* * * * * Every minute
30 * * * * Every hour, at minute 30
0 * * * * Every hour, at minute 0 (the start of each hour)
0 0 * * * Every day at midnight
30 2 * * * Every day at 02:30
0 3 * * 1 Every Monday at 03:00
0 0 1 * * First day of every month at midnight
0 0 * * 0 Every Sunday at midnight
*/15 * * * * Every 15 minutes
0 */2 * * * Every 2 hours
30 4 * * 1-5 Weekdays at 04:30
0 0 * * 1,3,5 Monday, Wednesday, and Friday at midnight
The day-of-week field uses 0 and 7 both representing Sunday, with 1 through 6 representing Monday through Saturday respectively.
If you are building automation scripts as part of your bash scripting workflow, scheduling those scripts with cron is a natural next step for recurring automation tasks.
Running Commands at Specific Times
Here are practical examples of scheduling common server administration tasks.
Daily Backup Script
Run a backup script every day at 3am:
0 3 * * * /usr/local/bin/backup.sh
Weekly Log Rotation
Run a log rotation script every Sunday at 2am:
0 2 * * 0 /usr/local/bin/rotate-logs.sh
PHP Script Execution
Run a PHP script every 15 minutes:
*/15 * * * * /usr/bin/php /var/www/html/yourdomain.co.uk/cron.php
Environment Variables and PATH Issues
Cron does not load your interactive shell environment. This is one of the most common reasons scripts work manually but fail under cron. Variables like PATH, HOME, and custom environment settings may not be available or may have different values than you expect.
Always use absolute paths in cron commands to avoid issues. Instead of relying on system PATH lookups, specify the full path to commands and scripts. Alternatively, you can set the PATH variable at the top of your crontab:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
0 3 * * * /usr/local/bin/backup.sh
When developing scripts that will run under cron, test them in a simulated cron environment first. The env -i command clears all environment variables, giving you a clean slate similar to what cron provides:
env -i HOME=$HOME PATH=$PATH /usr/local/bin/myscript.sh
If your script works in your normal shell session but fails with this command, it likely depends on environment variables that are not available in the cron environment. Update the script to explicitly set required variables or use absolute paths throughout.
Handling Command Output and Logging
By default, cron sends any output from commands to the local mail system. If a cron job produces output that you want to review for debugging purposes, you receive it as a local system user. Check your local mail with:
mail
For most server administration tasks, you will want to redirect output to a log file instead. This approach makes it easier to review historical output and monitor job execution over time:
0 3 * * * /usr/local/bin/backup.sh >> /var/log/cron-backup.log 2>&1
The >> operator appends standard output to the log file rather than overwriting it. The 2>&1 construction redirects standard error to the same destination as standard output, so both normal output and error messages go into the same log file. Without this redirection, cron sends any output to the local mail spool, where it may accumulate unread and cause disk space issues over time.
Disabling Email Notifications
If a cron job does not produce meaningful output, or if you are already logging everything to a file, you can suppress the email notification entirely:
0 3 * * * /usr/local/bin/backup.sh > /dev/null 2>&1
Alternatively, set the MAILTO variable at the top of your crontab:
MAILTO=""
0 3 * * * /usr/local/bin/backup.sh
An empty MAILTO value disables email notification for all cron jobs in that particular crontab file.
System Cron Directories
On Ubuntu, Debian, and many other Linux distributions, scripts in the system cron directories run automatically at scheduled intervals without requiring any crontab configuration:
/etc/cron.hourly/ runs every hour
/etc/cron.daily/ runs every day
/etc/cron.weekly/ runs once per week
/etc/cron.monthly/ runs once per month
Scripts placed in these directories are executed by the run-parts command, which runs executable files found in the directory. To use this approach, place your script in the appropriate directory, ensure it is executable, and give it a proper shebang line at the top such as #!/bin/bash or #!/bin/sh.
The anacron package, installed by default on Ubuntu desktop installations and common on many server setups, ensures that cron.daily tasks run even if the server was powered off at the scheduled time. When the server starts up after a missed daily run, anacron executes the task. On servers that run continuously without downtime, this behaviour is less relevant, but anacron still provides useful consistency guarantees.
Common Cron Mistakes That Cause Silent Failures
One of the most frustrating aspects of cron is that failed jobs often fail silently. Unlike a task run manually in your terminal, a failed cron job does not display errors on your screen. Understanding common mistakes helps you avoid them.
Environment Differences
As mentioned earlier, the most common cron problem is environment differences. A script that works perfectly when run manually but fails under cron is almost always due to a missing environment variable, a different working directory, or missing PATH entries. Always test scripts with a simulated cron environment before relying on them in production.
Relative Paths
Another common mistake is using relative paths for input or output files. If your script references data/input.csv, it will fail under cron unless the script changes to the correct directory first or uses an absolute path throughout. This issue often surfaces as a file not found error in your cron logs.
Missing Shebang Line
Scripts placed in system cron directories must have a proper shebang line as the first line. Without it, the system does not know which interpreter to use to run the script. Always include #!/bin/bash or #!/usr/bin/env bash at the top of shell scripts.
Permissions Issues
The script file must be executable. Use chmod +x /path/to/script.sh to add execute permissions. Additionally, the user whose crontab the job runs in must have read access to the script and execute permissions on it.
Verifying Cron Job Execution
When troubleshooting cron issues, check several places to understand what happened.
Checking System Logs
Cron logs its activity to /var/log/syslog on Ubuntu and Debian systems. Filter for cron entries to see what jobs have executed:
grep CRON /var/log/syslog | tail -20
This shows the last 20 cron executions. If a job is not listed at the expected time, investigate the crontab entry syntax, whether cron is running, and whether the script exists and is executable.
Confirming Cron Status
Verify the cron daemon is running:
systemctl status cron
If cron is not running, start it as shown earlier in this article. On some systems, you may need to use crond instead of cron as the service name.
A Practical Example: Automated Database Backup
Automated database backups are one of the most common uses for cron on web servers. Here is a practical example of a daily MySQL backup using cron:
0 3 * * * mysqldump -u root -p'mypassword' mydatabase | gzip > /backups/mydatabase_$(date +\%Y\%m\%d).sql.gz 2>> /var/log/backup-errors.log
Breaking this down: mysqldump outputs the database, | gzip compresses the output, > writes to a file with the date embedded by $(date +\%Y\%m\%d). The backslashes before the percent signs are necessary because cron interprets percent signs specially, converting them to newlines in the command. Error messages are appended to a separate log file using 2>>.
For more complex backup operations, create a separate backup script file rather than putting complex commands directly in the crontab. A script file is easier to test independently, easier to read and maintain, and can be run manually without reconstructing the full command each time.
If you are building automation workflows for your business, understanding how to schedule these tasks reliably can reduce administrative overhead significantly. Many small businesses find that automating routine server tasks reduces the time spent on manual administration and helps prevent important tasks from being forgotten.
Restricting Cron Access
On shared systems or servers where you need to control which users can schedule cron jobs, use the /etc/cron.deny and /etc/cron.allow files. These files let you grant or restrict cron access at the user level.
If /etc/cron.allow exists, only users listed in that file can use cron. All other users are denied. If only /etc/cron.deny exists, users listed in it are blocked while all others can use cron. The root user can always use cron regardless of these files.
sudo echo "deploy" >> /etc/cron.allow
sudo echo "backup-user" >> /etc/cron.deny
On production servers, it is good practice to restrict cron access to specific service accounts rather than allowing all system users to schedule jobs. This follows the principle of least privilege and reduces the potential impact of a compromised account.
When Cron Might Not Be the Best Solution
Cron is excellent for simple time-based scheduling, but it has limitations. For more complex scheduling needs, consider alternatives.
If you need second-level precision or event-driven scheduling rather than minute-level intervals, a task queue system like Celery with Redis or RabbitMQ may be more appropriate. For containerised environments, Kubernetes CronJobs provide better integration with container orchestration.
If you need to monitor cron job health, receive alerts on failures, or manage dependencies between tasks, consider a workflow automation tool. These systems provide better visibility into job status and often include retry logic, alerting, and dependency management that cron lacks natively.
For businesses evaluating ongoing costs of manual versus automated processes, understanding the limitations of basic scheduling tools helps make informed decisions about where to invest in more sophisticated automation.
Getting Started with Your Own Cron Jobs
Cron is a powerful tool that every Linux server administrator should understand. Start with simple scheduled tasks like daily log rotation or weekly cleanup scripts. Test your scripts in a simulated cron environment before relying on them, and always ensure output goes somewhere useful rather than disappearing silently.
Whether you are managing a single VPS or multiple servers, automating routine tasks with cron frees up time for more valuable work while ensuring critical maintenance happens consistently. If you need help setting up automated tasks for your server or want a review of your existing cron configuration, you can get in touch with details of your current setup and what you want to automate.