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 extensions
apt install redis-server php-redis php-apcu
# Verify Redis is running
redis-cli ping # Should return PONG
Edit your Nextcloud config.php:
# /var/www/nextcloud/config/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:/data
After 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:
# /etc/php/8.2/fpm/pool.d/nextcloud.conf
[nextcloud]
user = www-data
group = www-data
listen = /run/php/php8.2-fpm-nextcloud.sock
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 10
pm.max_requests = 500
# Increase memory limit for Nextcloud
php_admin_value[memory_limit] = 512M
php_admin_value[upload_max_filesize] = 16G
php_admin_value[post_max_size] = 16G
php_admin_value[max_execution_time] = 3600
# OPcache settings
php_admin_value[opcache.enable] = 1
php_admin_value[opcache.memory_consumption] = 256
php_admin_value[opcache.interned_strings_buffer] = 64
php_admin_value[opcache.max_accelerated_files] = 10000
php_admin_value[opcache.revalidate_freq] = 60
php_admin_value[opcache.save_comments] = 1
Rule 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 Docker
docker exec -u www-data nextcloud-app php occ [command]
# Common commands:
# Check system status
sudo -u www-data php occ status
sudo -u www-data php occ check
# List all users
sudo -u www-data php occ user:list
# Add a user
sudo -u www-data php occ user:add --password-from-env username
export OC_PASS=secretpassword
# Reset a user's password
sudo -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 --all
sudo -u www-data php occ files:scan username
# Fix file permissions
sudo -u www-data php occ files:scan-app-data
# Run background jobs manually
sudo -u www-data php occ background:cron
# Maintenance mode
sudo -u www-data php occ maintenance:mode --on
sudo -u www-data php occ maintenance:mode --off
# App management
sudo -u www-data php occ app:list
sudo -u www-data php occ app:enable appname
sudo -u www-data php occ app:disable appname
sudo -u www-data php occ app:update --all
# Database management
sudo -u www-data php occ db:add-missing-indices
sudo -u www-data php occ db:add-missing-columns
sudo -u www-data php occ db:convert-filecache-bigint
# Config management
sudo -u www-data php occ config:list
sudo -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 crontab
crontab -u www-data -e
# Add this line:
*/5 * * * * php -f /var/www/nextcloud/cron.php
Tell Nextcloud to use cron:
sudo -u www-data php occ background:cron
In 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:
- nextcloud
Federation: 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 URL
sudo -u www-data php occ config:system:get overwrite.cli.url
# Set it if wrong
sudo -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.com
Nextcloud 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 instances
sudo -u www-data php occ config:app:set files_sharing \
federatedfilesharing.allowHttpFallback \
--value="yes"
# Check federation status
sudo -u www-data php occ federation:sync-addressbooks
Automated Backups: The Three Things You Need
A complete Nextcloud backup requires three components:
- Database dump
- Data directory (user files)
- Config directory
#!/bin/bash
# /usr/local/bin/nextcloud-backup.sh
set -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 mode
sudo -u www-data php "$NC_PATH/occ" maintenance:mode --on
# Database backup
mysqldump -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" | \
gzip > "$BACKUP_DIR/db-$DATE.sql.gz"
# Config backup
tar -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 mode
sudo -u www-data php "$NC_PATH/occ" maintenance:mode --off
# Remove backups older than 14 days
find "$BACKUP_DIR" -name "*.gz" -mtime +14 -delete
echo "Backup completed: $DATE"
chmod +x /usr/local/bin/nextcloud-backup.sh
# Schedule daily at 3 AM
echo "0 3 * * * root /usr/local/bin/nextcloud-backup.sh >> /var/log/nextcloud-backup.log 2>&1" \
>> /etc/cron.d/nextcloud-backup
For 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" \
--progress
LDAP Integration Basics
Connect Nextcloud to an LDAP server (Active Directory, OpenLDAP, FreeIPA) for centralized user management:
# Enable the LDAP app
sudo -u www-data php occ app:enable user_ldap
# Run the LDAP configuration wizard or use occ
sudo -u www-data php occ ldap:create-empty-config
# List LDAP configurations
sudo -u www-data php occ ldap:show-config
Basic 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: cn
Test 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 app
sudo -u www-data php occ app:enable files_external
# Mount an S3 bucket via occ
sudo -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=true
Or configure via Administration → External Storages in the admin panel.
Security Hardening Quick Wins
# Verify recommended security settings
sudo -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 attempts
sudo -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 apps
sudo -u www-data php occ app:disable weather_status
sudo -u www-data php occ app:disable dashboard # If not used
Rate limit failed logins in Nginx:
# In your Nextcloud Nginx config
location ^~ /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 status
sudo -u www-data php occ check
And 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.