# Setting Up and Managing Cron Jobs

Source: https://support.kapsulehost.com/en-us/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:

1. Sign in to [KPanel](https://kpanel.kapsulehost.com) and click **Websites** in the left sidebar.
2. Click the site you want.
3. In the site's own menu, open **Settings**, 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.

![The Cron page for a site in KPanel, listing the scheduled jobs on that site](https://support.kapsulehost.com/help/screenshots/cron-jobs.13aef775.webp)

## 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 * * 1` runs 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.

> **Warning:** 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 **Settings**, 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
```

> **Tip:** 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:

1. Open the site, then the **WordPress** tab.
2. Open the **WP-Cron** section.
3. 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 **Settings**, then **File Manager**:

```php
define( 'DISABLE_WP_CRON', true );
```

**Add the real job.** In **Settings**, then **Cron**:

- Schedule: `*/5 * * * *`
- Label: `WordPress cron`
- Command: `cd ~/htdocs/yourdomain.co.nz && /usr/bin/wp cron event run --due-now`

> **Warning:** 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](https://support.kapsulehost.com/en-us/wordpress-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.

> **Important:** 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 KapsuleHost 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 **Settings**, then **SSH Keys** tab: see [Adding SSH Keys](https://support.kapsulehost.com/en-us/adding-ssh-keys).

> **Note:** 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.

> **Warning:** 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.** `*/5` is 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](https://support.kapsulehost.com/en-us/file-manager).

**WordPress tasks still run late.** Confirm both halves of the swap are in place: the schedule exists in **Settings**, 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](https://support.kapsulehost.com/en-us/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.
