Nextcloud Setup: Self-Hosted Cloud Storage and Collaboration
Nextcloud installation with Docker, Apache/Nginx configuration, database setup, SSL certificate, file synchronization, app store, and performance optimization.
Table of Contents
Nextcloud Setup: Self-Hosted Cloud Storage and Collaboration
Nextcloud is an open-source, self-hosted alternative to cloud storage services like Google Drive, Dropbox, and OneDrive. Beyond file storage and synchronization, it offers calendar, contacts, video conferencing, document editing, and much more. This guide covers Nextcloud installation with Docker Compose, Nginx reverse proxy configuration, and performance optimization.
What is Nextcloud?
Nextcloud is a collaboration platform that gives you full control over your data:
- File Storage: Unlimited storage (limited only by your disk capacity)
- Synchronization: Windows, macOS, Linux, iOS, Android clients
- App Store: 200+ apps (Nextcloud Talk, Calendar, Contacts, Office)
- User Management: LDAP/AD integration, group management
- Security: End-to-end encryption, 2FA, audit log
System Requirements
- Ubuntu 22.04 or Debian 12
- Minimum 2 GB RAM (4 GB recommended)
- Minimum 20 GB disk (additional space for storage)
- Docker and Docker Compose installed
Installation with Docker Compose
Create Directory Structure
mkdir -p /opt/nextcloud/{data,db,redis}
cd /opt/nextcloud
docker-compose.yml File
version: '3.8'
services:
db:
image: postgres:16-alpine
container_name: nextcloud-db
restart: unless-stopped
environment:
POSTGRES_DB: nextcloud
POSTGRES_USER: nextcloud
POSTGRES_PASSWORD: strong-db-password
volumes:
- ./db:/var/lib/postgresql/data
networks:
- nextcloud-net
redis:
image: redis:7-alpine
container_name: nextcloud-redis
restart: unless-stopped
command: redis-server --requirepass redis-password
volumes:
- ./redis:/data
networks:
- nextcloud-net
app:
image: nextcloud:28-fpm-alpine
container_name: nextcloud-app
restart: unless-stopped
depends_on:
- db
- redis
environment:
POSTGRES_HOST: db
POSTGRES_DB: nextcloud
POSTGRES_USER: nextcloud
POSTGRES_PASSWORD: strong-db-password
NEXTCLOUD_ADMIN_USER: admin
NEXTCLOUD_ADMIN_PASSWORD: admin-password
NEXTCLOUD_TRUSTED_DOMAINS: cloud.example.com
REDIS_HOST: redis
REDIS_HOST_PASSWORD: redis-password
PHP_MEMORY_LIMIT: 512M
PHP_UPLOAD_LIMIT: 10G
volumes:
- ./data:/var/www/html
networks:
- nextcloud-net
nginx:
image: nginx:alpine
container_name: nextcloud-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./data:/var/www/html:ro
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/ssl/nextcloud:ro
depends_on:
- app
networks:
- nextcloud-net
cron:
image: nextcloud:28-fpm-alpine
container_name: nextcloud-cron
restart: unless-stopped
volumes:
- ./data:/var/www/html
entrypoint: /cron.sh
depends_on:
- db
- redis
networks:
- nextcloud-net
networks:
nextcloud-net:
driver: bridge
Nginx Configuration
nano /opt/nextcloud/nginx.conf
worker_processes auto;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
upstream php-handler {
server nextcloud-app:9000;
}
server {
listen 80;
server_name cloud.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name cloud.example.com;
ssl_certificate /etc/ssl/nextcloud/fullchain.pem;
ssl_certificate_key /etc/ssl/nextcloud/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
root /var/www/html;
index index.php index.html;
client_max_body_size 10G;
fastcgi_buffers 64 4K;
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;
location = /robots.txt { allow all; log_not_found off; access_log off; }
location ^~ /.well-known {
location = /.well-known/carddav { return 301 /remote.php/dav/; }
location = /.well-known/caldav { return 301 /remote.php/dav/; }
return 301 /index.php$request_uri;
}
location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) {
fastcgi_split_path_info ^(.+?\.php)(\/.*|)$;
set $path_info $fastcgi_path_info;
try_files $fastcgi_script_name =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $path_info;
fastcgi_param HTTPS on;
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
fastcgi_read_timeout 3600;
}
location ~ \.(?:css|js|svg|gif|png|jpg|ico)$ {
try_files $uri /index.php$request_uri;
expires 6M;
access_log off;
}
location / {
try_files $uri $uri/ /index.php$request_uri;
}
}
}
SSL Certificate
# Let's Encrypt certificate with Certbot
apt install certbot -y
certbot certonly --standalone -d cloud.example.com
# Copy certificates
mkdir -p /opt/nextcloud/ssl
cp /etc/letsencrypt/live/cloud.example.com/fullchain.pem /opt/nextcloud/ssl/
cp /etc/letsencrypt/live/cloud.example.com/privkey.pem /opt/nextcloud/ssl/
# Auto-renewal cron
echo "0 3 * * * certbot renew --quiet && cp /etc/letsencrypt/live/cloud.example.com/*.pem /opt/nextcloud/ssl/ && docker restart nextcloud-nginx" | crontab -
Starting Nextcloud
cd /opt/nextcloud
docker compose up -d
# Follow logs
docker compose logs -f app
# Access after installation:
# https://cloud.example.com
occ Commands
Manage Nextcloud with the occ command-line tool:
# Run occ command
docker exec -u www-data nextcloud-app php occ [command]
# Check system status
docker exec -u www-data nextcloud-app php occ status
# Toggle maintenance mode
docker exec -u www-data nextcloud-app php occ maintenance:mode --on
docker exec -u www-data nextcloud-app php occ maintenance:mode --off
# Add missing indices
docker exec -u www-data nextcloud-app php occ db:add-missing-indices
# Scan files (detect new files)
docker exec -u www-data nextcloud-app php occ files:scan --all
# Clear cache
docker exec -u www-data nextcloud-app php occ cache:clear
# List users
docker exec -u www-data nextcloud-app php occ user:list
# Create new user
docker exec -u www-data nextcloud-app php occ user:add --password-from-env --display-name="Full Name" username
App Installation
# List available apps
docker exec -u www-data nextcloud-app php occ app:list
# Install apps
docker exec -u www-data nextcloud-app php occ app:install calendar
docker exec -u www-data nextcloud-app php occ app:install contacts
docker exec -u www-data nextcloud-app php occ app:install talk
docker exec -u www-data nextcloud-app php occ app:install onlyoffice
# Enable/disable apps
docker exec -u www-data nextcloud-app php occ app:enable deck
docker exec -u www-data nextcloud-app php occ app:disable activity
Performance Optimization
Redis Caching
Redis is already configured in docker-compose.yml. Add to Nextcloud config:
docker exec -u www-data nextcloud-app php occ config:system:set redis host --value="redis"
docker exec -u www-data nextcloud-app php occ config:system:set redis port --value=6379 --type=integer
docker exec -u www-data nextcloud-app php occ config:system:set redis password --value="redis-password"
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"
docker exec -u www-data nextcloud-app php occ config:system:set memcache.locking --value="\\OC\\Memcache\\Redis"
Cron Job Configuration
Cron is recommended for Nextcloud background tasks:
# The Nextcloud cron container is already running
# Set cron mode
docker exec -u www-data nextcloud-app php occ background:cron
Large File Uploads
# Increase PHP limits (add to docker-compose.yml environment)
PHP_MEMORY_LIMIT=1G
PHP_UPLOAD_LIMIT=10G
Security Settings
# Add trusted domain
docker exec -u www-data nextcloud-app php occ config:system:set trusted_domains 1 --value="cloud.example.com"
# Brute force protection
docker exec -u www-data nextcloud-app php occ config:system:set auth.bruteforce.protection.enabled --value=true --type=boolean
# Enforce 2FA
docker exec -u www-data nextcloud-app php occ twofactorauth:enforce --on
We recommend using SSD storage for Nextcloud on REXE servers. NVMe SSD performance makes a critical difference for large file transfers.
Related Articles
Coolify Setup: Application Deployment with Self-Hosted PaaS
Coolify installation, Docker and Git integration, application deployment, database management, SSL certificates, environment variables, and self-hosted PaaS alternative to Heroku/Netlify.
Docker Management with Portainer: Web-Based Container Control
Portainer CE installation, Docker and Kubernetes management, stack deployment, volume/network management, user authorization, webhook and GitOps integration.
Uptime Kuma Setup: Self-Hosted Uptime Monitoring
Uptime Kuma installation with Docker, HTTP/TCP/DNS/ping monitoring, notification integrations (Telegram, Discord, email), status page creation, and alert configuration.