Fix ownCloud Cron Job Not Running: Set Up a Reliable systemd Timer

You open ownCloud’s admin page and see that background jobs have not run recently, or cleanup, activity, external-storage, and other queued tasks seem delayed. A common reaction is to edit cron.php or add another crontab entry. On current ownCloud Server documentation, that is not the best starting point: ownCloud recommends the Cron background mode and the occ system:cron command. A systemd timer can provide the scheduling layer instead of traditional crontab on a Linux host.

This guide focuses on a package or bare-metal style installation where ownCloud lives under a path such as /var/www/owncloud. If you use ownCloud’s official Docker image, stop before creating a host timer: ownCloud documents that the image already configures cron internally, controlled by variables such as OWNCLOUD_CROND_ENABLED and OWNCLOUD_CROND_SCHEDULE. See the current ownCloud background jobs documentation.

What is verified, what depends on your server, and what still needs checking

  • Verified: ownCloud recommends Cron rather than AJAX for reliable background execution, and documents occ system:cron as the command to execute queued background jobs.
  • Depends on your installation: the ownCloud directory, PHP binary, web-server account, PHP environment, and whether you run a package install, container, appliance, or custom deployment.
  • Not knowable from a generic guide: why your current job failed. It may be a scheduler problem, but it can also be permissions, a wrong path, a different PHP CLI configuration, database connectivity, file locking, or an application-level background job failure.

Action: do not create a timer until the exact ownCloud command works manually under the same account that the timer will use.

Step 1: Confirm Cron mode and test ownCloud manually

For a typical Apache/Debian-style installation, the web user is www-data. Replace both the user and path if your environment differs.

sudo -u www-data /var/www/owncloud/occ background:cron
sudo -u www-data /var/www/owncloud/occ system:cron

The first command selects ownCloud’s Cron background-job mode. The second actually runs queued background jobs. ownCloud’s occ command documentation states that system:cron is intended for scheduled execution and that progress output should not be enabled in a non-interactive scheduler.

Ubuntu terminal illustrating ownCloud Cron mode and a manual occ system:cron execution as the www-data user
A manual check should succeed before systemd is involved. The exact output can vary; the important test is the command’s exit status and absence of application errors.

Common misunderstanding: “Cron mode” in ownCloud does not mean you must use the cron daemon specifically. It means ownCloud expects an external scheduler to invoke its background-job runner. A systemd timer can be that scheduler.

Action: if the manual command fails, fix that error first. A timer will only repeat the same failure on a schedule.

Step 2: Find the correct PHP and ownCloud paths

Some installations make occ executable directly; others are more predictable when invoked with the PHP CLI binary. Confirm both:

command -v php
readlink -f /var/www/owncloud/occ
sudo -u www-data /usr/bin/php -f /var/www/owncloud/occ system:cron

ownCloud’s documentation explicitly warns that scheduled jobs need to find PHP and therefore shows full paths in cron examples. This matters just as much under systemd because services receive a controlled environment rather than your interactive shell environment.

Action: replace /usr/bin/php, /var/www/owncloud, and www-data in the remaining examples with the values that worked on your host.

Step 3: Create a oneshot systemd service

Create /etc/systemd/system/owncloud-cron.service:

[Unit]
Description=Run ownCloud background jobs
After=network.target

[Service]
Type=oneshot
User=www-data
Group=www-data
WorkingDirectory=/var/www/owncloud
ExecStart=/usr/bin/php -f /var/www/owncloud/occ system:cron

You normally do not need an [Install] section for the service because the timer activates it. Keeping the service as Type=oneshot also makes its lifecycle easy to interpret: it starts, runs the command once, exits, and becomes inactive again.

Ubuntu terminal showing an owncloud-cron.service unit with Type=oneshot, www-data, WorkingDirectory, and occ system:cron
The systemd service should call the same command that already succeeded manually, using explicit paths and the web-server account.

Common misunderstanding: an inactive oneshot service is not automatically broken. After a successful run, a oneshot service without RemainAfterExit=yes normally becomes inactive.

Action: judge success by the exit code and journal, not by expecting this service to remain “running.”

Step 4: Create the systemd timer

Create /etc/systemd/system/owncloud-cron.timer:

[Unit]
Description=Run ownCloud background jobs every 15 minutes

[Timer]
OnCalendar=*:0/15
Persistent=true
Unit=owncloud-cron.service

[Install]
WantedBy=timers.target

ownCloud’s host-cron documentation recommends a 15-minute schedule. The timer above follows that cadence. Persistent=true is useful with an OnCalendar timer because systemd can trigger a missed calendar activation after the machine becomes available again. Exact behavior still depends on systemd version and how long the machine was down.

GNU nano window showing an owncloud-cron.timer unit with OnCalendar every 15 minutes, Persistent true, and the owncloud-cron service
A calendar timer can mirror ownCloud’s documented 15-minute cron cadence while keeping scheduling and logging inside systemd.

Action: if you intentionally need a different interval, change it deliberately rather than copying a value from another server. More frequent execution can increase background load; less frequent execution can delay queued work.

Step 5: Reload systemd and enable the timer

sudo systemctl daemon-reload
sudo systemctl enable --now owncloud-cron.timer
sudo systemctl status owncloud-cron.timer

daemon-reload makes systemd reread unit files. enable --now both enables the timer for future boots and starts it immediately.

Ubuntu terminal showing systemctl daemon-reload, enable --now owncloud-cron.timer, and an active waiting timer status
An enabled timer should normally show active (waiting) and identify the service it will trigger.

Action: if the timer is not active, inspect systemctl status owncloud-cron.timer before changing the ownCloud configuration again.

Step 6: Verify the next and previous timer runs

systemctl list-timers owncloud-cron.timer
systemctl list-timers --all | grep owncloud-cron

list-timers is the quickest way to confirm that systemd has scheduled a next activation and to see when the timer last fired. This distinguishes “the timer never ran” from “the timer ran but ownCloud failed inside the service.”

Ubuntu terminal showing owncloud-cron.timer enabled and a list-timers entry with previous and next activations
The timer list should show both the timer unit and the service it activates, along with timing information.
Ubuntu terminal showing systemctl list-timers for owncloud-cron.timer with NEXT, LAST, UNIT, and ACTIVATES columns
Use the NEXT and LAST columns to verify scheduling instead of assuming the absence of visible web activity means cron is broken.

Action: if NEXT is missing or the timer is not listed, recheck the timer filename, [Install] section, and whether the unit was enabled.

Step 7: Check the service journal, not just the timer

systemd records service output in the journal unless you deliberately redirect it elsewhere. The official journalctl documentation describes filtering journal entries by systemd unit.

sudo journalctl -u owncloud-cron.service --since today
sudo journalctl -u owncloud-cron.service -n 100 --no-pager
Ubuntu terminal showing journalctl logs for owncloud-cron.service with start, background processing, and finished entries
The service journal is where scheduler success and ownCloud command failures separate: a timer may fire correctly even when the invoked command returns an error.

Common misunderstanding: “The timer is active, so ownCloud cron works.” An active timer only proves the scheduler is waiting to fire. You still need a successful service invocation.

Action: look for PHP errors, permission denied messages, missing files, database errors, or a nonzero exit status. Fix the first concrete error rather than repeatedly restarting the timer.

Step 8: Trigger one run on demand and verify ownCloud

You do not need to wait 15 minutes for a final test:

sudo systemctl start owncloud-cron.service
sudo systemctl status owncloud-cron.service
sudo -u www-data /usr/bin/php -f /var/www/owncloud/occ status

After a successful oneshot run, systemctl status can legitimately report the service as inactive while also showing status=0/SUCCESS. The important result is that the command completed successfully.

Ubuntu terminal showing ownCloud occ status, a manual systemctl start of owncloud-cron.service, and status 0 SUCCESS
A manual service start is a practical end-to-end test of the exact command, user, paths, and PHP environment configured in systemd.

Action: after the manual service test succeeds, wait for at least one scheduled timer activation and confirm a new journal entry appears without manual intervention.

If it still does not run: troubleshoot by layer

Observed symptomWhat it provesNext action
occ system:cron fails manuallyThe problem is below the scheduler layerFix PHP, permissions, ownCloud configuration, database, or application errors first.
Manual command works, but service failsYour systemd execution environment differs from the shellCheck User=, WorkingDirectory=, full paths, and the journal.
Service works manually, timer has no NEXT runThe service is valid; scheduling is notCheck the timer syntax, reload systemd, then enable and start the timer.
Timer has NEXT/LAST times, but ownCloud jobs still lagThe timer is firingInspect service logs and application-level jobs rather than creating another scheduler.
Official Docker imageHost systemd may be the wrong layerUse the image’s built-in cron configuration documented by ownCloud.

A note about cron.php and older guides

Older ownCloud instructions often invoke cron.php directly. Current ownCloud documentation recommends occ system:cron, and ownCloud release notes explain the migration away from the older direct cron.php approach. See the ownCloud Server release notes.

Action: if you inherited an old crontab or systemd unit that runs cron.php, compare it with the documentation for your installed ownCloud release before keeping it.

Final verification checklist

  • ownCloud is configured for Cron background jobs.
  • The exact occ system:cron command succeeds under the intended web-server account.
  • owncloud-cron.timer is enabled and active (waiting).
  • systemctl list-timers shows both a next and previous activation after enough time has passed.
  • journalctl -u owncloud-cron.service shows successful scheduled executions.
  • The setup does not duplicate cron already supplied by the official ownCloud Docker image or another scheduler.

When those checks all pass, you have verified more than “a timer exists”: you have shown that systemd schedules the job, invokes ownCloud under the right account, and completes the actual background-job runner successfully.

Leave a Comment

7 Best WSUS Tools for Update Management and Troubleshooting

7 Best WSUS Tools for Update Management and Troubleshooting

Compare seven tools that support or complement WSUS, from Microsoft’s native console and diagnostics to third-party patch publishing and remote deployment.

Best Windows System Monitoring Tools: 6 Picks for Server Visibility

Best Windows System Monitoring Tools: 6 Picks for Server Visibility

Compare six Windows system monitoring tools for server health, application visibility, and alerting, with current notes on deployment and licensing.

7 Wake-on-LAN Tools: What’s Still Available From the 2021 List

7 Wake-on-LAN Tools: What’s Still Available From the 2021 List

Compare seven Wake-on-LAN tools by features and availability, including free utilities, network-admin suites, and 2021 picks that have since been retired.

9 Best Ping Tools for Testing Latency and Scanning a Network

9 Best Ping Tools for Testing Latency and Scanning a Network

Compare nine ping tools for quick reachability checks, subnet discovery, TCP tests, and latency monitoring, with guidance on which one fits your network task.

Best TFTP Servers for Windows, Linux, and macOS

Best TFTP Servers for Windows, Linux, and macOS

Compare the best TFTP servers for Windows, Linux, and macOS, including SolarWinds, Tftpd64, tftpd-hpa, atftpd, haneWIN, and dnsmasq.

5 Best Microsoft Access Alternatives for Desktop and Web Databases

5 Best Microsoft Access Alternatives for Desktop and Web Databases

Compare five Microsoft Access alternatives for desktop, SQLite, no-code, and browser-based database work, with strengths, limits, and best-fit use cases.

Open-Source vs. Closed-Source Monitoring Tools Compared

Open-Source vs. Closed-Source Monitoring Tools Compared

Compare open-source and closed-source monitoring tools by cost, support, customization, security, and current options including Zabbix, Nagios, PRTG, and more.

Ingress vs. Egress: What’s the Difference in Networking?

Ingress vs. Egress: What’s the Difference in Networking?

Understand how ingress and egress describe incoming and outgoing traffic, why direction depends on the network boundary, and how to monitor bandwidth and spot risky data transfers.

6 Best Free Syslog Servers to Try for Centralized Logging

6 Best Free Syslog Servers to Try for Centralized Logging

Compare six free syslog servers and collectors for Windows and Linux, including GUI tools, open-source options, search, alerting, and secure transport.

What Is IIS? Microsoft’s Windows Web Server and Alternatives

What Is IIS? Microsoft’s Windows Web Server and Alternatives

See what Microsoft IIS does, how its request pipeline and application pools work, and when Apache, NGINX, or Caddy may fit your web server needs better.