Self-hosted • Privacy-first • No tracking
Home / Homelab / Nextcloud Docker Compose: Production-Ready Setup with PostgreSQL & Redis (2026)
Homelab #privacy#docker-compose#nextcloud#cloud-storage#postgresql#Redis 8 min read 27 views Sep 04, 2026

Nextcloud Docker Compose: Production-Ready Setup with PostgreSQL & Redis (2026)

Build an enterprise-grade private cloud with Nextcloud in Docker. Includes PostgreSQL 16, Redis transactional locking, SSL reverse proxy, and backup scripts.

AdSense — Top (970x90) • Responsive
Nextcloud Docker Compose: Production-Ready Setup with PostgreSQL & Redis (2026)

Nextcloud Docker Compose: Production-Ready Setup with PostgreSQL & Redis (2026)

Executive Summary & Architecture Overview

Nextcloud Hub is the undisputed champion of private self-hosted collaboration suites, delivering file synchronization, office document editing, encrypted messaging, and calendar management. However, the standard SQLite single-container setup frequently leads to database locking errors (database is locked), slow sync performance, and catastrophic corruption under multi-user loads.

A true production-ready homelab deployment requires three decoupled services working in harmony:

  1. Nextcloud Application Container: The core PHP-FPM / Apache web application.
  2. PostgreSQL 16 Database: High-concurrency relational backend database.
  3. Redis 7 In-Memory Cache: Dedicated transactional file locking and session memory cache.
+------------------------------------------------------------------------+
|                          HTTPS Traffic (Port 443)                      |
+-----------------------------------^------------------------------------+
                                    |
+-----------------------------------v------------------------------------+
|               Reverse Proxy (Nginx Proxy Manager / Traefik)            |
+-----------------------------------^------------------------------------+
                                    | Internal Proxy Bridge
+-----------------------------------v------------------------------------+
|                  Nextcloud App Container (nextcloud:apache)            |
|                  - PHP 8.2+ OPCache enabled                            |
|                  - Background Cron Job container                       |
+-------------------^--------------------------------^-------------------+
                    |                                |
       (SQL Queries)|                     (Locks / Memory Cache)
+-------------------v----------+   +-----------------v-------------------+
|  PostgreSQL 16 Database      |   |  Redis 7 Cache Container            |
|  - ACID Compliant Storage    |   |  - Transactional File Locking       |
|  - UTF-8 Native Collations   |   |  - Zero Disk IO for File Locks      |
+------------------------------+   +-------------------------------------+

Hardware, OS & Network Requirements

Swipe horizontallyScroll table →
Specification Minimum (1-3 Users) Production Recommended (Homelab Family / Team)
CPU 2 Cores (x86_64) 4+ Cores (Modern Intel/AMD)
RAM 4 GB 8 GB - 16 GB
Storage (System) 30 GB SSD for OS & DB 100 GB NVMe SSD for PostgreSQL & DB indexes
Storage (Data) 500 GB HDD Multi-Terabyte ZFS / Btrfs mirror with automated scrubbing
Ports Required Port 8080 (Internal HTTP proxy target) Port 443 (External HTTPS via Reverse Proxy)

Step 1: Host Directory Layout & Permissions

Create a robust directory hierarchy for database files, application configurations, and bulk user data:

sudo mkdir -p /opt/nextcloud/{html,data,db_data,redis_data} && \
cd /opt/nextcloud && \
sudo chown -R 33:33 /opt/nextcloud/html /opt/nextcloud/data && \
sudo chmod 750 /opt/nextcloud/data

Important: User ID 33:33 corresponds to www-data inside the Debian-based official Nextcloud Docker image. Setting this ownership prevents initial setup permission faults.

Generate strong random credentials for your environment file:

cat << 'EOF' > /opt/nextcloud/.env
# PostgreSQL Configuration
POSTGRES_DB=nextcloud
POSTGRES_USER=nc_admin
POSTGRES_PASSWORD=f8a7e2b6d19c043e8a5b7c1d2e3f4a5b6c7d8e9f01a2b3c4
POSTGRES_HOST=nextcloud-db

# Redis Authentication Secret
REDIS_PASSWORD=9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f

# Nextcloud Admin Initial Setup
NEXTCLOUD_ADMIN_USER=admin
NEXTCLOUD_ADMIN_PASSWORD=change_this_master_password_immediately

# Hostname and Data paths
NEXTCLOUD_TRUSTED_DOMAINS=cloud.yourhomelab.net 192.168.1.100
OVERWRITEHOST=cloud.yourhomelab.net
OVERWRITEPROTOCOL=https
OVERWRITECLIURL=https://cloud.yourhomelab.net
EOF

Step 2: Production-Grade docker compose.yaml

Save the following configuration as /opt/nextcloud/compose.yaml:

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

  nextcloud-redis:
    image: redis:7-alpine
    container_name: nextcloud-redis
    restart: unless-stopped
    command: redis-server --requirepass \${REDIS_PASSWORD}
    volumes:
      - /opt/nextcloud/redis_data:/data
    networks:
      - nextcloud-net
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "\${REDIS_PASSWORD}", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

  nextcloud-app:
    image: nextcloud:apache
    container_name: nextcloud-app
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:80"
    volumes:
      - /opt/nextcloud/html:/var/www/html
      - /opt/nextcloud/data:/var/www/html/data
    environment:
      - POSTGRES_HOST=nextcloud-db
      - POSTGRES_DB=\${POSTGRES_DB}
      - POSTGRES_USER=\${POSTGRES_USER}
      - POSTGRES_PASSWORD=\${POSTGRES_PASSWORD}
      - REDIS_HOST=nextcloud-redis
      - REDIS_HOST_PASSWORD=\${REDIS_PASSWORD}
      - NEXTCLOUD_ADMIN_USER=\${NEXTCLOUD_ADMIN_USER}
      - NEXTCLOUD_ADMIN_PASSWORD=\${NEXTCLOUD_ADMIN_PASSWORD}
      - NEXTCLOUD_TRUSTED_DOMAINS=\${NEXTCLOUD_TRUSTED_DOMAINS}
      - OVERWRITEHOST=\${OVERWRITEHOST}
      - OVERWRITEPROTOCOL=\${OVERWRITEPROTOCOL}
      - OVERWRITECLIURL=\${OVERWRITECLIURL}
    depends_on:
      nextcloud-db:
        condition: service_healthy
      nextcloud-redis:
        condition: service_healthy
    networks:
      - nextcloud-net

  nextcloud-cron:
    image: nextcloud:apache
    container_name: nextcloud-cron
    restart: unless-stopped
    volumes:
      - /opt/nextcloud/html:/var/www/html
      - /opt/nextcloud/data:/var/www/html/data
    entrypoint: /cron.sh
    depends_on:
      - nextcloud-app
    networks:
      - nextcloud-net

networks:
  nextcloud-net:
    name: nextcloud-net
    driver: bridge

Step 3: Deployment & High-Performance Optimization

Start your stack:

cd /opt/nextcloud && docker compose up -d

Monitor initial table initialization:

docker compose logs -f nextcloud-app

Once installed, apply high-performance memory cache and locking settings via Nextcloud's built-in occ CLI:

# Enable Redis Transactional File Locking
docker exec -u www-data nextcloud-app php occ config:system:set filelocking.enabled --value="true" --type=boolean
docker exec -u www-data nextcloud-app php occ config:system:set memcache.locking --value="\OC\Memcache\Redis"
docker exec -u www-data nextcloud-app php occ config:system:set memcache.local --value="\OC\Memcache\APCu"
docker exec -u www-data nextcloud-app php occ config:system:set memcache.distributed --value="\OC\Memcache\Redis"

# Add missing database indexes
docker exec -u www-data nextcloud-app php occ db:add-missing-indices

# Add missing bigints
docker exec -u www-data nextcloud-app php occ db:add-missing-primary-keys

Step 4: Reverse Proxy & Security Headers

In Nginx Proxy Manager or Nginx reverse proxy configuration, map cloud.yourhomelab.net to http://127.0.0.1:8080.

Add these essential Nextcloud headers to pass the Nextcloud Security & Setup Warnings check:

location /.well-known/carddav {
    return 301 $scheme://$host/remote.php/dav;
}
location /.well-known/caldav {
    return 301 $scheme://$host/remote.php/dav;
}
client_max_body_size 16G;
proxy_buffering off;
proxy_request_buffering off;

Step 5: Zero-Trust Remote Access with Tailscale

To sync files from mobile phones and remote laptops without opening port 80/443 to the whole world:

  1. Run Tailscale on your host: sudo tailscale up.
  2. Add your Tailscale IP or MagicDNS domain to trusted domains:
docker exec -u www-data nextcloud-app php occ config:system:set trusted_domains 2 --value="your-server.tailnet-xyz.ts.net"
  1. Your mobile Nextcloud app can now connect directly to https://your-server.tailnet-xyz.ts.net via your private wireguard mesh.

Step 6: Automated Backup & Disaster Recovery

Create /opt/nextcloud/backup.sh:

#!/usr/bin/env bash
set -euo pipefail

BACKUP_PATH="/mnt/backups/nextcloud"
DATE=$(date +"%Y%m%d_%H%M%S")

mkdir -p "\${BACKUP_PATH}"

echo "[1/4] Turning on Nextcloud Maintenance Mode..."
docker exec -u www-data nextcloud-app php occ maintenance:mode --on

echo "[2/4] Dumping PostgreSQL Database..."
docker exec nextcloud-db pg_dump -U nc_admin nextcloud | gzip > "\${BACKUP_PATH}/nextcloud_db_\${DATE}.sql.gz"

echo "[3/4] Backing up Configuration & App Data..."
tar -czf "\${BACKUP_PATH}/nextcloud_config_\${DATE}.tar.gz" -C /opt/nextcloud html .env

echo "[4/4] Turning off Maintenance Mode..."
docker exec -u www-data nextcloud-app php occ maintenance:mode --off

# Delete backups older than 14 days
find "\${BACKUP_PATH}" -type f -name "*.gz" -mtime +14 -delete
echo "[✓] Backup successfully created at \${BACKUP_PATH}"

Schedule daily at 2:00 AM:

chmod +x /opt/nextcloud/backup.sh && \
(crontab -l 2>/dev/null; echo "0 2 * * * /opt/nextcloud/backup.sh >> /var/log/nc-backup.log 2>&1") | crontab -

Step 7: Deep Troubleshooting Matrix

Swipe horizontallyScroll table →
Error / Symptom Root Cause Verified Resolution
Access through untrusted domain Domain name not registered in config.php trusted domains. Run docker exec -u www-data nextcloud-app php occ config:system:set trusted_domains 1 --value="YOUR_DOMAIN".
Strict-Transport-Security HTTP header is not set to at least 15552000 seconds Reverse proxy SSL configuration missing HSTS response header. In Nginx Proxy Manager, check the HSTS Enabled box in the SSL tab.
Background jobs show Some jobs haven't been executed since... Background jobs set to AJAX instead of Cron. Go to Admin Settings -> Basic Settings -> Background jobs -> Select Cron (Recommended). Our nextcloud-cron container executes this automatically.
Redis server went away Redis authentication password missing or invalid in Nextcloud config. Verify REDIS_HOST_PASSWORD in .env and verify connection: docker exec -it nextcloud-redis redis-cli -a YOUR_PASS ping.
File uploads fail with large ISOs/videos Upload limits restricted by PHP defaults or Nginx proxy buffers. In reverse proxy add client_max_body_size 16G; and set docker exec -u www-data nextcloud-app php occ config:system:set max_chunk_size --value="20971520".

Step 8: Frequently Asked Questions (FAQ)

1. Why should I use PostgreSQL instead of MariaDB?

PostgreSQL 16 handles concurrent locking, large file tables, and full-text search indexing with significantly fewer deadlocks and higher write throughput under intense synchronization loads.

2. How can I mount an external ZFS storage pool or NAS?

Enable the External storage support app in Nextcloud Apps. You can then mount NFS shares, SMB shares, or direct local bind mounts (/mnt/storage) with full read/write permissions.

3. How do I upgrade Nextcloud to future major versions?

Never jump multiple major versions. Change the image tag from nextcloud:29-apache to nextcloud:30-apache, run docker compose up -d, and then run docker exec -u www-data nextcloud-app php occ upgrade.

4. How do I integrate OnlyOffice or Collabora for document editing?

Add an additional container service (collabora/code or onlyoffice/documentserver) to the compose file and configure the connector app within Nextcloud admin settings.

5. Is Nextcloud AIO (All-In-One) better than custom Docker Compose?

Nextcloud AIO provides automatic container management via a master container. However, custom Docker Compose gives complete control over database tuning, backup paths, and resource limits preferred by experienced sysadmins.

Technical Questions & Inquiries

1

Have a question about this guide or running into an error? Ask below — our technical support team usually replies in ~2 minutes.

Verified Technical Support (2026 Standards)
Protected by real-time anti-spam & moderation
MV
Marcus Vance Reader
10 hours ago

What is the recommended Redis maxmemory-policy setting for Nextcloud transactional file locking in 2026?

Play5afe Support Official Solution
10 hours ago
Verified 2026 Homelab Stack

Hi Marcus Vance,

Great question - this is a subtle but crucial setting for Nextcloud reliability. For transactional file locking, the only safe policy is noeviction.

Here's why: Nextcloud uses Redis for two distinct purposes - distributed locking (short-lived, must never be dropped) and caching (can be evicted). If Redis evicts a lock key under allkeys-lru or similar, you'll get spurious "file is locked" errors or, worse, concurrent writes corrupting files.

In your docker-compose.yml, set it explicitly:

services:
  redis:
    image: redis:7-alpine
    command: >
      redis-server
      --maxmemory 512mb
      --maxmemory-policy noeviction
      --appendonly yes

Size it correctly: 512MB is a solid baseline for most homelabs. Monitor redis-cli INFO memory - if used_memory approaches your cap, increase it rather than switching policies.

One exception: If you run a separate Redis instance for caching (e.g., via the Nextcloud memcache.distributed config), that instance can use allkeys-lru. But for your transactional locking Redis - keep noeviction locked in.

This remains the recommended approach through 2026 - Nextcloud's own docs and the core team still enforce this for data integrity. Pair it with appendonly yes for crash recovery, and you're solid.

  • The Play5afe Team
Tested on Docker Compose & 2026 Production Standards Play5afe Infrastructure Team
AdSense — In-article (responsive)

Related Guides