Crontab Basics


tl;dr

crontab -l # List crontab entries
crontab -e # Edit a crontab using the EDITOR specified (export EDITOR=nano)
crontab -r # Remove a crontab
sudo crontab -e # Edit root user’s crontab
crontab my-crontab # add cron jobs by giving a file to crontab
  • If you are adding a script in any of the cron directories, it has to be executable
  • Use absolute paths for files, directories and executable commands
  • it should link to the absolute path of the executables (commands). e.g. /bin/echo instead of echo. Find out absolute paths with the which command, e.g. which echo (or consider adding PATH at the top of the crontab file)
  • Commands that need to be run with sudo should be added to the root user’s crontab
  • Have your script create a file that log success or failure, makes it easier to troubleshoot cron echo "Nightly Backup Successful: $(date)" >> /tmp/mybackup.log
  • Recommended is to add cron jobs to any of the cron directories (e.g. /etc/cron.d) instead of editing a user’s crontab (crontab -e)
  • The user adding the crons needs to be in cron.allow (if it exists)
  • User access is determined by /etc/cron.allow and /etc/cron.deny, if they exist. Blank /etc/cron.deny means only root is allowed access, plus everyone who’s in /etc/cron.allow. No cron.allow and cron.deny means everyone has access

Where to add your cron jobs?

There are plenty of places where you can place your cron jobs. You can

  • edit the user’s crontab /var/spool/cron/crontabs/$USER – not recommended, /var/spool is considered temp/working directory, could wipe out with updates
  • edit /etc/crontab – This file could be used for other cron commands, but probably shouldn’t be. It is not usual to add commands to this file. While an experienced user should know about it, it is not recommended that you add anything to /etc/crontab. Apart from anything else, this could cause a problem if the /etc/crontab file is affected by updates!
  • place a file in /etc/cron.d – This directory can contain crontab files. The directory is often used by packages, and the crontab files allow a user to be associated with the commands in them. This would not be affected by updates but is a well known location
  • place a file in /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly, or /etc/cron.monthly

It is recommended to add individual scripts in the cron directories instead of editing the user’s crontab, as it can get wiped when you update the cron package (link). A user’s crontab is stored under the /var/spool dircetory, which is considered a temporary/working directory and is likely to get deleted during an update

See if a cron has run

Edits to a user’s crontab and the cron jobs run are all logged by default to /var/log/syslog and that’s the first place to check if things are not running as you expect.

# search the /var/log/syslog for 'CRON' or 'crontab'
#cat /var/log/syslog | grep cron
grep CRON /var/log/syslog
grep -i CRON /var/log/syslog # will show results for both CRON and crontab
Aug 15 06:17:01 amiranzur CRON[14961]: (root) CMD (   cd / && run-parts --report /etc/cron.hourly)

By default cron will email you the output of any program it runs. Popular destinations for cron logs include /var/log/cron, /var/log/messages and /var/log/syslog

See if a user has access

  • If /etc/cron.allow file exists, user must be in it in order to run crontab
  • If /etc/cron.deny file exists, user must NOT be in it in order to run crontab
  • No cron.allow or cron.deny files exist in a standard Ubuntu install, so all users should have cron available by default, until one of those files is created.
  • If a blank cron.deny file has been created, that will change to the standard behavior users of other operating systems might expect: cron only available to root or users in cron.allow.

Absolute paths

One major pitfall to cron is cron runs in an extremely limited shell environment, as a result a lot of variables aren’t exported in to the environment, mainly $PATH. Make sure you use all absolute paths to executable, including common functions like echo, uptime, date, etc all need to use full paths (/bin/echo, /bin/date, /usr/bin/uptime). To determine the path to an executable, you can use the which command like so: which echo - this will show you the full path to that tool.

Or, you can expand root users PATH variable by putting the following line at the top of the root crontab file:

PATH=/usr/sbin:/usr/bin:/sbin:/bin

Emails and logging

  • By default cron will email you the output of any program it runs. Default email address is root@yourhost
  • You can use a MAILTO=... line in the crontab file to have cron send email to a specific address, which should make it easier to grep the mailer daemon logs
MAILTO=my.offsite.email@example.org
00 15 * * *  echo "Just testing if crond sends email"
  • You can set the cron to explicitly log output to a file by redirecting it (> /var/log/myjob.log 2>&1 will append all output to /var/log/myjob.log, 2>&1 indicates that the standard error (2>) is redirected to the same file descriptor that is pointed by standard output (&1).) You can also use &>> for the same purpose.
  • &>> works in Bash whereas 2>&1 works in normal shell.
  • You can specify the Shell in the crontab by adding SHELL=/bin/bash in the crontab -e file. It’ll work for most but not all cron implemetations.

  • If you’re not getting emails than check the system logs. Popular locations are /var/log/cron, /var/log/messages and /var/log/syslog. Use grep to get cron related stuff (cat /var/log/syslog | grep cron)

Examples

touch /etc/cron.daily/certbot

echo "
# Check and Renew Let's Encrypt SSLs 
# run twice a day (12:15am, 12:15pm) as per recommendation
15 0,12 * * * root /usr/bin/certbot renew" > /etc/cron.daily/certbot

chmod +x /etc/cron.daily/certbot

Troubleshooting

  • If you have recently changed the server’s timezone then you might need to restart the cron server so it would evaluate the cron times in the proper timezone