Software & Configuration

Nextcloud

Install Nextcloud on a VPS with Docker Compose, Nginx reverse proxy and SSL, your personal cloud storage

Nextcloud is a self-hosted file storage and collaboration platform. This guide covers installation via Docker Compose with an Nginx reverse proxy and automatic SSL via Certbot.


Prerequisites

  • Docker and Docker Compose installed (see Docker guide)
  • A domain pointing to your server
  • Port 80 and 443 open on the firewall

Installation with Docker Compose

Create the directory structure

mkdir -p /opt/nextcloud
cd /opt/nextcloud

Create the docker-compose.yml file

services:
  nextcloud-db:
    image: mariadb:10.11
    container_name: nextcloud-db
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: root_secure_password
      MYSQL_DATABASE: nextcloud
      MYSQL_USER: nextcloud
      MYSQL_PASSWORD: nextcloud_secure_password
    volumes:
      - nextcloud_db:/var/lib/mysql
    networks:
      - nextcloud_net

  nextcloud:
    image: nextcloud:latest
    container_name: nextcloud
    restart: unless-stopped
    depends_on:
      - nextcloud-db
    environment:
      MYSQL_HOST: nextcloud-db
      MYSQL_DATABASE: nextcloud
      MYSQL_USER: nextcloud
      MYSQL_PASSWORD: nextcloud_secure_password
      NEXTCLOUD_TRUSTED_DOMAINS: cloud.yourdomain.com
      NEXTCLOUD_ADMIN_USER: admin
      NEXTCLOUD_ADMIN_PASSWORD: admin_secure_password
    volumes:
      - nextcloud_data:/var/www/html
    ports:
      - "127.0.0.1:8080:80"
    networks:
      - nextcloud_net

volumes:
  nextcloud_db:
  nextcloud_data:

networks:
  nextcloud_net:
docker compose up -d

Nginx Reverse Proxy Configuration

Install Nginx and Certbot

apt update && apt install nginx certbot python3-certbot-nginx -y

Create the Nginx configuration

nano /etc/nginx/sites-available/nextcloud
server {
    listen 80;
    server_name cloud.yourdomain.com;

    # Redirect to HTTPS
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name cloud.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/cloud.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/cloud.yourdomain.com/privkey.pem;

    # Required headers for Nextcloud
    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
    add_header Referrer-Policy "no-referrer" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Permitted-Cross-Domain-Policies "none" always;
    add_header X-Robots-Tag "noindex, nofollow" always;
    add_header X-XSS-Protection "1; mode=block" always;

    client_max_body_size 10G;
    proxy_read_timeout 600s;
    proxy_connect_timeout 600s;
    proxy_send_timeout 600s;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket support (for Nextcloud Talk)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Obtain SSL certificate and activate

# Obtain certificate
certbot --nginx -d cloud.yourdomain.com

# Enable the site
ln -s /etc/nginx/sites-available/nextcloud /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx

Post-Installation Configuration

Fix trusted domain warning

If you see a "trusted domain" error, edit the config:

docker exec -it nextcloud bash
nano /var/www/html/config/config.php

Add your domain to trusted_domains:

'trusted_domains' =>
array (
  0 => 'localhost',
  1 => 'cloud.yourdomain.com',
),

Nextcloud requires periodic background jobs. Use the system cron instead of AJAX:

# Add crontab for www-data
crontab -u www-data -e

Add the line:

*/5 * * * * php -f /var/www/html/cron.php

Or execute it directly from the container:

# Add to host crontab
echo "*/5 * * * * docker exec -u www-data nextcloud php -f /var/www/html/cron.php" | crontab -

Then in the Nextcloud web admin → Settings → Basic Settings → set Background jobs to Cron.


Maintenance and Updates

Update Nextcloud

cd /opt/nextcloud

# Pull new image
docker compose pull

# Restart with new version
docker compose up -d

# Check update status
docker exec -u www-data -it nextcloud php /var/www/html/updater/updater.phar

Useful admin commands (occ)

# General status
docker exec -u www-data nextcloud php occ status

# List all apps
docker exec -u www-data nextcloud php occ app:list

# Enable/disable maintenance mode
docker exec -u www-data nextcloud php occ maintenance:mode --on
docker exec -u www-data nextcloud php occ maintenance:mode --off

# Database repair
docker exec -u www-data nextcloud php occ db:add-missing-indices

# Rescan files
docker exec -u www-data nextcloud php occ files:scan --all

Performance Optimization

Enable Redis for caching

Add Redis to docker-compose.yml:

  redis:
    image: redis:alpine
    container_name: nextcloud-redis
    restart: unless-stopped
    networks:
      - nextcloud_net

Then in config.php add:

'memcache.local' => '\\OC\\Memcache\\Redis',
'memcache.locking' => '\\OC\\Memcache\\Redis',
'redis' => array(
  'host' => 'nextcloud-redis',
  'port' => 6379,
),

For large deployments (many users or files), Redis is essential to avoid performance issues. Without it Nextcloud can become slow even on powerful hardware.

On this page