I needed to set up a cron job for a client today on a Media Temple DV 4 server. I hadn’t set one up on a DV 4 server before but I figured it would be straightforward like setting one up on DV 3.5. I couldn’t get it to work the “recommended way” so I jumped on the command line to sort it out. This is my approach for getting a cron job working on DV 4.
First, cron jobs should ideally be created using the Scheduled Tasks tool found in Plesk. Under the Websites & Domains tab click the “show advanced operations” link to disclose more options. Scheduled Tasks should be there as an option and if you click through and then click the system user you can add a new task, fill in the details and away you go.
Problem is, it didn’t work. I set up the cron job accurately but it wouldn’t execute. Not only that, the cron log wasn’t listing any errors. I had to dig a little deeper and to do that I ssh’d on to the server as the root user.
An important tool for monitoring cron jobs is the cron log. You can view the end of cron log by issuing the following command:
tail /var/log/cron
This will show a line for every cron job that has been recently executed. Plesk sets up a few jobs for the root user to run so you should see those in there as jobs the cron daemon (crond) has executed as (root). If you set up a cron job through Plesk’s scheduled task tool you should also see the jobs logged.
An interesting (and perhaps crucial) thing to note is that cron jobs aren’t all executed as (root) but by the user that added the job to the system. This is important because cron tasks are executed with the permissions of the the user who created the task. It is quite possible that the commands I was asking cron to run could not be executed by the system username user due to permissions problems. However, I spent an hour trying different chown and chmod permission combinations trying to get my shell script and the commands therein to work for the system username and I found no joy.
As an aside I want to describe how I structure cron jobs in general. First, I create a bash shell script and put it below the webroot. I usually name it _cron.sh and I create it through the ftp. A very straightforward example of the shell script follows:
#!/bin/bash
/usr/bin/curl http://www.domain.com/_cron.php
The first bit is the bash shell shebang that dictates what language the script is written for and the second line is a command line command that calls a php file on my server. Now, I use curl to actually call the page using HTTP. I know some people use command line php and that works great too but I like using curl because I usually have the _cron.php file doing some work in the CMS and it’s best structured as a web page rather than a command line script. Inside _cron.php, to test, I insert the current time into a test database so that I can have some evidence that the code executed. When the cron job is working fine I re-write _cron.php to do whatever I want.
I like this approach for two reasons. First, you can change the PHP file or the shell script without having to stop and start the cron daemon or create a new job. Second, it’s easy to test each step. You can test the _cron.php script by visiting it in a browser to see if it works. Next, you can call the shell script direct from the command line and see if that works. Finally, you can have the cron job fire and see if it all works. If the code doesn’t work somewhere along the line you can pinpoint where the problem is. Case in point, when I was trying to use scheduled tasks to do the database insert, the problem was with the since the command line and browser visits worked fine.
Back to the DV 4. Plesk keeps the crontab, or list of all cron jobs, in a file unique to every user. The files can be found in /var/spool/cron. There is a file for root that lists all the root jobs and a file for every other user that has jobs (including the system username user if you created a scheduled task through Plesk). Listing the contents of these files is not very illuminating but it does demonstrate that the cron job created by scheduled tasks is well formed and ready to be executed by the cron daemon. This is what was so frustrating about Scheduled Tasks, everything looks right, it just doesn’t work.
So, what to do? I was pretty fed up after a couple of hours of head scratching and I decided that since root’s cron jobs were running just fine I would move my job over to root. To do this I needed to edit the root crontab by issuing the following command (when ssh’d in as root):
crontab -e
This opens root’s crontab in vi. Insert a new line after the last cron job and enter the new job’s information:
* * * * * /var/www/vhosts/domain.com/_cron.sh
A brief refresher on cron syntax. The asterisk means ‘all’ so this cron job will actually run every minute. This is good for testing since you’ll want to see results right away. Every asterisk is separated by a tab not just spaces. The command is an absolute path to the shell script I mentioned earlier. Do not hit return after adding this line (i.e. don’t add an empty line at the end of the crontab). Save and quit vi.
Now that the root crontab has been changed you’ll need to restart the cron daemon:
/etc/init.d/crond restat
One thing, chmod the cron shell script so that it can be executed by root:
chmod 744 /var/www/vhosts/domain.com/_cron.sh
After all this the cron job should start executing. In my example it means that every minute I see a new row being inserted into my test database table. This means that cron is properly calling my _cron.sh shell script and the shell script is properly curling my _cron.php file. Everything is right with the world.
Finally, edit root’s crontab again and change the frequency of the cron job (unless you really want it to fire every minute). My code, for example, fires once a day to clean some database stuff up. I have it fire at 4:01 AM:
1 4 * * * /var/www/vhosts/domain.com/_cron.sh
While this isn’t the best way to get a cron job working and I am disappointed that I couldn’t figure out scheduled tasks I am pleased with the result and I hope this helps someone out.