Cron is a time-based job scheduler for Unix-like operating systems. It is used to automate various tasks, typically system maintenance and administration related jobs such as:
- Backing up databases, files, and directories.
- Creating and sending scheduled reports for certain activities or events.
- Verifying if a service is accessible.
Cron allows these tasks to be executed periodically at selected times, dates,
months, and intervals. The
cron command utility can be found on all Unix-like
systems, most commonly on macOS and Linux-based systems.
This article will explain the Cron syntax and show you how to create and edit cron jobs on a Linux-based machine. You'll also learn how to monitor cron jobs so that if a job fails to run, you will be notified so that you can take the appropriate action to fix the problem.
Before continuing with the sections below, ensure that you have a Linux-based machine at hand. This could be a PC, virtual machine, virtual private server, or WSL (if you are using Windows). You also need root access so ensure to login to your machine using a non-root user with administrative privileges.
We'll be demonstrating the concepts discussed in this article on an Ubuntu 22.04 server, but the steps should be pretty similar on most mainstream Linux distributions.
Step 1 — Getting started with Cron
cron command utility comes preinstalled on every Ubuntu installation, so
you can check its status using the following command:
sudo systemctl status cron
● cron.service - Regular background program processing daemon Loaded: loaded (/lib/systemd/system/cron.service; enabled; vendor preset: >Docs: man:cron(8) Main PID: 751 (cron) Tasks: 1 (limit: 2258) Memory: 408.0K CPU: 3ms CGroup: /system.slice/cron.service └─751 /usr/sbin/cron -f -P
If you're getting the same output above, it means
cron is up and running on
your system, and you can skip ahead to the next section. However, just in case
the service is not found or not installed on your machine, we will describe how
to install and set it up in this section.
First, update your system repositories to the latest version using the following command:
sudo apt update -y
After the updates are completed, you can install Cron on your system:
sudo apt install cron -y
Next, you'll need to enable the service and start it so that it is launched in the background and keeps running even if the server is rebooted:
sudo systemctl enable cron
Synchronizing state of cron.service with SysV service script with /lib/systemd/systemd-sysv-install. Executing: /lib/systemd/systemd-sysv-install enable cron
sudo systemctl start cron
Check the status of
sudo systemctl status cron
At this point, you should observe that the
cron service is now up and running.
Step 2 — Writing your first Cron job
In this section, we will discuss how to automate a simple but repetitive task
using Cron. All Cron jobs are managed through a special program called
crontab, and every operating system user has their own
crontab file which is
located in the
You can open up your
crontab file using the following command:
If you are running this command for the first time, you will get the following output asking you to select a text editor:
no crontab for eric - 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 :
/bin/nano and press
Enter. Your default crontab editor will be set to
Nano and a temporary
crontab file will be created and opened in the editor.
This file contains some text explaining a Cron expression's basic syntax. Note
that any line beginning with the
# character is signifies a comment.
# Edit this file to introduce tasks to be run by cron. . . .# For example, you can run a backup of all your user accounts# at 5 a.m every week with:# # For more information see the manual pages of crontab(5) and cron(8) # # m h dom mon dow command
Basic Cron syntax
A Cron expression has the following structure:
minute hour day_of_month month day_of_week command
Each of the above fields takes the following values:
command: Any operating system commands. When you need to execute multiple commands in one Cron Job, you can chain them together using
For example, the expression below means the commands
curl https://betterstack.com and
curl https://www.google.com will be
executed every Sunday at 04:05 AM. The asterisk (
*) is a wildcard variable,
meaning that all possible values are accepted. Cron will treat the first five
parameters, separated by spaces, as scheduling parameters, and the rest will be
treated as Linux commands.
. . . 5 4 * * sun curl https://betterstack.com && curl https://www.google.com
CTRL + X to exit the editor, and then press
Y to save the
file, and it will be saved as
/var/spool/cron/crontabs/<username>. You can
open this file again using the same command (
crontab -e). Note that
crontab -e opens a file in the
/tmp directory instead of the actual crontab
file so that it can check your modifications for errors and prevent you from
overwriting your actual crontab file with those errors.
Let's now look at how to define more complex schedules with cron. For example, you might want the job to repeat every Monday, Tuesday, and Saturday at 00:00. To define schedules like this, we need a more powerful syntax, as shown in the list below:
*: This is a wildcard variable representing "all". For instance,
* * * * *means this Cron Job will be repeated every minute of every hour of every day.
,: Commas are used to break up values to form a list. For instance,
0 0 * * mon,tue,satspecifies a job which repeats at 00:00 every Monday, Tuesday, and Saturday.
-: A hyphen is used to define a range of values. For example,
0-9 * * * *means this job will be repeated for the first 10 minutes of every hour of every day.
/: A forward slash is used to define a step interval. For example,
*/5 * * * *defines a job that will be repeated every 5 minutes.
To make sure you are familiar with these syntaxes, here are some more examples:
5 7 3 8 *: Every August 3rd at 7:05 AM.
23 0-20/2 * * *: At minute 23 for every second hour from 0 to 20. (00:23, 02:23, 04:23, and so on)
0 0,12 1 */2 *: At 00:00 and 12:00 for the first day of every second month. (February 1st, April 1st, June 1st ...)
If you're still having trouble understanding these expressions, there is a handy
website called Crontab guru that allows you to test a
Cron expression before using it in your
crontab. Besides these special
syntaxes, Cron also tries to simplify your workflow by introducing these
@reboot: the scheduled task will run once at system startup.
@annually: run once a year, same as
0 0 1 1 *.
@monthly: run once a month, same as
0 0 1 * *.
@weekly: run once a week, same as
0 0 * * 0.
@midnight: run once a day, same as
0 0 * * *.
@hourly: Run once every hour, same as
0 * * * *.
You can replace the schedule variables using these shortcuts like this:
@yearly curl https://google.com
The above Cron expression is the same as:
0 0 1 1 * curl https://google.com
Step 3 — Managing
crontab -e command discussed earlier, which is used to open the
crontab file for the current user, there are some other
available commands for
crontab -l: echos the current contents of the
crontabfile to the console.
crontab -r: Remove the current
crontabfile. You should not use this command for safety reasons because it won't ask you to confirm the deletion of the
crontab -r -i: This is the recommended command to use when you wish to delete a
crontabfile, as it will ask you to confirm your choice like this:
crontab -r -i
crontab: really delete eric's crontab? (y/n)
crontab -e: This command opens up your
crontabfile for editing.
sudo crontab -u <user> -e: If a user has been granted root privileges, that user will be able to edit another user's
crontabfile using this command.
If you manage an operating system with multiple users, you may create prevent
certain users from accessing these
crontab commands for security reasons.
This can be done by specifying usernames in a
/etc/cron.deny file or a
/etc/cron.allow file. The former prevents users in the file from accessing the
crontab commands while the latter allows only the users in the file to access
the commands. If both files are present, then
cron.allow will override
cron.deny, meaning that a user present in both files will be granted access to
For instance, if you want to deny access to all users but grant access to only a specific user, you can use the following commands:
sudo echo ALL >>/etc/cron.deny # deny access to all users
sudo echo jack >>/etc/cron.allow # grant access to the user `jack`:
Step 4 — Executing script files with Cron
In this section, we'll automate a sequence of commands in order using a shell script. This script will retrieve system usage information such as CPU, memory and disk usage, as well as internet speed, and save them to a file.
Go ahead and create a new directory in your home directory with the following command:
cd ~ && mkdir scripts
Create a new script file within the
scripts directory, and populate it with
the following contents:
#! /bin/bash : > ~/system-usage.txt echo "============================== CPU and Memory Usage ==============================" >> ~/system-usage.txt top -b -n 1 >> ~/system-usage.txt echo "================================== Disk Usage ====================================" >> ~/system-usage.txt df -h >> ~/system-usage.txt echo "============================= Internet Speed Test ================================" >> ~/system-usage.txt speedtest >> ~/system-usage.txt
Before running the script, ensure to install the
speedtest-cli package with
the following command:
sudo apt install speedtest-cli
Next, make the script executable by the current user:
chmod +x scripts/system-usage.sh
Test the script to confirm that it's working as expected:
Once the script exits, check the contents of the
system-usage.txt file in the
You should observe the following output:
============================== CPU and Memory Usage ============================== top - 18:18:28 up 1 day, 1:55, 1 user, load average: 0.00, 0.00, 0.00 Tasks: 130 total, 1 running, 129 sleeping, 0 stopped, 0 zombie %Cpu(s): 0.0 us, 3.2 sy, 0.0 ni, 96.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st MiB Mem : 1927.7 total, 1289.0 free, 152.1 used, 486.6 buff/cache MiB Swap: 0.0 total, 0.0 free, 0.0 used. 1612.4 avail Mem . . . ================================== Disk Usage ==================================== Filesystem Size Used Avail Use% Mounted on tmpfs 193M 1.1M 192M 1% /run /dev/sda1 38G 2.0G 34G 6% / tmpfs 964M 0 964M 0% /dev/shm tmpfs 5.0M 0 5.0M 0% /run/lock /dev/sda15 253M 1.1M 252M 1% /boot/efi tmpfs 193M 0 193M 0% /run/user/1000 ============================= Internet Speed Test ================================ Retrieving speedtest.net configuration... Testing from Hetzner Online GmbH (184.108.40.206)... Retrieving speedtest.net server list... Selecting best server based on ping... Hosted by All Points Broadband (Ashburn, VA) [1774.19 km]: 1.337 ms Testing download speed................................................................................ Download: 1328.87 Mbit/s Testing upload speed...................................................................................................... Upload: 910.45 Mbit/s
Now, create a Cron job that runs this Bash script periodically.
Add the following line to the end of the file and quit your editor afterward:
*/5 * * * * bash ~/scripts/system-usage.sh
With this configuration in place, your system usage information will be
retrieved every 5 minutes, and the output will be saved to the
~/system-usage.txt file as demonstrated earlier.
Step 5 — Monitoring Cron output
Since the Cron Jobs are executed in the background, you will not receive feedback when the task executes so you must actively monitor each Cron Job to get notified when it succeeds or fails. Typically, there are two major ways to monitor your cron jobs and both will be demonstrated in this section.
1. Monitoring cron jobs via email
cron will attempt to send an email if your scheduled task produces
some output such as the one shown below:
* * * * * <command> && echo "Cron Job executed."
However, for this to work, you need to set up an SMTP server on your machine. In
this section, we'll talk about how to send emails using
sSMTP and Gmail. Start by installing
ssmtp on your computer:
sudo apt update
sudo apt install ssmtp
Next, open its configuration file:
sudo nano /etc/ssmtp/ssmtp.conf
Update the contents of the file as follows:
# # Config file for sSMTP sendmail # # The person who gets all mail for userids < 1000 # Make this empty to disable rewriting.# The place where the mail goes. The actual machine name is required no # MX records are consulted. Commonly mailhosts are named mail.domain.com mailhub=smtp.gmail.com:465 # Where will the mail seem to come from? rewriteDomain=gmail.com # The full hostname # Use implicit TLS (port 465). When using port 587, change UseSTARTTLS=Yes TLS_CA_FILE=/etc/ssl/certs/ca-certificates.crt UseTLS=Yes UseSTARTTLS=No # Username/PasswordAuthUser=<your_email_address>AuthMethod=LOGIN # Are users allowed to set their own From: address? # YES - Allow the user to specify their own From: address # NO - Use the system generated From: address FromLineOverride=YES
One thing to note is that you must enable 2-Step-Verification for your Google
account and then generate a unique
App Password to use in
ssmtp.conf, you cannot use your Google password directly.
Next, open your crontab file again, and this time, you can output the content of
. . . MAILTO="<your_email_address>" */5 * * * * bash ~/scripts/system-usage.sh && echo "$(cat ~/system-usage.txt)"
Remember to add the
MAILTO option shown above, otherwise, the cron emails will
be sent to
<username>@gmail.com. This particular job will run every five
minutes, and the output will be sent to the email address specified by
Wait for five minutes, and you should receive the following email in your inbox:
2. Monitoring Cron Jobs with a cloud service
Another way to monitor Cron Jobs is by use a cloud service that provides Cron monitoring capabilities. This is typically the way to go for serious production applications where the sustained failure of a scheduled task can potentially cause a massive problem for the business.
Better Uptime is a monitoring tool that offers Cron Job monitoring services. It provides much more flexibility for alerting options and keeps track of the health of the service over time. You can set up the exact person or team that should be alerted when a job fails and even create status pages for communicating downtime to your customers.
In this section, you will use Better Uptime to monitor the system usage cron job that you set up earlier. First, you need to create a free Better Uptime account if you don't have one already. Once signed in, click Heartbeats on the navigation menu and create your first heartbeat.
Enter an appropriate name for your monitor and how often you expect the monitored task to be repeated (five minutes in this case). Do enter an appropriate grace period to account for slight delays due to the network. In the On-call escalation section, select how you wish to be notified when an incident is detected. Once you are done, click the Save Changes button.
You will see this page next:
The highlighted URL above is what Better Uptime uses to monitor your Cron activity. You need to set up the job such that once it executes, a HEAD, GET, or POST request is made to this URL. Once Better Uptime receives the request, the job will be recorded as successfully executed.
Suppose the request is not received for any reason within the specified time period (including the grace period). An incident will be recorded and you will be notified through the appropriate channel.
Head back to the terminal and open your
crontab file once again:
Edit the cron job that you wish to monitor:
. . . */5 * * * * bash ~/scripts/system-usage.sh && echo "$(cat ~/system-usage.txt)" && curl https://betteruptime.com/api/v1/heartbeat/<your-heartbeat-monitor-id>
Save this crontab by exiting your editor, then wait for the job to run. You should observe that your monitor is marked as "Up" meaning that the job is running as scheduled.
You can also make a request to the Better Uptime URL in the bash script like this:
. . . curl https://betteruptime.com/api/v1/heartbeat/<your-heartbeat-monitor-id>
This way, when you have multiple scripts in one job, you can set up a heartbeat for each script, and you'll be able to tell which one is not working when an incident happens.
If you want to simulate an incident, stop the
cron service with the command
sudo systemctl stop cron
Better Uptime will stop receiving the requests and mark your monitor as "Down":
You will also get an alert in the configured channels:
You can view details about the incident or acknowledge it, indicating that you are working to resolve it, or you can escalate the incident further by alerting one or more members of the relevant team, or even the entire organization.
In this tutorial, we discussed how to use the
cron utility to automate tasks
on Linux and how to monitor cron jobs through email or a cloud monitoring
service like Better Uptime.
You should now understand the Cron scheduling syntax and how to create and
monitor any cron jobs. To learn more about the
cron command, see its
man cron), or view checkout
these articles tackling
common questions about the program.
Make your mark
Join the writer's program
Are you a developer and love writing and sharing your knowledge with the world? Join our guest writing program and get paid for writing amazing technical guides. We'll get them to the right readers that will appreciate them.Write for us
Build on top of Better Stack
Write a script, app or project on top of Better Stack and share it with the world. Make a public repository and share it with us at our email@example.com
or submit a pull request and help us build better products for everyone.
See the full list of amazing projects on github