$docker.recipes
·12 min read

Self-Hosting Nextcloud with Docker Compose: Complete Setup Guide

A comprehensive guide to deploying Nextcloud with Docker Compose, including PostgreSQL, Redis, and production-ready configurations.

nextclouddocker-composeself-hostingpostgresqlprivacy

01Why Self-Host Nextcloud?

After years of relying on cloud storage providers, I made the switch to self-hosting Nextcloud and haven't looked back. It's not just about privacy (though that's a huge factor) – it's about having complete control over your data, customizing your experience, and not being subject to arbitrary pricing changes or feature limitations. Nextcloud has evolved far beyond simple file storage. It's become a comprehensive collaboration platform with calendar, contacts, notes, video calls, and hundreds of apps. When you combine it with Docker Compose, deployment becomes straightforward and maintainable. In this guide, I'll walk you through setting up a production-ready Nextcloud instance using Docker Compose, complete with PostgreSQL database, Redis caching, and all the optimizations I've learned from running it for years.

02Understanding the Stack

A proper Nextcloud deployment consists of several components working together. The web application itself runs in a PHP container, but it needs a database for metadata storage and benefits significantly from caching. For the database, I always recommend PostgreSQL over MySQL/MariaDB for Nextcloud. PostgreSQL handles concurrent connections better and has superior full-text search capabilities. Redis serves as both a memory cache and file locking cache, dramatically improving performance especially with multiple users. We'll also include a separate cron container to handle Nextcloud's background jobs properly. This is much more reliable than relying on web-based cron triggers.

Always use separate containers for different services rather than cramming everything into one container. This makes updates, scaling, and troubleshooting much easier.

03Docker Compose Configuration

Here's the complete Docker Compose configuration I use for Nextcloud. This setup includes all the essential services and production-ready configurations:
[docker-compose.yml]
1version: '3.8'
2
3services:
4 nextcloud-db:
5 image: postgres:15-alpine
6 restart: unless-stopped
7 volumes:
8 - nextcloud_db:/var/lib/postgresql/data
9 environment:
10 - POSTGRES_DB=nextcloud
11 - POSTGRES_USER=nextcloud
12 - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
13 networks:
14 - nextcloud-network
15
16 nextcloud-redis:
17 image: redis:7-alpine
18 restart: unless-stopped
19 command: redis-server --requirepass ${REDIS_PASSWORD}
20 networks:
21 - nextcloud-network
22
23 nextcloud-app:
24 image: nextcloud:28-apache
25 restart: unless-stopped
26 ports:
27 - "8080:80"
28 volumes:
29 - nextcloud_data:/var/www/html
30 - ./data:/var/www/html/data
31 - ./config:/var/www/html/config
32 - ./apps:/var/www/html/custom_apps
33 environment:
34 - POSTGRES_HOST=nextcloud-db
35 - POSTGRES_DB=nextcloud
36 - POSTGRES_USER=nextcloud
37 - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
38 - REDIS_HOST=nextcloud-redis
39 - REDIS_HOST_PASSWORD=${REDIS_PASSWORD}
40 - NEXTCLOUD_ADMIN_USER=${ADMIN_USER}
41 - NEXTCLOUD_ADMIN_PASSWORD=${ADMIN_PASSWORD}
42 - NEXTCLOUD_TRUSTED_DOMAINS=${TRUSTED_DOMAINS}
43 - APACHE_DISABLE_REWRITE_IP=1
44 depends_on:
45 - nextcloud-db
46 - nextcloud-redis
47 networks:
48 - nextcloud-network
49
50 nextcloud-cron:
51 image: nextcloud:28-apache
52 restart: unless-stopped
53 volumes:
54 - nextcloud_data:/var/www/html
55 - ./data:/var/www/html/data
56 - ./config:/var/www/html/config
57 - ./apps:/var/www/html/custom_apps
58 entrypoint: /cron.sh
59 depends_on:
60 - nextcloud-db
61 - nextcloud-redis
62 networks:
63 - nextcloud-network
64
65volumes:
66 nextcloud_db:
67 nextcloud_data:
68
69networks:
70 nextcloud-network:
71 driver: bridge

04Environment Variables and Security

Security starts with proper environment variable management. Create a `.env` file in your project directory to store sensitive configuration:
[.env]
1# Database Configuration
2POSTGRES_PASSWORD=your-secure-database-password-here
3
4# Redis Configuration
5REDIS_PASSWORD=your-secure-redis-password-here
6
7# Nextcloud Admin Account
8ADMIN_USER=admin
9ADMIN_PASSWORD=your-secure-admin-password-here
10
11# Domain Configuration
12TRUSTED_DOMAINS=nextcloud.yourdomain.com localhost

Never commit your .env file to version control. Add it to your .gitignore file immediately. Use strong, unique passwords for all services.

05First-Time Deployment

Before starting the containers, create the necessary directory structure and set proper permissions. This prevents common issues with file ownership and ensures your data persists correctly: Create the required directories and start the services. The initial startup will take a few minutes as Nextcloud initializes the database and installs the base system:
[bash]
1# Create directory structure
2mkdir -p data config apps
3
4# Set proper permissions (adjust UID/GID as needed)
5sudo chown -R 33:33 data config apps
6
7# Start the services
8docker compose up -d
9
10# Monitor the initialization process
11docker compose logs -f nextcloud-app

The first startup can take 5-10 minutes. Don't panic if it seems slow – Nextcloud is setting up the database schema and installing default apps.

06Performance and Configuration Tuning

Once Nextcloud is running, there are several optimizations you should apply. These configurations go in your `config/config.php` file and can dramatically improve performance. First, let's configure the memory caching properly. Even though we set Redis in the Docker environment, we need to explicitly configure it in Nextcloud's config: Add these lines to your `config/config.php` file after the initial setup completes. You'll also want to configure PHP memory limits and upload sizes based on your needs. For better performance with large numbers of files, enable APCu caching and configure proper file locking. These settings prevent database locks and speed up file operations significantly.

07Ongoing Maintenance and Updates

Maintaining a Nextcloud installation involves regular updates, monitoring disk space, and occasional database maintenance. I've automated most of these tasks, but there are still some manual steps worth knowing. For updates, always backup your data and database first. The process is straightforward with Docker Compose – pull new images, stop containers, and restart. However, major version updates sometimes require manual intervention. Monitor your logs regularly for any errors or warnings. Nextcloud's admin panel provides excellent system health information, including recommendations for performance improvements. Set up log rotation for your Docker containers and monitor disk usage closely. Nextcloud can generate substantial logs, and user data will obviously grow over time. Consider implementing automated backups of both your data directory and database dumps.

Always test updates in a staging environment first. While Nextcloud updates are generally smooth, complex installations with many apps can sometimes have issues.

About the Author

Frank Pegasus

DevOps engineer and self-hosting enthusiast with over a decade of experience running containerized workloads in production. Creator of docker.recipes.