DocsCron jobs

Cron jobs

Run PHP scripts, WP-CLI, Laravel's scheduler, Node.js scripts or any command on a schedule as the hosting account, and get their output by e-mail or in a log file.

Cron Jobs run commands on a schedule as the hosting account: a Laravel scheduler every minute, a nightly export, a PHP script that sends reminders. Each account has its own list. The system cron service keeps the schedule (in /etc/cron.d/zopanel-<user>) and starts each job as the account, with its permissions, inside the account's slice: the package's CPU, memory and process limits apply to cron jobs as they do to its websites.

Who can use it

Customers manage the cron jobs of their own account. Resellers and administrators choose the account with the picker at the top of the page. Website members do not have access.

Limit Value
Cron jobs per account Set by the package's Cron Jobs limit (0 = unlimited). The installer's Default package allows 20.
Feature A package can leave out Cron jobs; its customers then get "this feature is not included in your hosting package".
Command length 1,024 characters, one line.
Note 200 characters.

See Packages and limits.

Create a cron job

  1. Open Cron Jobs in the menu. Administrators and resellers: choose the account.
  2. Click New cron job.
  3. Choose a Frequency, or Custom to type your own schedule (see below).
  4. Check the Schedule field. It shows the five-field expression of the chosen frequency.
  5. Enter the Command, with absolute paths (see Commands).
  6. Optionally add a Note to remember what the job does.
  7. Click Save. The schedule is updated at once.

To change a job, click the pencil icon, edit it in Edit cron job and click Save. The Enabled switch pauses a job without deleting it. The trash icon deletes it after Delete this cron job?.

Schedule syntax

A schedule has five fields separated by single spaces:

┌───────── minute (0-59)
│ ┌─────── hour (0-23)
│ │ ┌───── day of month (1-31)
│ │ │ ┌─── month (1-12)
│ │ │ │ ┌─ day of week (0-7, 0 and 7 are Sunday)
│ │ │ │ │
* * * * *

Each field accepts numbers and * (any), , (list), - (range) and / (step). Names such as MON or JAN are not accepted.

Frequency Schedule
Every minute * * * * *
Every 5 minutes */5 * * * *
Every hour 0 * * * *
Every day (00:00) 0 0 * * *
Every week (Sunday) 0 0 * * 0
Every month 0 0 1 * *
Every 15 minutes */15 * * * *
03:30 every day 30 3 * * *
Every 2 hours on weekdays 0 */2 * * 1-5
1st and 15th of the month at 06:00 0 6 1,15 * *

The shortcuts @hourly, @daily, @weekly, @monthly, @yearly and @reboot are also accepted. Times are the server's local time zone.

Note: when both day of month and day of week are restricted (neither is *), cron runs the job when either one matches.

Commands

Commands run with /bin/bash, as the hosting account, starting in its home directory (/home/<account>, which ~ also stands for). The PATH is only /usr/local/bin:/usr/bin:/bin, so give full paths to programs and files.

Important: a command cannot contain a line break or the % character (cron would treat % as a line break). For anything longer, or for date +%F, put the commands in a script and run the script:

bash /home/alice/scripts/nightly.sh

PHP

Use the binary of the PHP version your site runs, for example /usr/bin/php8.3:

/usr/bin/php8.3 /home/alice/domains/example.com/public_html/cron.php

WordPress (WP-CLI)

wp-cli is installed at /usr/local/bin/wp. Run it with your site's PHP version and its folder:

/usr/bin/php8.3 /usr/local/bin/wp --path=/home/alice/domains/example.com/public_html transient delete --expired

For WordPress's own scheduled tasks, do not add a cron job: see WordPress scheduled tasks.

Laravel scheduler

Laravel needs one entry that runs schedule:run every minute (schedule * * * * *):

cd /home/alice/domains/example.com/public_html && /usr/bin/php8.3 artisan schedule:run >> /dev/null 2>&1

For a Laravel site deployed from Git, use the live release folder domains/<domain>/current instead of public_html. See Git deployments.

Node.js

Node.js is not on cron's PATH. Use the full path of an installed version under /opt/zopanel/runtimes/node/<major>/bin:

cd /home/alice/scripts && /opt/zopanel/runtimes/node/22/bin/node report.js

Calling a URL

curl -fsS --max-time 60 https://example.com/tasks/run > /dev/null

Running the script directly with PHP is usually better: it is not limited by the web server's timeouts and does not use a PHP worker that visitors need.

Output and logs

The panel does not keep a run history. Choose where the output goes:

  • E-mail the output: at the top of the page, enter an address and click Save. Everything a job prints (standard output and errors) is e-mailed to that address after each run. The setting applies to all jobs of the account. Leave it empty to discard output. Sending needs a working mail server on this server (see Email).

  • Silence a job: end its command with > /dev/null 2>&1.

  • Write a log file: append the output to a file in the account's logs folder and read it in the File Manager:

    /usr/bin/php8.3 /home/alice/domains/example.com/public_html/cron.php >> /home/alice/logs/cron-example.log 2>&1
    

    A file you append to keeps growing and counts toward the account's disk space. Use > instead of >> to keep only the last run.

To test a command, run it once in the terminal with the same full paths before you schedule it.

WordPress scheduled tasks

WordPress has its own scheduler (wp-cron) for scheduled posts, shop e-mails and plugin jobs. On the website's WordPress tab, Maintenance card, Server runs scheduled tasks (every 5 min, not on visits) makes the server run them every 5 minutes with wp-cli. This is on by default for WordPress installed by ZoPanel.

These runs use a separate system timer: they do not appear in Cron Jobs and do not count toward the cron job limit. Do not also add a cron job that calls wp-cron.php, or the tasks run twice. See WordPress Toolkit.

Suspension and migration

  • While an account is suspended, its cron jobs do not run. They are put back when the account is resumed.
  • Cron jobs in cPanel and DirectAdmin backups are imported with the account (up to 100). See Migrating to ZoPanel.

Troubleshooting

Message or symptom What to do
"cron job limit reached (20)" The package allows no more jobs. Delete one, combine several in a script, or raise the package's Cron Jobs limit.
"schedule must have 5 fields separated by single spaces" Use exactly five fields, or one of the @ shortcuts.
"invalid schedule field …" A field contains something other than digits, *, ,, - and / (for example MON). Use numbers.
"invalid cron command (no newlines or % allowed)" Remove % and line breaks: move the commands into a script.
"invalid e-mail address" Enter one plain address, without spaces or quotes.
"this feature is not included in your hosting package" The package leaves out Cron jobs. Ask your provider.
The e-mail says "command not found" Use the full path, for example /usr/bin/php8.3 or /opt/zopanel/runtimes/node/22/bin/node.
The e-mail says "Permission denied" for a script Run it through its interpreter (bash script.sh, /usr/bin/php8.3 script.php) or give it execute permission.
The job runs at an unexpected hour Schedules use the server's time zone, not yours.
No e-mail arrives The job printed nothing, the address is empty, or the server has no working mail server. Write to a log file instead.
The job works in the terminal but not in cron Cron has a minimal PATH and no shell profile. Use full paths and cd to the right folder first.
A heavy job is slow or stops halfway ("Killed") Cron jobs share the package's CPU, memory and process limits with the account's websites. Run heavy jobs at a quiet hour, split them, or raise the package's limits.

← File Manager SSH access and terminal →