Cron Setup Deep-Dive
The [Scheduled Tasks](/docs/automation/scheduled-tasks) page covers the concept. This page is the hands-on reference: exactly how to install cron on every hosting environment, how to verify it works, and what happens if you never set it up.
You don't have to set up cron
As of v2.26.0, scheduled publishing works out of the box with no cron job at all. jekcms keeps a "next job due" timestamp and runs the publishing engine right after a page response has been delivered to a visitor — a post scheduled for 14:37 goes live on the first visit at or after 14:37, and that visitor never waits for it. This is the same model WordPress uses, but deterministic instead of probabilistic: on a normal request it costs one or two tiny file reads and nothing else.
The one honest limitation is shared with WordPress: with literally zero visits (not even your own admin sessions), nothing can fire. If your site is brand new and unvisited, or you want to-the-minute precision guaranteed, set up a real cron below — when a real cron is configured, the visitor-triggered scheduler detects it and switches itself off completely. To force it off regardless, define JEK_DISABLE_PSEUDO_CRON as true in your config.
Recommended interval
Set cron to run cron.php every 1 minute. Every 5 minutes is acceptable for low-traffic sites but introduces visible delay on scheduled publishes (a post set to go live at 10:00 might actually appear at 10:04).
Every 15+ minutes is too slow for the AI bulk worker — rate limiting stalls, and users watching a batch progress page will think it's frozen.
cPanel
Most shared hosts use cPanel. Log in and go to Advanced → Cron Jobs.
Under Add New Cron Job:
- Common settings: Once per minute (or pick a preset)
- Command:
/usr/bin/php /home/YOURUSER/public_html/cron.php >/dev/null 2>&1
If /usr/bin/php doesn't exist on your host, try /usr/local/bin/php, /opt/cpanel/ea-php82/root/usr/bin/php, or whatever your host documents. Run which php in cPanel's Terminal if you have shell access.
The >/dev/null 2>&1 silences output — without it, cPanel emails you every minute.
Plesk
Tools & Settings → Scheduled Tasks → Add Task.
- Task type: Run a command
- Command:
php /var/www/vhosts/yourdomain.com/httpdocs/cron.php - Run: Every minute
- Send notifications: "Only on errors" (otherwise inbox flood)
Click Run Now once after creating — confirms the command works before you wait for the first tick.
DirectAdmin
Advanced Features → Cron Jobs.
* * * * * /usr/bin/php /home/USER/domains/yourdomain.com/public_html/cron.php >/dev/null 2>&1
Same format as cPanel. DirectAdmin's interface is uglier but the concept is identical.
Linux server (crontab)
On a VPS or dedicated box, edit the web user's crontab — not root:
sudo -u www-data crontab -e
(or nginx, apache, whichever user owns the install)
Add:
* * * * * cd /var/www/jekcms && /usr/bin/php cron.php >> storage/logs/cron.log 2>&1
The cd first is important — some PHP includes assume the working directory is the install root. The log redirect gives you a breadcrumb trail when debugging.
Linux + systemd timer
If you prefer systemd over crontab, create two files.
/etc/systemd/system/jekcms-cron.service:
[Unit]
Description=jekcms cron tick
[Service]
Type=oneshot
User=www-data
WorkingDirectory=/var/www/jekcms
ExecStart=/usr/bin/php cron.php
/etc/systemd/system/jekcms-cron.timer:
[Unit]
Description=Run jekcms cron every minute
[Timer]
OnCalendar=*:0/1
Persistent=true
[Install]
WantedBy=timers.target
Then:
sudo systemctl daemon-reload
sudo systemctl enable --now jekcms-cron.timer
systemctl list-timers | grep jekcms
Advantages over crontab: proper journal logs (journalctl -u jekcms-cron), survives reboots cleanly, no per-user crontab confusion.
Windows Task Scheduler
For XAMPP / WAMP / IIS installs.
- Open Task Scheduler → Create Task (not "Basic" — you need the full dialog for the minute trigger)
- General: name "jekcms cron", check Run whether user is logged on or not
- Triggers → New: Daily, start today, repeat every 1 minute for a duration of 1 day, check Enabled
- Actions → New:
- Program: C:\xampp\php\php.exe - Arguments: C:\xampp\htdocs\jekcms\cron.php - Start in: C:\xampp\htdocs\jekcms
- Conditions: uncheck Start only if on AC power (otherwise it stops on laptops)
- Settings: check Run task as soon as possible after a scheduled start is missed
Save. Right-click the task → Run to confirm it fires manually before relying on the schedule.
Verifying cron is actually running
Three independent checks:
- Admin UI — open Automation → Scheduled Tasks. Every built-in row should have a
last_run_atwithin the last minute or two. If everything shows hours ago, cron isn't running. - Log file — if you redirected stdout to
storage/logs/cron.log, tail it:
tail -f storage/logs/cron.log
You should see fresh output every minute. No output means cron isn't calling cron.php.
- DB query — direct sanity check:
SELECT name, last_run_at, TIMESTAMPDIFF(SECOND, last_run_at, NOW()) AS age
FROM scheduled_tasks
ORDER BY age DESC;
If age on any task is older than its interval_seconds, cron is broken (or that task is stuck).
What happens if cron never runs
jekcms has a fallback: the sparse web-request tick. On roughly 2% of front-end page requests, the bootstrap code fires a mini-scheduler that runs one overdue task and returns. This is intentionally probabilistic — you can't rely on it for time-sensitive work, but it prevents a site with no cron from accumulating an infinite unsent-webhook queue.
Practical consequences of relying on the fallback:
- Low-traffic site (<50 visits/day): the fallback almost never fires. Scheduled publishes sit in
scheduledstate forever. Set up real cron. - Medium-traffic (100–1000 visits/day): most tasks tick within a reasonable window, but the AI bulk worker is painfully slow
- High-traffic (10k+ visits/day): fallback is frequent enough that the site feels almost normal — but the instant traffic dips, things stall
The fallback exists as a safety net, not a design. If you're building anything beyond a hobby site, install real cron.