Guides
Getting started with Cron Jobs

Getting Started with Cron Jobs on Linux

Better Stack Team
Updated on September 7, 2022

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.

Prerequisites

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

The cron command utility comes preinstalled on every Ubuntu installation, so you can check its status using the following command:

sudo systemctl status cron
Copied!
Output
● cron.service - Regular background program processing daemon
 Loaded: loaded (/lib/systemd/system/cron.service; enabled; vendor preset: >
Active: active (running) since Wed 2022-08-31 16:23:02 UTC; 4min 9s ago
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
Copied!

After the updates are completed, you can install Cron on your system:

sudo apt install cron -y
Copied!

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
Copied!
Output
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
Copied!

Check the status of cron again:

sudo systemctl status cron
Copied!

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 /var/spool/cron/crontabs/ directory.

You can open up your crontab file using the following command:

crontab -e
Copied!

If you are running this command for the first time, you will get the following output asking you to select a text editor:

Output
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 [1]:

Select /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.

crontab
# 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:
# 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
Copied!

Basic Cron syntax

A Cron expression has the following structure:

minute hour day_of_month month day_of_week command
Copied!

Each of the above fields takes the following values:

  • minute: 0-59
  • hour: 0-23
  • day_of_month: 1-31
  • month: 1-12 or JAN-DEC
  • day_of_week: 0-6 or SUN-SAT
  • 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
Copied!

Lastly, press 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,sat specifies 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 shortcuts.

  • @reboot: the scheduled task will run once at system startup.
  • @yearly or @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.
  • @daily or @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
Copied!

The above Cron expression is the same as:

0 0 1 1 * curl https://google.com
Copied!

Step 3 — Managing crontab files

Besides the crontab -e command discussed earlier, which is used to open the corresponding crontab file for the current user, there are some other available commands for crontab:

  • crontab -l: echos the current contents of the crontab file to the console.
  • crontab -r: Remove the current crontab file. You should not use this command for safety reasons because it won't ask you to confirm the deletion of the crontab file.
  • crontab -r -i: This is the recommended command to use when you wish to delete a crontab file, as it will ask you to confirm your choice like this:
crontab -r -i
Copied!
Output
crontab: really delete eric's crontab? (y/n)
  • crontab -e: This command opens up your crontab file 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 crontab file 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 the crontab command.

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
Copied!
sudo echo jack >>/etc/cron.allow # grant access to the user `jack`:
Copied!

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
Copied!

Create a new script file within the scripts directory, and populate it with the following contents:

nano scripts/system-usage.sh
Copied!
~/scripts/system-usage.sh
#! /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
Copied!

Before running the script, ensure to install the speedtest-cli package with the following command:

sudo apt install speedtest-cli
Copied!

Next, make the script executable by the current user:

chmod +x scripts/system-usage.sh
Copied!

Test the script to confirm that it's working as expected:

./scripts/system-usage.sh
Copied!

Once the script exits, check the contents of the system-usage.txt file in the home directory:

cat ~/system-usage.txt
Copied!

You should observe the following output:

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 (5.161.145.150)...
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.

crontab -e
Copied!

Add the following line to the end of the file and quit your editor afterward:

*/5 * * * * bash ~/scripts/system-usage.sh
Copied!

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

By default, 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."
Copied!

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
Copied!
sudo apt install ssmtp
Copied!

Next, open its configuration file:

sudo nano /etc/ssmtp/ssmtp.conf
Copied!

Update the contents of the file as follows:

/etc/ssmtp/ssmtp.conf
#
# Config file for sSMTP sendmail
#
# The person who gets all mail for userids < 1000
# Make this empty to disable rewriting.
root=<your_email_address>
# 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
hostname=<your_hostname>.<your_ip>.tld
# 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/Password
AuthUser=<your_email_address>
AuthPass=<password>
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
Copied!

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.

Google App Passwords

Next, open your crontab file again, and this time, you can output the content of the system-usage.txt file:

crontab -e
Copied!
crontab
. . .
MAILTO="<your_email_address>"

*/5 * * * * bash ~/scripts/system-usage.sh && echo "$(cat ~/system-usage.txt)"
Copied!

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 MAILTO. Wait for five minutes, and you should receive the following email in your inbox:

Cron Email

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.

Better Uptime Heartbeats

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.

Better Uptime create heartbeat

You will see this page next:

Better Uptime heartbeat URL

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:

crontab -e
Copied!

Edit the cron job that you wish to monitor:

crontab
. . .
*/5 * * * * bash ~/scripts/system-usage.sh && echo "$(cat ~/system-usage.txt)" && curl https://betteruptime.com/api/v1/heartbeat/<your-heartbeat-monitor-id>
Copied!

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.

Heartbeat Running

You can also make a request to the Better Uptime URL in the bash script like this:

~/scripts/system-usage.sh
. . .

curl https://betteruptime.com/api/v1/heartbeat/<your-heartbeat-monitor-id>
Copied!

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 below:

sudo systemctl stop cron
Copied!

Better Uptime will stop receiving the requests and mark your monitor as "Down":

Heartbeat Incident

You will also get an alert in the configured channels:

Better Uptime Incident Email Alert

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.

Final thoughts

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 manual page (man cron), or view checkout these articles tackling common questions about the program.

Check Uptime, Ping, Ports, SSL and more.
Get Slack, SMS and phone incident alerts.
Easy on-call duty scheduling.
Create free status page on your domain.
Got an article suggestion? Let us know
Licensed under CC-BY-NC-SA

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.