Your Nextcloud Works. Now Make It Not Embarrassing.
A default Nextcloud install is functional but rough around the edges. The performance warnings in the admin panel are nagging you. File uploads feel slower than they should. You have no backup strategy. Federation — sharing files with users on other Nextcloud instances — sounds interesting but you’ve never touched it.
This is the article for after the install guide. The part where you tune the thing, automate the backups, set up federation properly, and learn what the occ command can actually do.
Redis for Caching: The Single Biggest Performance Win
By default, Nextcloud uses filesystem-based locking and no APCu memory caching. This means file locking goes through the database (slow), and every page load re-computes things that could be cached (slower).
Adding Redis for file locking and APCu for memory caching is the single most impactful performance change you can make.
# Install Redis and PHP extensionsapt install redis-server php-redis php-apcu
# Verify Redis is runningredis-cli ping # Should return PONGEdit your Nextcloud config.php:
<?php$CONFIG = array ( // ... existing config ...
// APCu for memory caching 'memcache.local' => '\\OC\\Memcache\\APCu',
// Redis for distributed caching and file locking 'memcache.distributed' => '\\OC\\Memcache\\Redis', 'memcache.locking' => '\\OC\\Memcache\\Redis', 'redis' => array( 'host' => 'localhost', 'port' => 6379, 'timeout' => 1.5, // 'password' => 'your-redis-password', // if auth enabled ),
// APCu for memory (user-specific cache) // Already set above via memcache.local);For Docker Compose setups, add Redis as a service:
services: nextcloud: image: nextcloud:latest environment: REDIS_HOST: redis REDIS_HOST_PORT: 6379 depends_on: - redis
redis: image: redis:7-alpine restart: unless-stopped command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru volumes: - redis-data:/dataAfter adding Redis, check the admin panel warnings at Settings → Administration → Overview. The “memory caching” and “transactional file locking” warnings should disappear.
PHP-FPM Worker Configuration
For high-traffic or multi-user setups, PHP-FPM worker pool settings matter:
[nextcloud]user = www-datagroup = www-datalisten = /run/php/php8.2-fpm-nextcloud.sock
pm = dynamicpm.max_children = 20pm.start_servers = 5pm.min_spare_servers = 3pm.max_spare_servers = 10pm.max_requests = 500
# Increase memory limit for Nextcloudphp_admin_value[memory_limit] = 512Mphp_admin_value[upload_max_filesize] = 16Gphp_admin_value[post_max_size] = 16Gphp_admin_value[max_execution_time] = 3600
# OPcache settingsphp_admin_value[opcache.enable] = 1php_admin_value[opcache.memory_consumption] = 256php_admin_value[opcache.interned_strings_buffer] = 64php_admin_value[opcache.max_accelerated_files] = 10000php_admin_value[opcache.revalidate_freq] = 60php_admin_value[opcache.save_comments] = 1Rule of thumb for pm.max_children: number of workers = available_RAM_for_php / 35MB. If PHP can use 1GB RAM: ~28 workers. Adjust based on actual usage.
The occ Command: Your Nextcloud Swiss Army Knife
occ (OCC stands for “ownCloud Console”) is the Nextcloud CLI — essential for maintenance, debugging, and automation.
# Basic usage (as www-data user)sudo -u www-data php /var/www/nextcloud/occ [command]
# In Dockerdocker exec -u www-data nextcloud-app php occ [command]
# Common commands:
# Check system statussudo -u www-data php occ statussudo -u www-data php occ check
# List all userssudo -u www-data php occ user:list
# Add a usersudo -u www-data php occ user:add --password-from-env usernameexport OC_PASS=secretpassword
# Reset a user's passwordsudo -u www-data php occ user:resetpassword username
# Scan files (when files added outside the web UI)sudo -u www-data php occ files:scan --allsudo -u www-data php occ files:scan username
# Fix file permissionssudo -u www-data php occ files:scan-app-data
# Run background jobs manuallysudo -u www-data php occ background:cron
# Maintenance modesudo -u www-data php occ maintenance:mode --onsudo -u www-data php occ maintenance:mode --off
# App managementsudo -u www-data php occ app:listsudo -u www-data php occ app:enable appnamesudo -u www-data php occ app:disable appnamesudo -u www-data php occ app:update --all
# Database managementsudo -u www-data php occ db:add-missing-indicessudo -u www-data php occ db:add-missing-columnssudo -u www-data php occ db:convert-filecache-bigint
# Config managementsudo -u www-data php occ config:listsudo -u www-data php occ config:system:set trusted_domains 2 --value="new-domain.com"occ db:add-missing-indices is something you should run after every Nextcloud upgrade — it adds database indices that new versions require, dramatically improving query performance on large installs.
Setting Up Cron for Background Jobs
Nextcloud has background jobs (cleanup, notifications, indexing) that need to run regularly. By default they run on web request (AJAX mode) — meaning they only run when someone is using the site. Set up a proper cron job:
# Add to www-data's crontabcrontab -u www-data -e
# Add this line:*/5 * * * * php -f /var/www/nextcloud/cron.phpTell Nextcloud to use cron:
sudo -u www-data php occ background:cronIn the admin panel: Settings → Administration → Basic settings → Background jobs should now show “Cron” selected.
For Docker setups, either use a separate cron container or exec into the container:
services: nextcloud-cron: image: nextcloud:latest restart: unless-stopped volumes: - nextcloud-data:/var/www/html entrypoint: /cron.sh depends_on: - nextcloudFederation: Sharing Across Nextcloud Instances
Federation lets users on your Nextcloud share files with users on someone else’s Nextcloud. No accounts needed on the other instance — just a “federated cloud ID” like an email address.
Setting Your Federation Address
Your federated cloud ID is: username@your-nextcloud-domain.com
For this to work, your Nextcloud URL must be publicly accessible and your federation URL must be correct.
# Check your current federation URLsudo -u www-data php occ config:system:get overwrite.cli.url
# Set it if wrongsudo -u www-data php occ config:system:set overwrite.cli.url \ --value="https://cloud.example.com"Sharing with a Federated User
In the Files app, share a file or folder → type the federated cloud ID in the share box:
username@theirdomain.comNextcloud contacts the other instance’s /ocs/v2.php/apps/federation/api/v1/ API to establish the share. The recipient gets a notification on their instance.
Configuring Trusted Servers (Optional)
For frequent federation with specific instances, add them as trusted:
Administration → Sharing → Federated Cloud Sharing → Trusted servers
Add https://theirdomain.com — Nextcloud will verify the connection and add them to the trusted list. Shares with trusted servers happen more smoothly.
Federation Settings
# Allow users to share with other instancessudo -u www-data php occ config:app:set files_sharing \ federatedfilesharing.allowHttpFallback \ --value="yes"
# Check federation statussudo -u www-data php occ federation:sync-addressbooksAutomated Backups: The Three Things You Need
A complete Nextcloud backup requires three components:
- Database dump
- Data directory (user files)
- Config directory
#!/bin/bashset -euo pipefail
BACKUP_DIR="/backup/nextcloud"DATE=$(date +%Y%m%d_%H%M%S)NC_PATH="/var/www/nextcloud"NC_DATA="/mnt/nextcloud-data"DB_NAME="nextcloud"DB_USER="nextcloud"DB_PASS="your-db-password"
# Enable maintenance modesudo -u www-data php "$NC_PATH/occ" maintenance:mode --on
# Database backupmysqldump -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" | \ gzip > "$BACKUP_DIR/db-$DATE.sql.gz"
# Config backuptar -czf "$BACKUP_DIR/config-$DATE.tar.gz" \ "$NC_PATH/config/"
# Data backup (rsync for efficiency)rsync -av --delete \ "$NC_DATA/" \ "$BACKUP_DIR/data/"
# Disable maintenance modesudo -u www-data php "$NC_PATH/occ" maintenance:mode --off
# Remove backups older than 14 daysfind "$BACKUP_DIR" -name "*.gz" -mtime +14 -delete
echo "Backup completed: $DATE"chmod +x /usr/local/bin/nextcloud-backup.sh
# Schedule daily at 3 AMecho "0 3 * * * root /usr/local/bin/nextcloud-backup.sh >> /var/log/nextcloud-backup.log 2>&1" \ >> /etc/cron.d/nextcloud-backupFor remote backups, pipe the rsync to a remote server or an S3-compatible bucket:
# Rclone to S3-compatible storage (Backblaze B2, Wasabi, etc.)rclone sync "$BACKUP_DIR/" remote:my-nextcloud-backup/ \ --exclude "*.tmp" \ --progressLDAP Integration Basics
Connect Nextcloud to an LDAP server (Active Directory, OpenLDAP, FreeIPA) for centralized user management:
# Enable the LDAP appsudo -u www-data php occ app:enable user_ldap
# Run the LDAP configuration wizard or use occsudo -u www-data php occ ldap:create-empty-config
# List LDAP configurationssudo -u www-data php occ ldap:show-configBasic LDAP config in config.php:
// Better to configure via admin panel: Settings → Administration → LDAP/AD integration
// Key settings to fill in:// Server: ldap://ldap.example.com:389// Port: 389 (or 636 for LDAPS)// Bind DN: cn=nextcloud,ou=service-accounts,dc=example,dc=com// Bind password: your-service-account-password// Base DN: ou=users,dc=example,dc=com// User filter: (&(objectClass=inetOrgPerson)(memberOf=cn=nextcloud-users,ou=groups,dc=example,dc=com))// Username attribute: uid (or sAMAccountName for AD)// Email attribute: mail// Display name: cnTest the LDAP connection from the admin panel and verify users sync correctly before disabling local auth.
External Storage
Nextcloud can mount external storage as a directory in the Files app — S3 buckets, SFTP servers, SMB/CIFS shares, WebDAV:
# Enable external storage appsudo -u www-data php occ app:enable files_external
# Mount an S3 bucket via occsudo -u www-data php occ files_external:create \ /S3-Archive \ amazons3 \ amazons3::accesskey \ --config bucket=my-nextcloud-archive \ --config key=AKIAIOSFODNN7EXAMPLE \ --config secret=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY \ --config region=us-east-1 \ --config use_ssl=trueOr configure via Administration → External Storages in the admin panel.
Security Hardening Quick Wins
# Verify recommended security settingssudo -u www-data php occ security:check
# Enable brute force protection (usually already on)sudo -u www-data php occ app:enable bruteforceprotection
# Set max login attemptssudo -u www-data php occ config:app:set bruteforceprotection \ fail2ban_enabled --value="1"
# Enable two-factor auth enforcement (optional but recommended)sudo -u www-data php occ twofactorauth:enforce --on
# Disable unused appssudo -u www-data php occ app:disable weather_statussudo -u www-data php occ app:disable dashboard # If not usedRate limit failed logins in Nginx:
# In your Nextcloud Nginx configlocation ^~ /login { limit_req zone=login burst=3 nodelay; try_files $uri $uri/ /index.php$request_uri;}After All This: Check the Health Page
After all tuning is done:
sudo -u www-data php occ statussudo -u www-data php occ checkAnd visit Settings → Administration → Overview in the web UI. Green checkmarks everywhere, no warnings, no “Your installation has no default phone region” nagging.
That’s the goal: a Nextcloud that doesn’t embarrass you in the admin panel, backs up automatically, performs respectably, and can actually talk to other instances without you having to read four different documentation pages to figure out why a federated share isn’t working.
The caching alone — Redis + APCu — typically drops page load times by 40-60% on installs with any real number of users. Do that first.