Nextcloud: Memory Caching, Redis, Cron Jobs, and Performance Tuning (Part 2)
Optimize your self-hosted Nextcloud instance for speed and reliability. Configure Redis caching, systemd cron tasks, and fine-tune PHP-FPM memory allocations.
Memory Caching: APCu and Redis Integration
A default Nextcloud installation performs hundreds of database queries and file lookups on every page request. Implementing memory caching reduces database read overhead and prevents file corruption from concurrent processes.
Local Cache: APCu
APCu (APC User Cache) is an in-memory key-value store for PHP. Because APCu is locked to the local PHP process space, it is highly efficient for single-server setups but cannot be used for file locking or distributed caching.
To configure APCu as your local cache, append the following line to /var/www/html/config/config.php:
'memcache.local' => '\OC\Memcache\APCu',
Ensure APCu is enabled for CLI commands, which is required for running Nextcloud's background cron jobs successfully. Edit your PHP configuration (/etc/php/8.3/mods-available/apcu.ini or similar):
extension=apcu.so
apc.enabled=1
apc.enable_cli=1
Distributed Cache and File Locking: Redis
For transactional file locking (preventing files from being written to by multiple processes simultaneously) and distributed caching (if scaling horizontally), Redis is required.
Option A: Connection via TCP
If your Redis instance runs in a separate Docker container on the same bridge network:
'memcache.distributed' => '\OC\Memcache\Redis',
'memcache.locking' => '\OC\Memcache\Redis',
'redis' => [
'host' => 'redis-container', // Docker service name or IP
'port' => 6379,
'timeout' => 0.0,
'password' => 'secure_redis_auth_token',
],
Option B: Connection via Unix Socket
For bare-metal, VM, or co-located container setups, connecting via a Unix socket avoids TCP overhead and increases throughput.
'memcache.distributed' => '\OC\Memcache\Redis',
'memcache.locking' => '\OC\Memcache\Redis',
'redis' => [
'host' => '/var/run/redis/redis-server.sock',
'port' => 0,
'timeout' => 0.0,
'password' => 'secure_redis_auth_token',
],
Ensure the web server user (www-data or nginx) has read/write permissions to the socket file:
usermod -aG redis www-data
chmod 770 /var/run/redis/redis-server.sock
Transitioning from AJAX to System Cron (via Docker)
Nextcloud's default "AJAX" cron execution triggers background tasks only when a user visits the web interface. For production instances, this creates noticeable latency for the active user and prevents background jobs (such as activity notifications, federated sharing synchronization, and cleanups) from executing when no users are logged in.
Navigate to Administration settings -> Basic settings -> Background jobs and switch the option to Cron.
Configured via Host Crontab to Docker Exec
If your Nextcloud instance is containerized, configure the host's crontab to execute the Nextcloud cron system inside the running container.
Edit the host crontab (crontab -e as root or a user with Docker privileges):
# Run Nextcloud system cron every 5 minutes
*/5 * * * * docker exec -u www-data nextcloud-app php -f /var/www/html/cron.php
Ensure the container name (nextcloud-app in this example) matches your actual container name.
Configured via systemd Service and Timer
Using systemd on the host system offers structured logging and prevents overlapping runs.
Create /etc/systemd/system/nextcloud-cron.service:
[Unit]
Description=Nextcloud Cron Job
After=docker.service
[Service]
Type=oneshot
ExecStart=/usr/bin/docker exec -u www-data nextcloud-app php -f /var/www/html/cron.php
[Install]
WantedBy=multi-user.target
Create /etc/systemd/system/nextcloud-cron.timer:
[Unit]
Description=Run Nextcloud Cron Job every 5 minutes
[Timer]
OnBootSec=5min
OnUnitActiveSec=5min
Unit=nextcloud-cron.service
[Install]
WantedBy=timers.target
Enable and start the systemd timer:
systemctl daemon-reload
systemctl enable --now nextcloud-cron.timer
PHP-FPM Process Manager & OPcache Tuning
Nextcloud relies heavily on PHP execution speed. Tuning the PHP-FPM process pool limits resource starvation while preventing the system from running out of RAM.
Adjusting PHP Memory Limits and OPcache (php.ini)
Open your active php.ini (e.g., /etc/php/8.3/fpm/php.ini or /usr/local/etc/php/conf.d/nextcloud.ini inside Docker) and apply the following parameters:
; Nextcloud minimum requirement is 512M; increase to 1G/2G for larger files and previews
memory_limit = 1024M
; OPcache performance optimization
opcache.enable = 1
opcache.enable_cli = 1
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 32
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 60
opcache.save_comments = 1
Tuning PHP-FPM pool settings (www.conf)
Edit your PHP-FPM pool configuration file (commonly /etc/php/8.3/fpm/pool.d/www.conf):
pm = dynamic
; Formula for max_children:
; max_children = (Total Available Server RAM - RAM for Database/OS) / Average PHP-FPM process size
; E.g., on a system with 8GB RAM, reserving 3GB for system/database:
; (5000MB) / 120MB per process = ~40 max_children
pm.max_children = 40
; Initial count of child processes on startup
pm.start_servers = 10
; Minimum spare child processes kept idle
pm.min_spare_servers = 5
; Maximum spare child processes kept idle
pm.max_spare_servers = 15
; Number of requests a child process handles before recycling to prevent memory leaks
pm.max_requests = 1000
Optimizing Preview Generation
Generating thumbnails on-the-fly causes massive CPU spikes when users open folders containing raw images or high-resolution graphics.
Restricting Preview Parameters (config.php)
Configure Nextcloud to limit preview resolution and disable unnecessary providers (such as PDFs, PSDs, or SVGs, which can be computationally expensive and expose security vulnerabilities).
Edit /var/www/html/config/config.php:
'enable_previews' => true,
'enabledPreviewProviders' => [
'OC\Preview\PNG',
'OC\Preview\JPEG',
'OC\Preview\GIF',
'OC\Preview\BMP',
'OC\Preview\MarkDown',
'OC\Preview\TXT',
],
'preview_max_x' => 1024,
'preview_max_y' => 1024,
'preview_max_filesize_image' => 50, // Ignore images larger than 50MB
Pre-Generating Previews
Pre-generating previews offloads processing from the web request cycle to background cron jobs.
- Install the Preview Generator App:
bash docker exec -u www-data nextcloud-app php occ app:enable previewgenerator - Run the Initial Generation: This step builds previews for all existing assets. It can take several hours depending on the size of your directory.
bash docker exec -u www-data nextcloud-app php occ preview:generate-all -v - Automate Continuous Generation: Add a dedicated host cron job to pre-generate previews for newly uploaded files:
cron # Pre-generate previews every 15 minutes */15 * * * * docker exec -u www-data nextcloud-app php occ preview:pre-generate -v