Websites
Setting Up and Managing Cron Jobs
A cron job runs a command on a schedule, in the background, whether or not anyone is visiting your site. This guide covers adding one in KPanel, writing the schedule and the command correctly for this platform, replacing WordPress's unreliable built in scheduler, and finding the output when a job does not do what you expected.
Where Cron Lives in KPanel
Cron belongs to a site, so you reach it from the site rather than from the main menu:
- Sign in to KPanel and click Websites in the left sidebar.
- Click the site you want.
- In the site's own menu, open Advanced, then Cron.
The direct address is /websites/<site-id>/cron. You will see a table of existing jobs, or an empty state if the site has none.

Adding a Job
Click Add Cron Job at the top right. The form has three fields.
Schedule
Six preset buttons fill the expression for you:
| Button | Expression |
|---|---|
| Every minute | * * * * * |
| Every 5 min | */5 * * * * |
| Every hour | 0 * * * * |
| Daily 2AM | 0 2 * * * |
| Weekly Sunday | 0 2 * * 0 |
| Monthly 1st | 0 2 1 * * |
Or type your own into Cron expression. The five fields, in order, are minute, hour, day of month, month, day of week:
minute hour day-of-month month day-of-week
0 3 * * *runs at 3:00 am every day.*/15 * * * *runs every fifteen minutes.0 9 * * 1runs at 9:00 am every Monday.30 1 1 * *runs at 1:30 am on the first of each month.0 */6 * * *runs every six hours, on the hour.
Label
A name you will recognise later, such as WordPress cron or Nightly stock sync. It is what the jobs table shows you, so make it descriptive: job 3 helps nobody at 2 am.
Command
The shell command to run. Click Save to create the job.
Use full paths. Cron runs with a minimal environment and none of your shell profile, so a bare php or a relative directory that works when you are logged in over SSH will fail silently here. Write out the whole path, every time.
Writing the Command
Jobs run as your site's own system user, so your home directory is the right anchor and ~ resolves correctly. Your site's files live at:
~/htdocs/yourdomain.co.nz
You can confirm the exact path on the site's Files, then SFTP tab, which prints it under Site files.
Typical commands:
cd ~/htdocs/yourdomain.co.nz && /usr/bin/wp cron event run --due-now
cd ~/htdocs/yourdomain.co.nz && /usr/bin/php bin/send-queued-emails.php
/usr/bin/curl -fsS https://yourdomain.co.nz/api/nightly-report
Test the command before you schedule it. Paste it into the site's WordPress, then Console section if it is a wp command, or run it over SSH. A job that was never going to work is much easier to spot at the prompt than at 3 am in a log file.
Replacing WordPress's Built In Scheduler
WordPress ships with its own pseudo-scheduler, WP-Cron, which only fires when someone loads a page. On a quiet site, scheduled posts publish late and emails queue up unsent. On a busy site, every visitor pays the cost of checking the schedule.
A real cron job fixes both. KPanel does the whole swap for you:
- Open the site, then the WordPress tab.
- Open the WP-Cron section.
- Click Enable system cron.
That adds a schedule that runs WP-Cron every five minutes and sets DISABLE_WP_CRON so page loads stop triggering it as well. Remove system cron on the same screen reverses both halves.
If you would rather do it by hand, it is two steps:
Disable the visitor triggered version. Add this to wp-config.php, above the /* That's all, stop editing! */ line, using Files, then File Manager:
define( 'DISABLE_WP_CRON', true );
Add the real job. In Advanced, then Cron:
- Schedule:
*/5 * * * * - Label:
WordPress cron - Command:
cd ~/htdocs/yourdomain.co.nz && /usr/bin/wp cron event run --due-now
Do not skip the DISABLE_WP_CRON half. With both running, every scheduled task can fire twice: duplicate emails, duplicate order processing, duplicate charges on a subscription plugin. Use the one click action in the WP-Cron section and this cannot happen to you.
WooCommerce and Background Queues
WooCommerce uses a background queue for order status changes, subscription renewals, emails and stock updates. It relies on WP-Cron, so it is exactly the workload that suffers on a quiet store.
Once the real schedule is in place, the queue is processed every five minutes. Watch it at WooCommerce, then Status, then Scheduled Actions in wp-admin.
A high volume store can move to */2 * * * *. Going below that rarely helps: you spend more time starting processes than doing work. See Setting Up WooCommerce.
Managing Existing Jobs
The jobs table shows Label, Schedule, Command, Last run and Status, with two actions on each row:
- Disable pauses a job without deleting it, and turns into Enable to bring it back. Use this when you are testing whether a job is causing a problem.
- Delete removes it permanently. You are asked to confirm, and scheduled runs stop immediately.
Deleting a cron job cannot be undone. The schedule is removed from the server there and then. If you are only trying to stop it temporarily, use Disable.
Finding the Output
Every job Kapsule creates has its output captured for you. Standard output and errors are appended to a log file in a cron-logs directory in your site user's home directory, one file per job.
That log is the answer to almost every "did my job run?" question, because it records what the command printed and any error it raised.
To read it, connect over SSH and look in ~/cron-logs/. SSH uses key authentication, so add your public key first from the site's Files, then SSH Keys tab: see Adding SSH Keys.
The File Manager and SFTP accounts are confined to your site directory, ~/htdocs/yourdomain.co.nz, and cron-logs sits one level above it. That is deliberate: it keeps a contractor with SFTP access out of everything except the website. Use native SSH to reach the logs, or redirect output into your site directory as shown below.
If you would rather have the output somewhere the File Manager can open, redirect it yourself:
cd ~/htdocs/yourdomain.co.nz && /usr/bin/wp cron event run --due-now >> ~/htdocs/yourdomain.co.nz/wp-content/cron.log 2>&1
2>&1 sends errors to the same file as normal output. Without it, errors go nowhere.
Anything inside your site directory can potentially be requested over the web. Put a redirected log under wp-content rather than at the site root, give it a name nobody would guess, and delete it once you have finished debugging.
Good Practice
- Stagger your schedules. Six jobs all set to
0 2 * * *all start at once. Spread them:0 2,10 2,20 2. - Do not use every minute unless you truly need it.
*/5is enough for almost everything, including WordPress and WooCommerce. - Keep jobs short. A job that takes longer than its interval will overlap with the next run.
- Redirect output for anything noisy, so one chatty job does not fill your disk.
- Review the list occasionally. Jobs left behind from a plugin you removed keep running.
Troubleshooting
The job never seems to run. Check the path first. Open the log file. Then confirm the status is Active and not Disabled. Then run the same command over SSH and see what it says.
"command not found" in the log. A missing full path. Use /usr/bin/php, /usr/bin/wp, /usr/bin/curl rather than the bare name.
Permission denied. The job runs as your site's system user. That user needs to own, or at least be able to read, everything the command touches. Check permissions in Using the File Manager.
WordPress tasks still run late. Confirm both halves of the swap are in place: the schedule exists in Advanced, then Cron, and DISABLE_WP_CRON is set. The WP-Cron section on the WordPress tab shows the current state of both.
The job runs but the site is slow while it does. Move it to a quieter hour, or split the work into smaller batches. Site level resource use is visible under Performance: see Improving Website Speed.
A job stopped working after a plugin update. The command path may have changed. Check the log, then update the command from the jobs table by deleting the old job and adding a corrected one.