How to Set Up a Cron Job on Linux
Automate anything on a schedule with cron: crontab syntax explained, real examples, logging output, and how to avoid the common gotchas.

Cron is the Linux scheduler that runs commands at set times — backups at 3am, a script every five minutes, log cleanup every Sunday. This guide explains crontab syntax clearly, gives real examples, and covers the gotchas that cause "my cron job didn't run" every single time.
The five-field schedule
A crontab line has five time fields followed by the command:
* * * * * command-to-run
│ │ │ │ │
│ │ │ │ └── day of week (0-7, 0 and 7 both = Sunday)
│ │ │ └──── month (1-12)
│ │ └────── day of month (1-31)
│ └──────── hour (0-23)
└────────── minute (0-59)
An * means "every". So * * * * * runs every minute, and 0 3 * * * runs at 03:00 every day.
Edit your crontab
Each user has their own crontab. Edit it with:
crontab -e
The first time, it asks which editor to use — pick nano if unsure. List your current jobs with crontab -l.
Real examples
- Every day at 3am — database backup:
0 3 * * * /home/youruser/scripts/backup.sh
- Every 5 minutes — health check:
*/5 * * * * /usr/bin/curl -fsS https://example.com/health > /dev/null
- Every Sunday at 2am — clean old files:
0 2 * * 0 find /tmp -type f -mtime +7 -delete
- Every weekday at 9am:
0 9 * * 1-5 /home/youruser/scripts/report.sh
- Twice a day (noon and midnight):
0 0,12 * * * /home/youruser/scripts/sync.sh
The */5 step syntax means "every 5th"; ranges like 1-5 and lists like 0,12 combine naturally.

The two gotchas that break most cron jobs
Nearly every "it works in my terminal but not in cron" problem is one of these:
1. Cron has a minimal PATH. Cron runs with a bare environment, so node, python3, or docker may not be found. Always use absolute paths, and set PATH at the top of your crontab:
PATH=/usr/local/bin:/usr/bin:/bin
2. The working directory is the user's home. Do not assume you are in your project folder. Either cd inside the script or use absolute paths for every file.
Always log the output
By default, cron emails output to the local user, which you will never see. Redirect to a log file so you can debug:
0 3 * * * /home/youruser/scripts/backup.sh >> /home/youruser/logs/backup.log 2>&1
2>&1 sends errors to the same file as normal output — essential for finding out why a job failed.
Verify cron is running and check its log
systemctl status cron
grep CRON /var/log/syslog
The syslog entries show each time cron fired your job (though not the job's own output — that is what your redirect is for).
When to use a systemd timer instead
For jobs tightly tied to a service, or that need to catch up after downtime (Persistent=true), a systemd timer is more powerful and integrates with journald logging. See our systemd service guide for the service side. For most simple schedules, though, cron is perfect. Cron pairs beautifully with automated database backups and Gitea dumps.
Shortcut schedules and @reboot
Cron understands a few named schedules that read more clearly than five stars:
@daily /home/youruser/scripts/backup.sh
@hourly /home/youruser/scripts/sync.sh
@reboot /home/youruser/scripts/startup.sh
@daily runs at midnight, @hourly at the top of each hour, and @reboot runs once when the server boots — handy for starting a helper process that is not a full service. There is also @weekly, @monthly, and @yearly.
Write cron-friendly scripts
The most reliable pattern is to keep the crontab line short and put the real work in a script that sets its own environment. Start each script with a strict shell and explicit paths:
#!/bin/bash
set -euo pipefail
export PATH=/usr/local/bin:/usr/bin:/bin
cd /home/youruser/myapp
# ... do the work ...
set -euo pipefail makes the script stop on the first error instead of silently continuing — exactly what you want for an unattended job you are not watching.
FAQ
Why does my cron job work manually but not on schedule?
Almost certainly PATH or working directory. Cron's environment is minimal — use absolute paths for both the interpreter and files, set PATH at the top of the crontab, and redirect output to a log to see the actual error.
What is the difference between crontab -e and /etc/crontab?
crontab -e edits the per-user crontab (no username field). /etc/crontab and files in /etc/cron.d/ are system-wide and include an extra username field before the command. Use per-user crontabs for your own jobs.
How do I run a job every 30 seconds?
Cron's finest granularity is one minute. For sub-minute intervals, use a systemd timer with OnUnitActiveSec=30s, or a script that loops with sleep 30.
How do I remove all my cron jobs?
crontab -r deletes your entire crontab — use with care. To remove one job, run crontab -e and delete just that line.
Nxeon VPS plans give you full root to schedule backups, syncs, and maintenance with cron on fast NVMe — with free migration help if you are moving an automated setup across.