What is cron?
cron is the time-based job scheduler built into every Linux distribution. It runs commands and scripts automatically at fixed times, dates, or intervals — perfect for backups, log rotation, certificate renewals, database cleanups, and triggering application schedulers. On Ubuntu the scheduler runs as a background service called cron.service, and you define what it should run in files called crontabs.
This guide covers per-user and system-wide cron jobs on Ubuntu 22.04/24.04 LTS, the exact syntax, how to handle environment and logging, and how to keep scheduled tasks running reliably on a managed VPS or cloud server.
Check that cron is installed and running
On Ubuntu, the cron daemon is provided by the cron package and is usually already installed. Verify it:
systemctl status cron
You should see Active: active (running). If the package is missing, install and enable it:
sudo apt update && sudo apt install -y cron
sudo systemctl enable --now cron
Understanding crontab syntax
Each cron job is a single line with five time-and-date fields followed by the command to run:
# ┌───────────── minute (0–59)
# │ ┌───────────── hour (0–23)
# │ │ ┌───────────── day of month (1–31)
# │ │ │ ┌───────────── month (1–12)
# │ │ │ │ ┌───────────── day of week (0–7, where 0 and 7 are Sunday)
# │ │ │ │ │
# * * * * * command to execute
Each field accepts:
| Operator | Meaning | Example |
|---|---|---|
* |
every value | * * * * * = every minute |
, |
a list | 0,30 * * * * = at :00 and :30 |
- |
a range | 0 9-17 * * * = every hour 9am–5pm |
/ |
a step | */15 * * * * = every 15 minutes |
A few worked examples:
0 2 * * * # every day at 02:00
*/5 * * * * # every 5 minutes
30 3 * * 1 # 03:30 every Monday
0 0 1 * * # midnight on the 1st of every month
0 8 * * 1-5 # 08:00 Monday–Friday
You can also use these shorthand strings instead of the five fields: @reboot, @hourly, @daily, @weekly, @monthly, and @yearly. For example, @reboot runs a job once each time the server boots.
Creating a per-user cron job
Most application tasks should run as a normal user, not root. Edit your user's crontab with:
crontab -e
The first time, you'll be asked to pick an editor (nano is the simplest). Add a job — for example, run a backup script every day at 1:30 AM and log the output:
30 1 * * * /home/deploy/scripts/backup.sh >> /home/deploy/logs/backup.log 2>&1
Save and exit. cron installs the new schedule immediately — no restart needed. List your jobs with crontab -l, and remove all of them with crontab -r (use carefully).
The >> file 2>&1 part appends both standard output and errors to a log file. This is important: by default cron emails output to the local user, which you usually never see, so explicit logging is how you debug failures.
System-wide jobs and the run-parts directories
Root-level and packaged jobs live in /etc/crontab and /etc/cron.d/. These files have one extra field — the username — between the time fields and the command:
# m h dom mon dow user command
0 4 * * * root /usr/local/bin/cleanup.sh
For the common cases you don't even need to write a schedule. Ubuntu runs anything you drop into these directories on a fixed cadence:
/etc/cron.hourly/
/etc/cron.daily/
/etc/cron.weekly/
/etc/cron.monthly/
Place an executable script (no file extension, chmod +x) in /etc/cron.daily/ and it runs once a day. This is the cleanest way to ship maintenance scripts.
Environment and PATH gotchas
The single most common reason a job "works in my shell but not in cron" is the environment. cron runs with a minimal PATH (typically /usr/bin:/bin) and does not load your .bashrc or profile. Two fixes:
- Always use absolute paths to binaries and files (
/usr/bin/php, notphp). - Set variables at the top of the crontab:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=ops@example.com
SHELL=/bin/bash
*/10 * * * * cd /var/www/app && /usr/bin/php artisan schedule:run >> /var/log/app-cron.log 2>&1
Note MAILTO="" disables all email; setting it to an address sends job output there if a mailer is configured.
Time zones
cron uses the server's system time zone, not your local one — easy to forget when your team is in Riyadh but the VPS defaults to UTC. Check and set it:
timedatectl # shows current time zone
sudo timedatectl set-timezone Asia/Riyadh
After changing the time zone, restart cron so running jobs pick it up: sudo systemctl restart cron. Hosting your server in-Kingdom means it's naturally aligned to Riyadh time and PDPL data-residency requirements.
Verifying and debugging jobs
On Ubuntu, cron activity is logged to the system journal and /var/log/syslog (there is no separate /var/log/cron by default). Watch executions live:
grep CRON /var/log/syslog | tail
journalctl -u cron --since "1 hour ago"
If a job isn't firing, check in order: the cron service is running, the line has exactly five time fields (or one @ string), the script is executable, and your log file shows the command output. To prove a script works in cron's stripped-down environment, test it with env -i /bin/bash -c '/path/to/script.sh'.
Restricting who can use cron
To control which users may install crontabs, create /etc/cron.allow (a whitelist) or /etc/cron.deny (a blacklist). If /etc/cron.allow exists, only listed users can use crontab — a sensible hardening step on a shared server.
Run it reliably on Skyline Cloud
A cron job is only as dependable as the server it runs on. On a Skyline Cloud VPS or cloud server, your scheduled backups, report generation, and renewal tasks run on always-on infrastructure hosted in Saudi data centres, with local Arabic support and PDPL/NCA-aligned data residency. Pair it with Skyline business email hosting so MAILTO alerts about failed jobs actually reach your team.
Ready to automate your workloads on in-Kingdom infrastructure? Create your Skyline Cloud account and deploy a VPS in minutes.
Comments
0 total · 0 threads