Skip to content

NEXTCLOUD โ€” Self-Hosted Cloud Platform

Last reviewed: 2026-06-16

Purpose: Comprehensive reference for deploying, configuring, and maintaining a production-grade Nextcloud instance using Docker Compose with PostgreSQL and Redis.


Table of Contents


Overview

Nextcloud is an open-source, self-hosted file sync and share platform that provides a private alternative to Google Drive, Dropbox, and Microsoft 365. It offers file storage, collaboration (documents, chat, video calls), calendar/contact sync, email integration, and a rich app ecosystem โ€” all under your own control.

This guide covers a Docker Compose deployment with:

  • Nextcloud (Apache-based FPM image)
  • PostgreSQL 16 as the primary database
  • Redis for in-memory caching and file locking
  • Nginx as a reverse proxy (or Traefik/Caddy for TLS termination)
  • Optional: Collabora Online / OnlyOffice for document editing

Architecture

                         Internet
                            |
                      [Reverse Proxy]
                     (Nginx / Traefik / Caddy)
                            |
               +------------+------------+
               |            |            |
         nextcloud-app  postgres-db   redis-cache
         (port 9000)    (port 5432)   (port 6379)
               |
         [Nginx inside container]
         serves /var/www/html
  • nextcloud-app: PHP-FPM container serving Nextcloud.
  • postgres-db: Persistent PostgreSQL database.
  • redis-cache: Redis for transaction file locking, caching, and session storage.

All services communicate over a dedicated Docker bridge network. Persistent data lives in named volumes or bind mounts.


Prerequisites

Requirement Minimum Recommended
CPU 2 cores 4+ cores
RAM 4 GB 8 GB
Disk 20 GB + storage SSD, 50 GB + user data
OS Linux (Ubuntu 22.04+/Debian 12+) Ubuntu 24.04 LTS
Docker 24.x 27.x
Docker Compose v2 v2.30+
Domain โ€” FQDN with DNS A record

Install Docker and Compose:

# Official Docker install (Ubuntu/Debian)
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
newgrp docker

# Verify
docker --version
docker compose version

Docker Compose Deployment

Directory Structure

/opt/nextcloud/
โ”œโ”€โ”€ docker-compose.yml
โ”œโ”€โ”€ .env
โ”œโ”€โ”€ nginx/
โ”‚   โ””โ”€โ”€ nextcloud.conf        (optional, if using bundled Nginx)
โ”œโ”€โ”€ data/
โ”‚   โ”œโ”€โ”€ db/                   (PostgreSQL data โ€” bind mount)
โ”‚   โ”œโ”€โ”€ app/                  (Nextcloud config + data โ€” bind mount)
โ”‚   โ””โ”€โ”€ redis/                (Redis persistence)
โ””โ”€โ”€ backup/
    โ””โ”€โ”€ scripts/

Environment File (.env)

# PostgreSQL
POSTGRES_DB=nextcloud
POSTGRES_USER=nextcloud
POSTGRES_PASSWORD=CHANGE_ME_STRONG_PASSWORD

# Nextcloud admin (set during first-run setup OR pre-seed)
NEXTCLOUD_ADMIN_USER=admin
NEXTCLOUD_ADMIN_PASSWORD=CHANGE_ME_STRONG_ADMIN_PASS

# Redis
REDIS_HOST=redis
REDIS_PORT=6379

# Domain (for trusted domains / reverse proxy)
NEXTCLOUD_TRUSTED_DOMAINS=cloud.example.com
OVERWRITEHOST=cloud.example.com
OVERWRITEPROTOCOL=https

docker-compose.yml

version: "3.8"

services:
  db:
    image: postgres:16-alpine
    container_name: nextcloud-db
    restart: unless-stopped
    volumes:
      - ./data/db:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=${POSTGRES_DB}
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - nextcloud-net

  redis:
    image: redis:7-alpine
    container_name: nextcloud-redis
    restart: unless-stopped
    command: redis-server --appendonly yes --requirepass ""  # set requirepass if needed
    volumes:
      - ./data/redis:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - nextcloud-net

  app:
    image: nextcloud:30-fpm-alpine
    container_name: nextcloud-app
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    volumes:
      - ./data/app:/var/www/html
    environment:
      - POSTGRES_HOST=db
      - POSTGRES_DB=${POSTGRES_DB}
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - REDIS_HOST=${REDIS_HOST}
      - REDIS_PORT=${REDIS_PORT}
      - NEXTCLOUD_ADMIN_USER=${NEXTCLOUD_ADMIN_USER}
      - NEXTCLOUD_ADMIN_PASSWORD=${NEXTCLOUD_ADMIN_PASSWORD}
      - NEXTCLOUD_TRUSTED_DOMAINS=${NEXTCLOUD_TRUSTED_DOMAINS}
      - OVERWRITEHOST=${OVERWRITEHOST}
      - OVERWRITEPROTOCOL=${OVERWRITEPROTOCOL}
      - PHP_MEMORY_LIMIT=512M
      - PHP_UPLOAD_LIMIT=10G
    networks:
      - nextcloud-net

  web:
    image: nginx:alpine
    container_name: nextcloud-web
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - ./data/app:/var/www/html:ro
      - ./nginx/nextcloud.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - app
    networks:
      - nextcloud-net

networks:
  nextcloud-net:
    driver: bridge

Nginx Configuration (nginx/nextcloud.conf)

upstream php-handler {
    server app:9000;
}

server {
    listen 80;
    server_name _;

    root /var/www/html;
    index index.php index.html;

    client_max_body_size 10G;
    fastcgi_buffers 64 4K;

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
        deny all;
    }

    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
        deny all;
    }

    location / {
        rewrite ^ /index.php;
    }

    location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\.php(?:$|/) {
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param HTTPS on;
        fastcgi_pass php-handler;
        fastcgi_read_timeout 300;
    }

    location ~ ^/(?:updater|ocs[12]) {
        try_files $uri $uri/ =404;
        index index.php;
    }

    location ~* \.(?:css|js|svg|gif|png|jpg|ico|wasm|tff|woff|woff2)$ {
        try_files $uri /index.php$uri$is_args$args;
        add_header Cache-Control "public, max-age=15778463";
        access_log off;
    }

    location ~* \.(?:ogg|mp3|mp4|m4a|mov)$ {
        try_files $uri /index.php$uri$is_args$args;
        add_header Cache-Control "public, max-age=2592000";
        access_log off;
    }
}

Deploy

cd /opt/nextcloud

# Create directories
mkdir -p data/{db,app,redis} nginx backup/scripts

# Create the Nginx config file (content above)
vim nginx/nextcloud.conf

# Create .env with your secrets
vim .env

# Start all services
docker compose up -d

# Watch logs
docker compose logs -f

After startup, Nextcloud will be available at http://<your-host>:8080 (or behind your reverse proxy at https://cloud.example.com).


Initial Admin Setup

Automatic Setup via Environment Variables

If you set NEXTCLOUD_ADMIN_USER and NEXTCLOUD_ADMIN_PASSWORD in .env, the container auto-configures the admin account on first boot. You can log in immediately at /login.

Manual Setup (Web UI)

If you skipped the env vars, open http://<host>:8080 in a browser:

  1. Create an admin account (username + password).
  2. Storage & database โ†’ choose PostgreSQL.
  3. Enter database credentials matching .env:
  4. Host: db
  5. Database: nextcloud
  6. User: nextcloud
  7. Password: (as set in .env)
  8. Click Finish setup.

Verify Installation

# Check the Nextcloud version and system status
docker exec -it nextcloud-app php occ status

# Check for configuration warnings
docker exec -it nextcloud-app php occ check

Run php occ check โ€” it will flag items like missing indexes, memory limits, or missing background job configuration. Fix them one by one.


Post-Install Hardening

Set Trusted Domains

# Add domain via OCC
docker exec -it nextcloud-app php occ config:system:set trusted_domains 1 --value=cloud.example.com
docker exec -it nextcloud-app php occ config:system:set trusted_domains 2 --value=192.168.1.100  # optional LAN access

Or manually edit config/config.php:

'trusted_domains' => [
  0 => 'localhost',
  1 => 'cloud.example.com',
],

Enable HTTPS (Reverse Proxy)

If using a reverse proxy (e.g., Nginx, Traefik, Caddy) for TLS:

docker exec -it nextcloud-app php occ config:system:set overwriteprotocol --value=https
docker exec -it nextcloud-app php occ config:system:set overwrite.cli.url --value=https://cloud.example.com

For Caddy, add this to your Caddyfile:

cloud.example.com {
    reverse_proxy 127.0.0.1:8080
}

Set Security Headers (in Reverse Proxy)

# Nginx example (outside Docker, or in your edge proxy)
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer" always;

App Ecosystem

Nextcloud has a rich app store at apps.nextcloud.com. Install apps via the Web UI (user menu โ†’ Apps) or via OCC:

# List installed apps
docker exec -it nextcloud-app php occ app:list

# Install an app (e.g., Calendar, Contacts, Talk)
docker exec -it nextcloud-app php occ app:install calendar
docker exec -it nextcloud-app php occ app:install contacts
docker exec -it nextcloud-app php occ app:install talk
docker exec -it nextcloud-app php occ app:install notes
docker exec -it nextcloud-app php occ app:install deck
docker exec -it nextcloud-app php occ app:install twofactor_totp

# Enable (if installed but disabled)
docker exec -it nextcloud-app php occ app:enable calendar

# Disable / remove
docker exec -it nextcloud-app php occ app:disable survey_client
docker exec -it nextcloud-app php occ app:remove survey_client
App Purpose Install Command
Calendar CalDAV calendar occ app:install calendar
Contacts CardDAV contacts occ app:install contacts
Talk Video/audio chat & messaging occ app:install talk
Notes Rich text notes occ app:install notes
Deck Kanban-style project boards occ app:install deck
Nextcloud Office Collaborative document editing (requires Collabora/ONLYOFFICE) occ app:install richdocuments
Two-Factor TOTP 2FA via authenticator app occ app:install twofactor_totp
Two-Factor WebAuthn Hardware security key 2FA occ app:install twofactor_webauthn
Preview Generator Pre-generate file previews (performance) occ app:install previewgenerator
External Storage Mount S3, SMB, FTP, etc. Built-in
LDAP / Active Directory User auth integration occ app:install user_ldap

File Sync Clients

Nextcloud provides desktop and mobile clients for file synchronization.

Desktop Clients

  • Linux: sudo apt install nextcloud-desclient (Ubuntu), or download from nextcloud.com/install
  • macOS: DMG installer from nextcloud.com
  • Windows: EXE/MSI installer from nextcloud.com

Client configuration (headless / CLI):

# Set up via command line (Linux)
nextcloudcmd --user paul --password 'your-pass' /home/paul/Nextcloud https://cloud.example.com

# Use app password instead of main password for better security
nextcloudcmd --user paul --password 'app-password' /home/paul/Nextcloud https://cloud.example.com

Mobile Clients

WebDAV Access

All files are accessible via WebDAV at:

https://cloud.example.com/remote.php/dav/files/USERNAME/

Mount on Linux:

# Install davfs2
sudo apt install davfs2

# Mount
sudo mount -t davfs https://cloud.example.com/remote.php/dav/files/paul /mnt/nextcloud

Performance Tuning

Redis Caching (Already Configured)

Redis is used for three purposes:

  1. Transaction file locking โ€” prevents conflicts during concurrent file operations.
  2. Memory cache (distributed) โ€” caches file metadata, user sessions, and queries.
  3. Locking โ€” for app-level locking with OCC commands.

Verify Redis is active:

docker exec -it nextcloud-app php occ config:system:get memcache.locking
# Should return: \OC\Memcache\Redis

docker exec -it nextcloud-app php occ config:system:get memcache.distributed
# Should return: \OC\Memcache\Redis

If they're empty, add them to config/config.php:

'memcache.local' => '\OC\Memcache\APCu',
'memcache.distributed' => '\OC\Memcache\Redis',
'memcache.locking' => '\OC\Memcache\Redis',
'redis' => [
    'host' => 'redis',
    'port' => 6379,
],

PHP Memory & Upload Limits

Increase PHP limits inside the app service by setting environment variables in .env or docker-compose.yml:

environment:
  - PHP_MEMORY_LIMIT=512M
  - PHP_UPLOAD_LIMIT=10G

For existing containers, these can also be set at runtime:

docker exec -it nextcloud-app php occ config:system:set memcache.local --value='\OC\Memcache\APCu'

Database Indexes

Nextcloud's OCC command can add missing database indexes for better query performance:

docker exec -it nextcloud-app php occ db:add-missing-indices
docker exec -it nextcloud-app php occ db:add-missing-primary-keys
docker exec -it nextcloud-app php occ db:add-missing-columns
docker exec -it nextcloud-app php occ db:convert-filecache-bigint

Run these after every major Nextcloud upgrade.

Preview Generation

File previews (thumbnails) are generated on-demand, which slows down browsing. The Preview Generator app pre-generates them:

docker exec -it nextcloud-app php occ app:install previewgenerator

# Optional: set preview generation settings
docker exec -it nextcloud-app php occ config:app:set previewgenerator squareSizes --value="32 256"
docker exec -it nextcloud-app php occ config:app:set previewgenerator widthSizes --value="256 1024"
docker exec -it nextcloud-app php occ config:app:set previewgenerator heightSizes --value="256 1024"

# Generate previews for all existing files
docker exec -it nextcloud-app php occ preview:generate-all --quiet

Opcache Configuration

APCu provides local memory caching. It's enabled by default in the FPM image. Verify:

docker exec -it nextcloud-app php -i | grep -i apcu

For custom opcache settings, create opcache.ini and mount it:

opcache.enable=1
opcache.enable_cli=1
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.memory_consumption=128
opcache.save_comments=1
opcache.revalidate_freq=1

Mount it in docker-compose.yml:

volumes:
  - ./php/opcache.ini:/usr/local/etc/php/conf.d/opcache.ini:ro

Cron Jobs (Background Jobs)

Nextcloud needs background jobs for: file scanning, email notifications, expiring shares, preview generation, cleanup, and more.

This runs only when a user visits the page. It's the default but causes lag for interactive users.

Switch to cron via OCC:

docker exec -it nextcloud-app php occ background:cron

Then on the host machine (not inside the container), add a crontab entry:

sudo crontab -u root -e

Add this line (runs every 5 minutes):

*/5 * * * * docker exec -u www-data nextcloud-app php -f /var/www/html/cron.php

Or if you prefer a script-based approach, create /opt/nextcloud/backup/scripts/cron.sh:

#!/bin/bash
docker exec -u www-data nextcloud-app php -f /var/www/html/cron.php

Make it executable and add to crontab:

chmod +x /opt/nextcloud/backup/scripts/cron.sh
(crontab -l 2>/dev/null; echo "*/5 * * * * /opt/nextcloud/backup/scripts/cron.sh") | crontab -

Verify Cron Works

docker exec -it nextcloud-app php occ status
# Look for: "Background Jobs: cron"

If jobs aren't running, check the Nextcloud log:

docker exec -it nextcloud-app tail -n 50 /var/www/html/data/nextcloud.log

Backup Strategy

A robust backup strategy includes the database, application files, and configuration โ€” and a tested restore procedure.

What to Back Up

Component Path / Method Frequency
PostgreSQL database docker exec -t nextcloud-db pg_dump Daily
Nextcloud data + config ./data/app/ (bind mount) Daily
PostgreSQL WAL / data dir ./data/db/ (optional, for PITR) Continuous
Redis data ./data/redis/ (ephemeral โ€” optional) Weekly
Docker Compose files /opt/nextcloud/docker-compose.yml, .env, nginx/ On change

Backup Script (/opt/nextcloud/backup/scripts/backup.sh)

#!/bin/bash
set -euo pipefail

BACKUP_DIR="/opt/nextcloud/backup"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_PATH="${BACKUP_DIR}/${TIMESTAMP}"
RETENTION_DAYS=14

mkdir -p "${BACKUP_PATH}"

echo "[$(date)] Starting Nextcloud backup..."

# 1. Put Nextcloud into maintenance mode
docker exec -u www-data nextcloud-app php occ maintenance:mode --on

# 2. Dump PostgreSQL database
echo "  -> Dumping PostgreSQL database..."
docker exec -t nextcloud-db pg_dump \
    -U "${POSTGRES_USER}" \
    -d "${POSTGRES_DB}" \
    --clean \
    --if-exists \
    > "${BACKUP_PATH}/nextcloud-db.sql"

# 3. Copy application files (config, apps, themes)
echo "  -> Copying Nextcloud data (config + app data)..."
tar czf "${BACKUP_PATH}/nextcloud-data.tar.gz" \
    -C /opt/nextcloud/data/app \
    --exclude="data/nextcloud.log" \
    --exclude="data/access.log" \
    --exclude="data/error.log" \
    --exclude="data/.ocdata" \
    .

# 4. Exit maintenance mode
docker exec -u www-data nextcloud-app php occ maintenance:mode --off

# 5. Copy Docker config files
cp /opt/nextcloud/docker-compose.yml "${BACKUP_PATH}/"
cp /opt/nextcloud/.env "${BACKUP_PATH}/"
cp -r /opt/nextcloud/nginx "${BACKUP_PATH}/nginx"

# 6. Compress entire backup
cd "${BACKUP_DIR}"
tar czf "${TIMESTAMP}.tar.gz" "${TIMESTAMP}"
rm -rf "${BACKUP_PATH}"

# 7. Clean old backups
find "${BACKUP_DIR}" -name "*.tar.gz" -mtime +${RETENTION_DAYS} -delete

echo "[$(date)] Backup completed: ${BACKUP_DIR}/${TIMESTAMP}.tar.gz"

Restore Script (/opt/nextcloud/backup/scripts/restore.sh)

#!/bin/bash
set -euo pipefail

BACKUP_FILE="${1:-}"
if [ -z "${BACKUP_FILE}" ]; then
    echo "Usage: $0 <path-to-backup.tar.gz>"
    exit 1
fi

RESTORE_DIR="/tmp/nextcloud-restore"

echo "[$(date)] Starting Nextcloud restore from ${BACKUP_FILE}..."

# 1. Extract backup
mkdir -p "${RESTORE_DIR}"
tar xzf "${BACKUP_FILE}" -C "${RESTORE_DIR}"
TIMESTAMP_DIR=$(ls "${RESTORE_DIR}")

cd "${RESTORE_DIR}/${TIMESTAMP_DIR}"

# 2. Stop services
cd /opt/nextcloud
docker compose down

# 3. Restore application data
echo "  -> Restoring application data..."
rm -rf /opt/nextcloud/data/app/*
tar xzf nextcloud-data.tar.gz -C /opt/nextcloud/data/app

# 4. Restore database
echo "  -> Restoring database..."
docker compose up -d db
sleep 5
psql_user="${POSTGRES_USER:-nextcloud}"
psql_db="${POSTGRES_DB:-nextcloud}"
docker exec -i nextcloud-db psql -U "${psql_user}" -d "${psql_db}" < nextcloud-db.sql

# 5. Restore config files
cp docker-compose.yml /opt/nextcloud/
cp .env /opt/nextcloud/ 2>/dev/null || true
cp -r nginx /opt/nextcloud/ 2>/dev/null || true

# 6. Start all services
docker compose up -d

# 7. Run integrity checks
sleep 10
docker exec -u www-data nextcloud-app php occ files:scan --all

# 8. Cleanup
rm -rf "${RESTORE_DIR}"

echo "[$(date)] Restore completed successfully."

Make scripts executable:

chmod +x /opt/nextcloud/backup/scripts/*.sh

Schedule Automatic Backups

Add to host crontab:

# Daily backup at 2:00 AM
0 2 * * * /opt/nextcloud/backup/scripts/backup.sh >> /var/log/nextcloud-backup.log 2>&1

Offsite Backup (Optional)

Use rclone to sync backups to S3, B2, or another remote:

# Install rclone
sudo apt install rclone

# Configure (follow prompts)
rclone config

# Sync to remote
rclone sync /opt/nextcloud/backup/ remote:bucket-name/nextcloud-backups/

Add a second cron entry for offsite sync:

# Offsite sync at 3:00 AM
0 3 * * * rclone sync /opt/nextcloud/backup/ remote:bucket-name/nextcloud-backups/

Monitoring & Maintenance

Health Checks

Docker Compose healthchecks are defined in the compose file. Check container health:

docker ps --filter name=nextcloud --format "table {{.Names}}\t{{.Status}}"

Logs

# Application logs
docker logs nextcloud-app -f --tail 50

# Nextcloud internal log
docker exec -it nextcloud-app tail -f /var/www/html/data/nextcloud.log

# Nginx access log
docker logs nextcloud-web -f --tail 50

Upgrading Nextcloud

cd /opt/nextcloud

# 1. Enable maintenance mode
docker exec -u www-data nextcloud-app php occ maintenance:mode --on

# 2. Backup current state (run backup script)
./backup/scripts/backup.sh

# 3. Pull new images
docker compose pull app

# 4. Recreate containers
docker compose up -d --remove-orphans

# 5. Run upgrade
docker exec -u www-data nextcloud-app php occ upgrade

# 6. Add missing DB indices (post-upgrade)
docker exec -u www-data nextcloud-app php occ db:add-missing-indices
docker exec -u www-data nextcloud-app php occ db:add-missing-primary-keys
docker exec -u www-data nextcloud-app php occ db:convert-filecache-bigint

# 7. Disable maintenance mode
docker exec -u www-data nextcloud-app php occ maintenance:mode --off

# 8. Clean up unused images
docker image prune -f

Regular Maintenance Tasks

Frequency Task Command
Daily Verify cron jobs ran docker exec nextcloud-app php occ status
Weekly Check for security updates docker exec nextcloud-app php occ update:check
Weekly Purge deleted files docker exec nextcloud-app php occ trashbin:cleanup --all-users
Weekly Clean up versions docker exec nextcloud-app php occ versions:cleanup
Monthly Re-index files docker exec nextcloud-app php occ files:scan --all
Monthly Check integrity docker exec nextcloud-app php occ integrity:check-core
Per-upgrade Rebuild indices occ db:add-missing-indices

Troubleshooting

Common Issues

"Your data directory is not writable"

# Fix permissions on the app data volume
docker exec -it nextcloud-app chown -R www-data:www-data /var/www/html
docker exec -it nextcloud-app chmod -R 755 /var/www/html

"Can't connect to database"

# Verify DB container is healthy
docker logs nextcloud-db

# Check PostgreSQL is accepting connections
docker exec -it nextcloud-db psql -U nextcloud -d nextcloud -c "SELECT 1;"

# Check the DB hostname in config.php
docker exec -it nextcloud-app php occ config:system:get dbhost
# Should be: db

"Redis connection refused"

# Check Redis is running
docker exec -it nextcloud-redis redis-cli ping
# Should return: PONG

# Verify config.php has correct host
docker exec -it nextcloud-app php occ config:system:get redis

"413 Request Entity Too Large" (upload fails)

Increase client_max_body_size in the Nginx config to match PHP_UPLOAD_LIMIT, then reload Nginx:

docker exec nextcloud-web nginx -s reload

Slow performance

# Run the Nextcloud performance checker
docker exec -it nextcloud-app php occ check

# Check if background jobs are backlogged
docker exec -it nextcloud-app php occ status

# Verify Redis is being used as cache
docker exec -it nextcloud-app php occ config:system:get memcache.distributed

# Check DB query performance โ€” look for slow queries
docker exec -it nextcloud-app php occ db:add-missing-indices --dry-run

Email not sending

# Configure SMTP via OCC
docker exec -it nextcloud-app php occ config:system:set mail_smtpmode --value=smtp
docker exec -it nextcloud-app php occ config:system:set mail_smtphost --value=smtp.example.com
docker exec -it nextcloud-app php occ config:system:set mail_smtpport --value=587
docker exec -it nextcloud-app php occ config:system:set mail_smtpsecure --value=tls
docker exec -it nextcloud-app php occ config:system:set mail_smtpauthtype --value=LOGIN
docker exec -it nextcloud-app php occ config:system:set mail_from_address --value=nextcloud
docker exec -it nextcloud-app php occ config:system:set mail_domain --value=example.com
docker exec -it nextcloud-app php occ config:system:set mail_smtpname --value=no-reply@example.com
docker exec -it nextcloud-app php occ config:system:set mail_smtppassword --value=CHANGE_ME

# Test
docker exec -it nextcloud-app php occ notification:generate admin "Test email - check mail log"

Logs to Check

Log Source Location
Nextcloud internal log ./data/app/data/nextcloud.log (or occ logs:watch)
Docker container logs docker logs nextcloud-app -f
Nginx error log docker logs nextcloud-web -f
PHP-FPM errors Inside container: /var/log/php8/
PostgreSQL logs docker logs nextcloud-db

References