Report this

What is the reason for this report?

How To Use Cron To Automate Recurring Tasks on Ubuntu

Updated on June 16, 2026
Shaun LewisMark DrakeVinayak Baranwal

By Shaun Lewis, Mark Drake and Vinayak Baranwal

English

Not using Ubuntu 18.04?
Choose a different version or distribution.
Ubuntu 18.04
How To Use Cron To Automate Recurring Tasks on Ubuntu

Introduction

Cron is a time-based job scheduler built into Ubuntu and other Unix-like systems. You use it to run commands and scripts automatically on a fixed schedule, which makes it the standard tool for backups, log rotation, cleanup jobs, and other recurring maintenance tasks. Cron has been part of Unix since Version 7 (1979) and remains the default scheduler on Ubuntu server installations.

In this guide, you will install and verify cron, read and write crontab expressions, set the environment variables that cron jobs depend on, schedule several real-world jobs, inspect cron logs to debug silent failures, and decide when a systemd timer is the better tool. The commands and file paths in this tutorial are verified against Ubuntu 22.04 and Ubuntu 24.04.

Key Takeaways

  • Cron is the default time-based job scheduler on Ubuntu; manage per-user jobs with the crontab command, not by editing files directly.
  • A cron expression has five time fields (minute, hour, day of month, month, day of week) followed by the command to run.
  • Edit jobs with crontab -e, list them with crontab -l, and remove them with crontab -r.
  • Cron runs jobs in a minimal environment, so use absolute paths and set PATH, SHELL, and MAILTO inside the crontab when needed.
  • Inspect cron activity with journalctl -u cron; most “job not running” issues trace back to relative paths, missing permissions, or environment differences.
  • Use cron for simple recurring schedules; reach for systemd timers when you need dependency ordering, missed-run handling, or per-job logging and resource limits.

Quick Start: Schedule Your First Cron Job

  1. Confirm cron is running: systemctl status cron.
  2. Open your crontab for editing: crontab -e.
  3. Add a job using the five-field schedule followed by the command, for example */5 * * * * /usr/local/bin/myscript.sh.
  4. Use absolute paths for every command and file the job references.
  5. Save and exit the editor (CTRL + X, then Y, then ENTER in nano). Cron loads the new schedule automatically.
  6. Verify the job is registered with crontab -l, and check that it ran with journalctl -u cron --since today.

Prerequisites

To follow this guide, you will need:

  • A machine running Ubuntu 22.04 or Ubuntu 24.04. This can be your local machine, a virtual machine, or a DigitalOcean Droplet.
  • A non-root user with sudo privileges. To set this up, follow the Initial Server Setup guide.
  • Basic familiarity with the Linux command line and a text editor such as nano.

Installing Cron

On most Ubuntu installations, cron is already present. To install or confirm it is installed, update the local package index first:

  1. sudo apt update

Then install cron with the following command:

  1. sudo apt install cron

Make sure the daemon is enabled at boot and running now:

  1. sudo systemctl enable --now cron
Synchronizing state of cron.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install enable cron

Confirm the service is active:

  1. systemctl is-active cron
active

Understanding How Cron Works

The Cron Daemon

Cron runs as a background service (cron.service) that wakes up every minute, reads the active crontab files, and runs any job whose schedule matches the current time. Because it runs as a service, you can inspect it with systemctl status cron and read its activity through journald, as covered in the Viewing and Debugging Cron Logs on Ubuntu section below.

The Crontab File

Cron jobs are recorded in a file called a crontab. Each user profile has its own crontab, stored under /var/spool/cron/crontabs/. These files are not meant to be edited directly. Instead, manage them with the crontab command, which validates your syntax and reloads the schedule for you.

System-Wide Cron Directories

Beyond per-user crontabs, Ubuntu ships a set of system-wide locations that run jobs as root:

Directory Default schedule
/etc/cron.hourly/ Once per hour
/etc/cron.daily/ Once per day
/etc/cron.weekly/ Once per week
/etc/cron.monthly/ Once per month
/etc/cron.d/ Custom schedules; file format mirrors /etc/crontab

Scripts placed in the cron.* drop-in directories must be executable and must not have a file extension. The /etc/cron.d/ directory accepts files in full crontab format, including a username field:

# /etc/cron.d/example-job
# Format: minute hour day month weekday username command
0 2 * * * root /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

Use the drop-in directories for packaged or system-level maintenance scripts. Use per-user crontabs for application-level scheduling.

Cron Syntax Reference

The Five Time Fields

A cron expression is five schedule fields followed by the command to run:

Field Allowed Values Special Characters
Minute 0-59 * , - /
Hour 0-23 * , - /
Day of Month 1-31 * , - /
Month 1-12 or JAN-DEC * , - /
Day of Week 0-7 or SUN-SAT (0 and 7 both equal Sunday) * , - /

Together, a scheduled task is structured like this:

minute hour day_of_month month day_of_week command_to_run

The following expression runs curl https://www.example.com every Tuesday at 5:30 PM:

30 17 * * 2 curl https://www.example.com

There are also special characters you can include in the schedule component to streamline scheduling:

  • *: A wildcard representing “all.” A task scheduled with * * * * * ... runs every minute of every hour of every day.
  • ,: Breaks up values into a list. To run a task at the beginning and middle of every hour: 0,30 * * * * ....
  • -: Represents a range. To run a command for the first 30 minutes of every hour: 0-29 * * * * ....
  • /: Used with * to express a step value. To run a command every three hours: 0 */3 * * * ....

Note: Cron accepts any integer step value, but only steps that divide evenly into the field’s range produce a consistent interval. In the “hours” field the evenly dividing steps are 1, 2, 3, 4, 6, 8, and 12. A value like */5 is valid syntax but resets at midnight, leaving an uneven gap between the last run of one day and the first of the next.

Reading and Writing Crontab Expressions

Common schedule examples:

  • * * * * *: Run every minute.
  • 12 * * * *: Run 12 minutes after every hour.
  • 0,15,30,45 * * * *: Run every 15 minutes.
  • */15 * * * *: Run every 15 minutes (step syntax).
  • 0 4 * * *: Run every day at 4:00 AM.
  • 0 4 * * 2-4: Run every Tuesday, Wednesday, and Thursday at 4:00 AM.
  • 20,40 */8 * 7-12 *: Run at minutes 20 and 40 of every 8th hour, during the last 6 months of the year.

If you find any of this confusing, Cronitor provides a cron schedule expression editor named Crontab Guru that validates your expressions interactively.

Special Cron Strings

Cron supports shorthand strings in place of a numeric schedule. These are supported by the version of cron shipped with Ubuntu 22.04 and 24.04:

String Equivalent Expression Description
@reboot (none) Run once at daemon startup after system boot
@hourly 0 * * * * Run at the start of every hour
@daily 0 0 * * * Run at midnight every day
@weekly 0 0 * * 0 Run at midnight every Sunday
@monthly 0 0 1 * * Run at midnight on the first day of each month
@yearly 0 0 1 1 * Run at midnight on January 1st

The @reboot string runs its command once immediately after the cron daemon starts following a reboot. It is useful for starting user-level services or initialization scripts:

@reboot /home/sammy/scripts/init.sh >> /home/sammy/logs/init.log 2>&1

Note: Not all cron daemons can parse shorthand strings (particularly older versions). Confirm they work on your target system before relying on them in production. For startup jobs with strict ordering requirements, a systemd service unit is more reliable than @reboot.

Managing Your Crontab File

Use the crontab command to manage your scheduled jobs. It edits the crontab file for your user profile, validates syntax before saving, and reloads the schedule automatically. Do not edit the file under /var/spool/cron/crontabs/ directly. That path bypasses validation and can corrupt the crontab.

Opening the Crontab Editor

You can edit your crontab with the following command:

  1. crontab -e

If this is the first time you’re running the crontab command under this user profile, it will prompt you to select a default text editor to use when editing your crontab:

no crontab for sammy - using an empty one

Select an editor.  To change later, run 'select-editor'.
  1. /bin/nano        <---- easiest
  2. /usr/bin/vim.basic
  3. /usr/bin/vim.tiny
  4. /bin/ed

Choose 1-4 [1]: 

Enter the number corresponding to the editor of your choice. Alternatively, you could press ENTER to accept the default choice, nano.

After making your selection, you’ll be taken to a new crontab containing some commented-out instructions on how to use it:

# Edit this file to introduce tasks to be run by cron.
# 
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
# 
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').
# 
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
# 
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
# 
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
# 
# For more information see the manual pages of crontab(5) and cron(8)
# 
# m h  dom mon dow   command

When you run crontab -e in the future, it will bring up your crontab in this text editor automatically. Once in the editor, you can input your schedule with each job on a new line. Otherwise, you can save and close the crontab for now (CTRL + X, Y, then ENTER if you selected nano).

Note: On Linux systems, there is another crontab stored under the /etc/ directory. This is a system-wide crontab that has an additional field for which user profile each cron job should be run under. This tutorial focuses on user-specific crontabs, but if you wanted to edit the system-wide crontab, you could do so with the following command:

  1. sudo nano /etc/crontab

Listing Current Cron Jobs

If you’d like to view the contents of your crontab, but not edit it, you can use the following command:

  1. crontab -l

To list cron jobs for a different user (requires sudo):

  1. sudo crontab -u username -l

Removing the Crontab

You can erase your crontab with the following command:

Warning: The following command will not ask you to confirm that you want to erase your crontab. Only run it if you are certain that you want to erase it.

  1. crontab -r

This command will delete the user’s crontab immediately. However, you can include the -i flag to have the command prompt you to confirm that you actually want to delete the user’s crontab:

  1. crontab -r -i
crontab: really delete sammy's crontab? (y/n)

When prompted, you must enter y to delete the crontab or n to cancel the deletion.

Editing Another User’s Crontab

Note that if a user has sudo privileges, they can edit another user’s crontab with the following command:

  1. sudo crontab -u user -e

However, if cron.deny exists and user is listed in it and they aren’t listed in cron.allow, you’ll receive the following error after running the previous command:

The user user cannot use this program (crontab)

Setting Environment Variables in Cron

Why Cron Runs in a Minimal Environment

Cron jobs do not inherit your interactive shell environment. They run with a minimal set of variables: typically SHELL=/bin/sh, a short PATH such as /usr/bin:/bin, and a HOME set to the job owner’s home directory. This is the most common reason a command that works in your terminal fails under cron: a binary on your interactive PATH is not found, or a script relies on a variable that cron never sets.

To avoid this, use absolute paths for every command and file, and declare the variables your jobs need at the top of the crontab.

Setting PATH, SHELL, and MAILTO in the Crontab

Declare environment variables at the top of the crontab file, before any job lines:

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

* * * * * echo 'Run this command every minute'

SHELL sets the interpreter used to run commands. PATH controls where cron looks for binaries, which is why setting it explicitly resolves most “command not found” failures. HOME is the home directory the job runs in, not a search path for the cron binary. MAILTO directs job output to an email address; emailing requires a configured mail transfer agent such as Sendmail or Postfix on the server. Set MAILTO="" to disable email output entirely.

Note: Cron treats the percent sign (%) as a newline inside the command field. If a command contains a literal %, such as in a date format string, escape it as \%.

Capturing Output and Errors to a Log File

Relying on email for output is fragile because most servers do not have a mail transfer agent configured. The reliable pattern is to redirect both standard output and standard error to a log file. Append >> /path/to/logfile.log 2>&1 to the command, using an absolute path.

Before running any job that writes to a log file, make sure the destination directory exists:

  1. mkdir -p /home/sammy/logs
* * * * * /usr/local/bin/backup.sh >> /home/sammy/logs/backup.log 2>&1

Here >> appends standard output to the log file, and 2>&1 redirects standard error to the same destination so both successes and failures are captured. To discard output entirely and run a job silently, redirect to /dev/null instead:

* * * * * /usr/bin/php /var/www/example.com/sync.php > /dev/null 2>&1

Note: Log files written by cron jobs grow indefinitely unless rotated. For jobs that run frequently or produce verbose output, add a configuration file under /etc/logrotate.d/ to rotate and compress the log automatically. Alternatively, use a timestamped filename in the crontab command so each run writes a separate file:

0 2 * * * /usr/local/bin/backup.sh >> /home/sammy/logs/backup-$(date +\%Y\%m\%d).log 2>&1

Note the escaped \%: cron treats unescaped % as a newline.

Restricting Crontab Access

Two files control which users can schedule cron jobs: /etc/cron.allow and /etc/cron.deny. Neither file exists by default on Ubuntu. When both are absent, all users with shell access can use crontab. Creating either file activates the restriction:

  • If /etc/cron.deny exists, users listed in it cannot edit their crontab.
  • If /etc/cron.allow exists, only users listed in it can edit their crontab.
  • If both files exist and a user appears in both, cron.allow takes precedence.

For example, to restrict crontab access so only the user ishmael can schedule cron jobs, you can create an /etc/cron.allow file that lists allowed users:

echo ishmael | sudo tee /etc/cron.allow > /dev/null
sudo rm -f /etc/cron.deny
echo ishmael | sudo tee -a /etc/cron.allow

Use sudo tee (or sudo sh -c) when writing to files under /etc/; sudo echo ... >> file fails because the redirection happens in your unprivileged shell. Creating /etc/cron.allow restricts crontab access to only the users listed in that file.

The pipe to sudo tee -a is what makes this work: with sudo echo ALL >> /etc/cron.deny, the >> redirection runs in your unprivileged shell and fails with a permission error because only the echo runs as root. Piping to sudo tee -a performs the append as root. The first command locks out all users by appending ALL to cron.deny; the second grants the ishmael profile access by listing it in cron.allow, which takes precedence over cron.deny.

Practical Crontab Examples

These examples assume the referenced scripts exist, are executable (chmod +x), and begin with a shebang such as #!/bin/bash. They also assume the log directory exists. If you have not already created it, run:

  1. mkdir -p /home/sammy/logs

Note: Cron schedules use the system’s local timezone. To confirm what timezone your server is set to before scheduling time-sensitive jobs, run:

  1. timedatectl

If the server is set to UTC and you need jobs to run at a local time, either adjust the server timezone with sudo timedatectl set-timezone Region/City or run date -u to check current UTC time and calculate the offset manually. A job set to 0 9 * * 1 runs at 09:00 in whatever timezone timedatectl reports.

End-to-End Example: Write, Schedule, and Verify a Job

This example walks through the complete workflow: write a script, make it executable, schedule it, and confirm it ran.

Step 1: Write the script.

Create the directory for your scripts if it does not already exist, then open a new script file:

  1. mkdir -p /home/sammy/scripts
  2. nano /home/sammy/scripts/disk-report.sh

Add the following content:

#!/bin/bash
# disk-report.sh - appends a timestamped disk-usage snapshot to the log
LOGFILE="/home/sammy/logs/disk-report.log"
printf '\n=== %s ===\n' "$(date '+%Y-%m-%d %H:%M:%S')" >> "$LOGFILE"
df -h / >> "$LOGFILE"

Save and exit (CTRL + X, Y, ENTER).

Step 2: Make the script executable.

  1. chmod +x /home/sammy/scripts/disk-report.sh

Step 3: Test the script manually before scheduling it.

Always confirm the script runs correctly outside of cron first:

  1. /home/sammy/scripts/disk-report.sh
  2. cat /home/sammy/logs/disk-report.log
=== 2026-06-10 14:05:22 ===
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1        25G  4.2G   20G  18% /

If the output appears correctly, the script is ready to schedule.

Step 4: Add the job to your crontab.

Open your crontab:

  1. crontab -e

To test that cron picks up the job, add it with a * * * * * schedule first (every minute). Change it to the final schedule once you have confirmed it runs:

* * * * * /home/sammy/scripts/disk-report.sh

Save and exit. Wait one to two minutes.

Step 5: Confirm the job ran.

Check the log file:

  1. cat /home/sammy/logs/disk-report.log

You should see a new timestamped entry. Also confirm cron triggered the job:

  1. journalctl -u cron --since "5 minutes ago"
Jun 10 14:06:01 hostname CRON[pid]: (sammy) CMD (/home/sammy/scripts/disk-report.sh)

Step 6: Update to the final schedule.

Once confirmed, open the crontab again and change the schedule. To run the report every day at 6:00 AM:

0 6 * * * /home/sammy/scripts/disk-report.sh

Run a Backup Script Every Night at 2:00 AM

0 2 * * * /usr/local/bin/backup.sh >> /home/sammy/logs/backup.log 2>&1

Clear a Temporary Directory Every Sunday at 3:00 AM

0 3 * * 0 /usr/bin/find /tmp/cache -type f -mtime +7 -delete

This removes files in /tmp/cache that are older than seven days.

Run a Script on Server Reboot

@reboot /usr/local/bin/startup.sh >> /home/sammy/logs/startup.log 2>&1

Run a Sync Job Every 15 Minutes

*/15 * * * * /usr/bin/php /var/www/example.com/sync.php >> /home/sammy/logs/sync.log 2>&1

Send a Weekly Report Every Monday at 8:00 AM

0 8 * * 1 /usr/local/bin/weekly-report.sh >> /home/sammy/logs/weekly-report.log 2>&1

For more on building the scripts these jobs run, see How To Write a Simple Shell Script on a VPS.

Viewing and Debugging Cron Logs on Ubuntu

Checking Cron Logs with journalctl

On Ubuntu 22.04 and 24.04, the reliable way to view cron activity is through journald, which is always present on systemd-based systems. View today’s cron entries:

  1. journalctl -u cron --since today
Jun 10 02:00:01 hostname CRON[pid]: (sammy) CMD (/usr/local/bin/backup.sh >> /home/sammy/logs/backup.log 2>&1)

To follow cron activity live:

  1. journalctl -u cron -f

Reading /var/log/syslog for Cron Entries

If rsyslog is installed, cron also writes to /var/log/syslog. Filter for cron entries:

  1. grep CRON /var/log/syslog

Note: Minimal Ubuntu 24.04 installations may not include rsyslog, in which case /var/log/syslog will not exist. Use journalctl -u cron instead, or install rsyslog with sudo apt install rsyslog.

Common Reasons Cron Jobs Fail Silently

Once you have confirmed in the logs that a job is triggering (the CMD line is present), but the job is not producing the expected result, work through the Common Mistakes checklist. The most frequent causes are relative paths, missing execute permission, environment differences, and unescaped percent signs. Each is covered there with the specific fix.

If the CMD line is absent from the logs entirely, the job is not triggering. Check that the cron daemon is running (systemctl status cron), that your crontab expression is valid (crontab.guru), and that the user has not been blocked by /etc/cron.allow or /etc/cron.deny.

Cron vs. Systemd Timers: When to Use Each

Key Differences

Both cron and systemd timers schedule recurring work, but they differ in capability:

Criteria Cron Systemd Timer
Setup complexity Single crontab line Two unit files (.timer and .service)
Logging Manual redirection to a file Captured in journald automatically
Dependency ordering Not supported Supported via unit dependencies
Missed-run handling Skipped if system was off Persistent=true runs missed jobs at next boot
Randomized start delay Not native RandomizedDelaySec available
Resource limits per job Not supported Inherited from the service unit (cgroups)
Portability Available on virtually all Unix-like systems Linux with systemd only

Decision Guidance

Use cron when the task is a simple recurring command, portability matters, or you want the lowest setup overhead. Choose a systemd timer when you need built-in logging through journald, dependency ordering, missed-run recovery on a machine that is not always on, or per-job resource control.

Minimal Systemd Timer Example

For comparison, the equivalent of 0 2 * * * /usr/local/bin/backup.sh as a systemd timer requires two files.

The service unit at /etc/systemd/system/backup.service:

[Unit]
Description=Daily backup job

[Service]
Type=oneshot
User=sammy

Group=sammy

ExecStart=/usr/local/bin/backup.sh
StandardOutput=append:/home/sammy/logs/backup.log
StandardError=append:/home/sammy/logs/backup.log

The timer unit at /etc/systemd/system/backup.timer:

[Unit]
Description=Run backup daily at 2 AM

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target

Enable and start the timer:

  1. sudo systemctl enable --now backup.timer

Persistent=true means the job runs at the next opportunity if the system was off at the scheduled time. Cron silently skips that run. Use journalctl -u backup.service to view logs without any redirection setup.

For workloads that outgrow both, consider a dedicated scheduler such as Celery for distributed task queues or Apache Airflow for pipeline orchestration.

To configure timers, see Understanding Systemd Units and Unit Files.

Common Mistakes

  • Using ~ in crontab paths. Cron does not expand ~ to the home directory. Always use the full absolute path: /home/sammy/.
  • Forgetting to make the script executable. Cron cannot run a script without the execute bit set. Run chmod +x /path/to/script.sh before scheduling it.
  • Omitting the shebang. A script called by cron needs an interpreter line on the first line, such as #!/bin/bash or #!/usr/bin/env python3. Without it, the shell does not know how to execute the file.
  • Assuming cron shares your interactive environment. Cron runs with a minimal PATH (/usr/bin:/bin). Binaries outside that path are not found unless you set PATH explicitly at the top of the crontab or use absolute paths for every command.
  • Unescaped percent signs in the crontab command field. Cron reads an unescaped % as a newline. Escape literal percent signs as \%. This applies only in the crontab command field; scripts called by cron can use % freely.
  • Forgetting output redirection. Without >> /path/to/log 2>&1, cron discards all output silently unless a mail transfer agent is configured.
  • Using sudo inside a user crontab. A user crontab already runs as that user. For root-level tasks, edit the root crontab with sudo crontab -e rather than prepending sudo to commands inside a user crontab.
  • Editing /var/spool/cron/crontabs/ directly. These files must be managed through crontab -e. Direct edits bypass syntax validation and can corrupt the crontab.
  • Forgetting crontab -r -i. Running crontab -r deletes the crontab immediately with no confirmation. Use crontab -r -i to prompt before deletion.
  • Using sudo echo >> /etc/cron.deny. The >> redirection runs in the unprivileged shell and fails with a permission error, because only echo runs as root. Use echo value | sudo tee -a /etc/cron.deny instead.
  • No protection against overlapping runs. Cron has no built-in locking. If a job is still running when the next scheduled run triggers, cron starts a second instance. For jobs that must not overlap (database exports, slow backups), use a lock file or flock:
*/5 * * * * /usr/bin/flock -n /tmp/backup.lock /usr/local/bin/backup.sh >> /home/sammy/logs/backup.log 2>&1

flock -n exits immediately if the lock is already held, so the second instance skips rather than stacking.

Frequently Asked Questions

How Do I Open and Edit My Crontab File on Ubuntu?

Run crontab -e in your terminal. This opens your user-level crontab in the default editor (usually nano on Ubuntu). Each line in the file represents one scheduled job.

How Do I List All Cron Jobs for the Current User on Ubuntu?

Run crontab -l to print all scheduled jobs for the current user. To list another user’s jobs, run sudo crontab -u username -l.

How Do I Disable a Cron Job Temporarily Without Deleting It?

Open the crontab with crontab -e and add a # character at the start of the job line to comment it out:

# 0 2 * * * /usr/local/bin/backup.sh >> /home/sammy/logs/backup.log 2>&1

Cron ignores commented lines. Remove the # to re-enable the job. This is the standard approach for pausing a scheduled job during maintenance without losing the expression.

Why Is My Cron Job Not Running on Ubuntu?

Run journalctl -u cron --since today. If the CMD line for your job appears in the output, the job triggered and the issue is in the script or its environment. If the CMD line is absent, the job is not firing at all. See Viewing and Debugging Cron Logs on Ubuntu for the diagnostic workflow and Common Mistakes for the full failure-mode checklist.

How Do I Check Cron Logs on Ubuntu?

On Ubuntu 22.04 and 24.04, run journalctl -u cron --since today to view recent cron activity; this works on every systemd-based system. If rsyslog is installed, you can also run grep CRON /var/log/syslog. Log entries show whether a job was triggered and whether it produced output or errors.

What Is the Difference Between crontab -e and /etc/crontab?

crontab -e edits the per-user crontab, and jobs run as that user. /etc/crontab is the system-wide crontab and includes an extra field specifying the user each job runs as. For application-level scheduling, per-user crontabs are preferred.

What Does @reboot Do in a Crontab?

@reboot runs its command once after the cron daemon starts at boot. For a usage example and compatibility notes, see Special Cron Strings.

Does Cron Run When I Am Not Logged In?

Yes. Cron is a system daemon that runs continuously in the background regardless of whether any user is logged in. Jobs scheduled in a user’s crontab run at the specified time as long as the machine is on and the cron service is running. This is one of the primary reasons cron is used for server maintenance: the task runs whether or not an administrator is connected.

Should I Use Cron or Systemd Timers on Ubuntu?

For simple recurring tasks where portability and simplicity matter, cron is the practical choice. Systemd timers are preferable when you need dependency management, logging through journald without extra configuration, missed-run recovery, or per-job resource limits.

How Do I Redirect Cron Job Output to a Log File?

Append >> /absolute/path/to/logfile.log 2>&1 to the command. This sends both standard output and standard error to the file. Without it, cron tries to email output to the local user, which is often not configured on servers.

Conclusion

In this guide, you installed and verified cron, learned the five-field schedule syntax and the special shorthand strings, and managed jobs with the crontab command. You also set the environment variables cron jobs depend on, redirected their output to log files, and worked through practical scheduling examples covering backups, cleanup jobs, and boot-time initialization.

You then inspected cron activity with journalctl and stepped through the most common reasons cron jobs fail silently. With that troubleshooting checklist, you can diagnose a scheduled job that is not behaving as expected rather than guessing at the cause.

To go further, combine cron with shell scripts to automate larger workflows. For example, you could Automate backups with cron. When a job outgrows a fixed schedule, revisit the Cron vs. Systemd Timers section to decide whether a timer fits better.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the author(s)

Shaun Lewis
Shaun Lewis
Author
Mark Drake
Mark Drake
Author
Manager, Developer Education
See author profile

Former Technical Writer at DigitalOcean. Focused on SysAdmin topics including Debian 11, Ubuntu 22.04, Ubuntu 20.04, Databases, SQL and PostgreSQL.

Vinayak Baranwal
Vinayak Baranwal
Editor
Technical Writer II
See author profile

Building future-ready infrastructure with Linux, Cloud, and DevOps. Full Stack Developer & System Administrator. Technical Writer @ DigitalOcean | GitHub Contributor | Passionate about Docker, PostgreSQL, and Open Source | Exploring NLP & AI-TensorFlow | Nailed over 50+ deployments across production environments.

Still looking for an answer?

Was this helpful?


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

how to schedule a python script in the cron job?

Creative CommonsThis work is licensed under a Creative Commons Attribution-NonCommercial- ShareAlike 4.0 International License.
Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Start building today

From GPU-powered inference and Kubernetes to managed databases and storage, get everything you need to build, scale, and deploy intelligent applications.

Dark mode is coming soon.