Domain insights

Cron Jobs for Beginners: How to Schedule Backups, Scripts, and Routine Tasks on a VPS

Read crontab schedules, automate tested scripts, protect database backups, capture errors, and troubleshoot cron jobs on a Linux VPS.

Linux and VPS
Cron Jobs for Beginners: How to Schedule Backups, Scripts, and Routine Tasks on a VPS

You have a script that works perfectly.

Every night you connect to your VPS, run it, wait for it to finish, and disconnect. Maybe the script creates a database backup. Maybe it clears temporary files. Maybe it generates a report.

After a week, one thing becomes obvious: the computer should be doing this by itself.

That is exactly the kind of problem cron solves.

Cron is a scheduler commonly used on Linux systems. It runs commands automatically at times you define. You can use it for backups, maintenance scripts, report generation, cache cleanup, application tasks, and many other repetitive jobs.

The idea is simple. The syntax looks strange for about ten minutes.

This guide explains cron from the beginning, builds a useful scheduled task, and shows how to troubleshoot it when "nothing happened."

What a cron job actually is

A cron job is simply a command plus a schedule.

Instead of typing:

/home/soxdomains/scripts/backup.sh

every night, you tell cron to run it automatically.

Cron reads schedule files called crontabs and executes matching commands in the background. Your user does not need to remain logged in.

That makes cron useful for servers, where routine work should continue at 3:00 a.m. even while everyone is asleep.

Open your personal crontab

To edit the cron jobs for your current user:

crontab -e

The first time, Linux may ask which text editor you prefer. If you are a beginner, nano is usually easier than vim.

To list your current jobs:

crontab -l

To edit root's crontab:

sudo crontab -e

Do not use the root crontab merely because a command failed under your normal user. Use root only when the scheduled task genuinely requires administrative privileges.

Understanding the five fields

A normal crontab line contains five schedule fields followed by the command:

* * * * * command

From left to right:

minute hour day-of-month month day-of-week

The usual ranges are:

minute        0-59
hour          0-23
day-of-month  1-31
month         1-12
day-of-week   0-7

Sunday is commonly represented by 0 or 7.

These examples use your personal crontab. System files such as /etc/crontab include an additional username field before the command. When both day-of-month and day-of-week are restricted, traditional cron matches either day field, not necessarily both.

The asterisk means every allowed value.

So:

* * * * * /home/soxdomains/test.sh

means run every minute. That is useful for a quick test, but it is usually a terrible permanent schedule.

Useful schedules you can read at a glance

Every day at 2:00 a.m.:

0 2 * * * /home/soxdomains/scripts/backup.sh

Every hour at minute 15:

15 * * * * /home/soxdomains/scripts/task.sh

Every Monday at 7:30 a.m.:

30 7 * * 1 /home/soxdomains/scripts/report.sh

At midnight on the first day of every month:

0 0 1 * * /home/soxdomains/scripts/monthly.sh

Every 15 minutes:

*/15 * * * * /home/soxdomains/scripts/check.sh

At 11:45 p.m. every day:

45 23 * * * /home/soxdomains/scripts/task.sh

For this expression:

30 4 * * 0

read it from left to right: minute 30, hour 4, every day of month, every month, Sunday. The job runs Sunday at 4:30 a.m.

Once you understand the five positions, cron becomes much easier.

Your first cron job

Create a place for personal scripts:

mkdir -p ~/scripts

Now create a tiny test script:

nano ~/scripts/hello-cron.sh

Add:

#!/bin/bash
date >> /home/soxdomains/cron-test.log
echo "Cron ran successfully" >> /home/soxdomains/cron-test.log

Replace /home/soxdomains with your actual home directory.

Save the file and make it executable:

chmod u+x ~/scripts/hello-cron.sh

Test it manually:

~/scripts/hello-cron.sh
cat ~/cron-test.log

Only after the script works manually should you schedule it.

Open:

crontab -e

Add temporarily:

* * * * * /home/soxdomains/scripts/hello-cron.sh

Wait a minute or two, then check the log. Once the test works, remove the every-minute schedule.

A practical MySQL backup example

Suppose you have a MySQL database named exampleapp.

A simple backup script could look like this:

#!/bin/bash
set -eu
umask 077
BACKUP_DIR="/home/soxdomains/backups"
DATE=$(date +%Y-%m-%d_%H-%M-%S)
mkdir -p "$BACKUP_DIR"
TEMP_FILE=$(mktemp "$BACKUP_DIR/exampleapp_$DATE.XXXXXX.part")
trap 'rm -f -- "$TEMP_FILE"' EXIT
/usr/bin/mysqldump --single-transaction --no-tablespaces exampleapp > "$TEMP_FILE"
test -s "$TEMP_FILE"
mv "$TEMP_FILE" "$BACKUP_DIR/exampleapp_$DATE.sql"

Save it as:

/home/soxdomains/scripts/mysql-backup.sh

Make it executable:

chmod 700 /home/soxdomains/scripts/mysql-backup.sh

Test it manually. Then schedule it:

0 2 * * * /home/soxdomains/scripts/mysql-backup.sh

Now it runs every day at 2:00 a.m.

The script stops on a failed command, restricts newly created files to the owner, and publishes the final .sql filename only after the dump succeeds and contains data. Check the permissions of an existing backup directory too: umask does not change existing files or directories. Replace the example paths and verify the installed mysqldump binary before scheduling.

--single-transaction is intended for transactional tables such as InnoDB. It does not provide the same consistency for MyISAM tables, and concurrent schema changes can invalidate a dump. --no-tablespaces omits tablespace statements; required privileges, stored routines, events, and GTID settings depend on your database and restore plan. Test a restore before relying on this example in production.

A production backup script should not expose a plain-text database password to other users. Use an authentication method appropriate to your MySQL setup and restrict any credential files.

Also remember that a backup stored only on the same VPS is not a complete backup strategy. If the VPS disappears, the backup may disappear with it.

Cron has a smaller environment than your terminal

This is one of the most common beginner surprises.

You log in and run:

mysqldump

It works.

Cron runs the script and says the command does not exist.

Your interactive shell and cron may not have the same environment or PATH.

Find the complete path:

which mysqldump

Perhaps it returns:

/usr/bin/mysqldump

Use that full path in scripts run by cron.

The same principle applies to PHP, Python, Node.js, Composer, and custom programs.

Use absolute paths

This command depends on the current directory:

cp config.php backups/

Cron may not start in the directory you expected.

Prefer:

cp /var/www/example.com/config.php /home/soxdomains/backups/

Be explicit. Servers appreciate clarity. So does the person troubleshooting them six months later.

Capture output and errors

If a job fails silently, debugging becomes difficult.

Redirect normal output and errors to a log:

0 2 * * * /home/soxdomains/scripts/backup.sh >> /home/soxdomains/logs/backup.log 2>&1

Create the directory first:

mkdir -p /home/soxdomains/logs

Then inspect:

tail -n 100 /home/soxdomains/logs/backup.log

>> appends normal output. 2>&1 sends error output to the same destination.

If a command produces sensitive information, protect the log appropriately.

Did cron fail, or did the command fail?

These are different questions.

On Ubuntu, try:

sudo journalctl -u cron --since "1 hour ago"

If cron launched the command, the scheduler may be working correctly even though your script failed afterward.

This distinction saves time. First prove the scheduler launched the job. Then investigate the job itself.

Permission problems

If the script says Permission denied, inspect it:

ls -l /home/soxdomains/scripts/backup.sh

Make it executable for its owner if appropriate:

chmod u+x /home/soxdomains/scripts/backup.sh

Also verify that the cron user can read the required source files and write to destination directories.

Do not solve every permission problem with chmod 777. That gives far more access than most files need.

The user running the job matters

A job in your crontab -e runs as your user. A job in sudo crontab -e runs as root.

That affects file ownership, home directories, SSH keys, environment variables, and credentials.

A backup created as root may later be inconvenient for the application owner to manage.

Choose the execution identity deliberately.

PHP and Python versions

If an application requires a particular PHP binary, schedule it explicitly:

*/5 * * * * /usr/bin/php /var/www/example.com/cron.php >> /home/soxdomains/logs/app-cron.log 2>&1

For Python:

0 * * * * /usr/bin/python3 /home/soxdomains/scripts/report.py

Virtual environments need additional care because cron does not automatically reproduce the environment you activate in an interactive terminal.

Do not start everything at midnight

Five backups, log compression, a malware scan, and a report all beginning at 00:00 can create an unnecessary CPU and disk spike.

Spread jobs out:

5 0 * * *
20 0 * * *
45 0 * * *
15 1 * * *

cPanel's own documentation warns that cron jobs scheduled too frequently can overlap and degrade performance. The same operational principle applies on a VPS.

On systems with flock, a lock can prevent the same job from running concurrently:

0 2 * * * /usr/bin/flock -n /home/soxdomains/backups/mysql-backup.lock /home/soxdomains/scripts/mysql-backup.sh >> /home/soxdomains/logs/backup.log 2>&1

Use this as an alternative to the unlocked entry, not as a second schedule for the same backup. Create the backup and log directories first, check the flock path, and monitor skipped runs. With -n, an overlapping invocation exits instead of waiting.

Retention matters

Successful backups consume space. Without retention, an automated backup can eventually fill the filesystem.

Before deleting anything, first display the files that would match:

find /home/soxdomains/backups -type f -name "*.sql" -mtime +14 -print

Inspect the output carefully before designing an automated deletion policy.

Deletion commands deserve more suspicion than creation commands.

Time zones matter

Cron uses the server's configured time.

Some cron implementations support a per-crontab timezone such as CRON_TZ; verify your implementation before using it. Daylight-saving changes can skip or repeat wall-clock times. For tasks where that matters, choose an appropriate timezone and check your scheduler's documented behavior.

Check:

timedatectl

If the VPS uses UTC and you expect another timezone, 0 8 * * * may not mean the hour you think it does.

Document the intended timezone for reports, billing tasks, backups, and notifications.

Cron in cPanel

If you use cPanel hosting instead of a VPS command line, cPanel includes a Cron Jobs interface when enabled by the hosting provider.

It lets you select common schedules or enter minute, hour, day, month, and weekday values manually.

The concept is the same.

A PHP command might look similar to:

/usr/local/bin/php /home/username/public_html/task.php

The exact PHP path depends on the hosting environment. Do not copy a path from another provider without checking yours.

cPanel can also send cron output by email, which is useful during setup.

Never assume a cron backup is good

A new .sql file every morning is encouraging. It is not proof that restoration works.

Periodically verify:

  1. the file exists;
  2. its size is reasonable;
  3. it is not empty;
  4. it can be read;
  5. the backup command completed successfully;
  6. a test restoration succeeds;
  7. an off-server copy exists.

Automation can repeat mistakes with impressive punctuality.

Troubleshooting checklist

When a cron job does not work:

  1. Run the command manually.
  2. Confirm the script is executable.
  3. Use absolute paths.
  4. Check which user owns the crontab.
  5. Check file permissions.
  6. Capture normal output and errors.
  7. Check cron logs.
  8. Verify the server timezone.
  9. Verify required environment variables.
  10. Verify executable paths.
  11. Check disk space with df -h.
  12. Test again with a temporary frequent schedule, then remove it.

A good crontab should be boring. That is a compliment.

More practical answers

How do I edit my cron jobs?

crontab -e

How do I list my cron jobs?

crontab -l

Does my computer need to remain connected?

No. Cron runs on the server.

Can cron create database backups?

Yes. Cron can run a tested backup script. Keep protected copies outside the VPS and test restoration.

Frequently asked questions

What is cron?

Cron is a scheduler commonly used on Linux systems to run commands automatically at specified times.

What does 0 2 * * * mean?

It means run every day at 2:00 a.m. according to the server's configured time.

Why does my command work in SSH but fail in cron?

Cron may use a smaller environment and a different PATH. Use absolute paths and capture errors.

Should I run every cron job as root?

No. Use the least privileged account that can perform the required task.