Deployment guide

Self-Host Nextcloud on VPS: NC 35, PHP 8.3 and MariaDB 11 Guide

Deploy on a VPS Cloud →

Tutorial

Self-Host Nextcloud on VPS: NC 35, PHP 8.3 and MariaDB 11 Guide

Self-hosting19 min read5 steps

Nextcloud is one of the most widely deployed self-hosted applications — and one of the most misconfigured. Between instances running without Redis, without forced TLS, the May 2026 update patching two critical 2FA bypass vulnerabilities, and now the NC 34.0.0-specific regressions — recommended apps missing at first launch, a duplicated PostgreSQL constraint that can spike CPU — every release brings its own pitfalls. Nextcloud 35 (Hub 26 Summer, released September 16, 2026) adds two major constraints: PHP 8.3 is now the minimum requirement (PHP 8.2 is abandoned), and MariaDB 11 removes the mysqldump binary. This guide takes you from a complete installation to security verification, covering NC 34.0.2 fixes, the NC 35 upgrade path, and the 5 most common mistakes.

Contents· Security Alert — May 2026 2FA Bypass CVEs1/17
  1. 01Security Alert — May 2026 2FA Bypass CVEs
  2. 02NC 34.0.0 — Recommended Apps Missing on First Launch
  3. 03NC 34.0.0 — Duplicated PostgreSQL Constraint and CPU Spike
  4. 04Prerequisites and Sizing
  5. 05Installing Nextcloud with Docker Compose
  6. 06Check if Your Instance is Vulnerable to the 2FA CVEs
  7. 07Optimize Performance with Redis and OPcache
  8. 08The 5 Most Common Mistakes
  9. 09Verify Redis Effectiveness with occ
  10. 10Nextcloud Backups — Data, Database and Config
  11. 11Backup with MariaDB 11 — mariadb-dump replaces mysqldump
  12. 12Next Steps — Go Further with Your Instance
  13. 13Update Nextcloud in Production
  14. 14PHP 8.3: Migration and Nextcloud 35 Requirements
  15. 15Nextcloud 35: Upgrade Path and Supported PHP Versions
  16. 16Check App Compatibility Before Upgrading to Nextcloud 35
  17. 17Recognize v7 — Debugging the Silent 'sh: exec: line 1' Error

Security Alert — May 2026 2FA Bypass CVEs

In May 2026, two critical two-factor authentication bypass vulnerabilities were disclosed in Nextcloud:

CVE-2026-45690 (CVSS score 5.9, disclosed May 15, 2026): an attacker with a username and password can bypass 2FA verification using HTTP Basic Auth (basic authentication via the Authorization: Basic base64(user:pass) header). Nextcloud, in affected versions, accepted HTTP Basic Auth even when 2FA was enabled for the targeted account.

CVE-2026-45691 (CVSS score 5.9, disclosed May 13, 2026): same vulnerability class, exploitable via a DAV Bearer token — the WebDAV protocol used by desktop sync clients (Nextcloud Desktop, Nautilus, Finder).

Both CVEs are fixed in Nextcloud 32.0.9 (branch 32) and 33.0.3 (branch 33). Branches 34.x and above are not affected. Check if your instance is vulnerable (see dedicated section below).

NC 34.0.0 — Recommended Apps Missing on First Launch

Nextcloud 34.0.0 introduces a regression in the installation wizard: recommended apps (Notes, Calendar, Contacts) are not offered during initial setup. The suggested apps list stays empty, regardless of the installation profile selected.

Practical impact: a fresh NC 34.0.0 instance lacks the basic productivity apps. Users expecting CalDAV calendar or CardDAV contact sync must install them manually from the admin interface.

Sources: GitHub issues #61313 and #61611 — fixed in 34.0.2.

Check if your apps are present:

docker compose exec -u www-data app php occ app:list | grep -E 'calendar|contacts|notes'

If the command returns nothing, the apps are not installed. To add them manually:

docker compose exec -u www-data app php occ app:install calendar
docker compose exec -u www-data app php occ app:install contacts
docker compose exec -u www-data app php occ app:install notes

NC 34.0.0 — Duplicated PostgreSQL Constraint and CPU Spike

On instances using PostgreSQL (instead of MariaDB/MySQL), an interrupted Nextcloud 34.0.0 migration can leave a duplicated constraint on the oc_filecache_extended table. This duplicate goes unnoticed at startup but triggers a CPU and RAM spike during the next file scan (files:scan) or automatic maintenance.

Symptoms: abnormally high CPU load on the Nextcloud container, a file scan that never completes, log errors like duplicate key value violates unique constraint.

Source: GitHub issue #61597.

Verification and fix:

docker compose exec -u www-data app php occ files:cleanup
docker compose exec -u www-data app php occ db:add-missing-indices
docker compose exec -u www-data app php occ db:add-missing-columns

If errors persist, upgrade directly to 34.0.2 which contains the migration fix.

Prerequisites and Sizing

Recommended configuration: VPS with 2 GB RAM (4 GB for more than 5 active users), SSD required (many file and thumbnail operations), 20 GB minimum storage plus data space, Ubuntu 22.04 or Debian 12, Docker Engine ≥ 24, a domain name with TLS certificate, ports 80 and 443 open.

Installing Nextcloud with Docker Compose

  1. Step 1 — Create the project structure

    Create /opt/nextcloud/docker-compose.yml with MariaDB 10.11, Redis 7-alpine, and Nextcloud nextcloud:34.0.4-apache. Bind the app to 127.0.0.1:8080:80. Set depends_on: db and redis.

  2. Step 2 — Create the environment file

    cat > /opt/nextcloud/.env << 'EOF'
    MYSQL_ROOT_PASSWORD=strong_root_password
    MYSQL_PASSWORD=strong_nextcloud_password
    REDIS_PASSWORD=strong_redis_password
    NEXTCLOUD_ADMIN_USER=admin
    NEXTCLOUD_ADMIN_PASSWORD=strong_admin_password
    NEXTCLOUD_DOMAIN=cloud.yourdomain.com
    EOF
  3. Step 3 — Start the containers

    docker compose up -d
    docker compose logs -f app

    First startup takes 2 to 4 minutes. Wait for Nextcloud was successfully installed.

  4. Step 4 — Configure Nginx with TLS

    Install Nginx and Certbot, create the Nextcloud site with client_max_body_size 10G; and proxy headers, then run certbot --nginx -d cloud.yourdomain.com.

  5. Step 5 — Configure the trusted URL in Nextcloud

    docker compose exec -u www-data app php occ config:system:set trusted_domains 0 \
      --value=cloud.yourdomain.com
    docker compose exec -u www-data app php occ config:system:set overwrite.cli.url \
      --value=https://cloud.yourdomain.com

Check if Your Instance is Vulnerable to the 2FA CVEs

Check current version:

docker compose exec -u www-data app php occ status

Vulnerable versions: all Nextcloud 32.x < 32.0.9 and 33.x < 33.0.3. Branches 34.x and above are not affected by these CVEs.

Update to the patched version (branch 32 → 32.0.9, branch 33 → 33.0.3):

# Branch 32:
sed -i 's|nextcloud:[0-9.]*-apache|nextcloud:32.0.9-apache|g' docker-compose.yml
# Branch 33:
# sed -i 's|nextcloud:[0-9.]*-apache|nextcloud:33.0.3-apache|g' docker-compose.yml
docker compose pull app && docker compose up -d app
docker compose exec -u www-data app php occ upgrade

Optimize Performance with Redis and OPcache

Nextcloud without Redis is a slow Nextcloud. Redis plays two critical roles: session caching (avoids disk reads/writes on every authenticated request) and distributed locking (file locking) which prevents conflicts during simultaneous synchronizations.

Verify Redis is connected:

docker compose exec -u www-data app php occ config:system:get redis

If nothing appears, add the Redis config to config.php manually.

The 5 Most Common Mistakes

1. Redis not configured — slow interface, sync conflicts.
2. overwrite.cli.url pointing to http:// — insecure share links and emails.
3. trusted_domains misconfigured — 'untrusted domain' access denied error.
4. Upload size limited to 2 MB — add client_max_body_size 10G in Nginx.
5. Missed security updates — configure update notifications and schedule regular updates.

Verify Redis Effectiveness with occ

docker compose exec -u www-data app php occ status
docker compose exec -u www-data app php occ check
docker compose exec -u www-data app php occ config:system:get redis

The occ check command lists all detected configuration issues. It is the first diagnostic to run on any existing Nextcloud instance.

Nextcloud Backups — Data, Database and Config

Nextcloud stores data in three places — all three must be backed up:

1. MariaDB database: file metadata, users, shares, installed apps.
2. nextcloud volume: PHP code, installed apps, and config/config.php.
3. User files: default in the Docker volume or in the path set by datadirectory in config.php.

# Enable maintenance mode
docker compose exec -u www-data app php occ maintenance:mode --on
# Backup the database (MariaDB 10.x)
docker compose exec -T db mysqldump -u nextcloud -p${MYSQL_PASSWORD} nextcloud | gzip > /opt/nextcloud/backups/db-$(date +%Y%m%d).sql.gz
# Disable maintenance mode
docker compose exec -u www-data app php occ maintenance:mode --off

Note for MariaDB 11+: replace mysqldump with mariadb-dump (see dedicated section below).

Backup with MariaDB 11 — mariadb-dump replaces mysqldump

From MariaDB 11.0, the mysqldump and mysql binaries have been removed from the official Docker image. Only mariadb-dump and mariadb are available. Scripts still using mysqldump with a mariadb:11.x image will fail silently.

Check your MariaDB version:

docker compose exec db mariadb --version

Backup script for MariaDB 11+:

#!/bin/bash
DATE=$(date +%Y%m%d)
BACKUP_DIR=/opt/nextcloud/backups
mkdir -p $BACKUP_DIR

docker compose exec -u www-data app php occ maintenance:mode --on

# mariadb-dump replaces mysqldump on MariaDB 11+
docker compose exec -T db \
  mariadb-dump -u nextcloud -p${MYSQL_PASSWORD} nextcloud \
  | gzip > $BACKUP_DIR/db-$DATE.sql.gz

if gzip -t $BACKUP_DIR/db-$DATE.sql.gz 2>/dev/null; then
  echo "Backup OK: $BACKUP_DIR/db-$DATE.sql.gz"
else
  echo "ERROR: corrupted or empty archive"
  docker compose exec -u www-data app php occ maintenance:mode --off
  exit 1
fi

docker compose cp app:/var/www/html/config/config.php $BACKUP_DIR/config-$DATE.php
docker compose exec -u www-data app php occ maintenance:mode --off

Restore:

gunzip -c $BACKUP_DIR/db-$DATE.sql.gz | \
  docker compose exec -T db mariadb -u nextcloud -p${MYSQL_PASSWORD} nextcloud

Note: if you stay on mariadb:10.11 (EOL February 2028), both mysqldump and mariadb-dump work. The removal only affects MariaDB 11.0 and above.

Next Steps — Go Further with Your Instance

Once Nextcloud is installed and secured:

Enable Talk (video conferencing): install the Nextcloud Talk app from the admin interface. For meetings with more than 4–5 participants, a TURN server is required (Coturn on a dedicated VPS).

Enable OnlyOffice or Collabora Online: these apps require their own Docker container and Nextcloud Office configuration.

Monitor your instance: configure alerts in Administration → Monitoring to receive email notifications if Nextcloud detects configuration errors, security updates, or quota issues.

Update Nextcloud in Production

Always run updates with maintenance mode enabled:

docker compose exec -u www-data app php occ maintenance:mode --on
# MariaDB 10.x:
docker compose exec -T db mysqldump -u nextcloud -p${MYSQL_PASSWORD} nextcloud \
  | gzip > /opt/nextcloud/backups/pre-update-db.sql.gz
# MariaDB 11+: use mariadb-dump instead
sed -i 's|nextcloud:[0-9.]*-apache|nextcloud:34.0.4-apache|g' docker-compose.yml
docker compose pull app && docker compose up -d app
docker compose exec -u www-data app php occ upgrade
docker compose exec -u www-data app php occ maintenance:mode --off

PHP 8.3: Migration and Nextcloud 35 Requirements

Nextcloud 35 makes PHP 8.3 mandatory — PHP 8.2 is no longer supported. This is documented in the official release notes and in the Nextcloud PHP compatibility matrix (GitHub wiki *Releases and PHP versions*). If you run a native installation or a Docker image locked to PHP 8.2, you must migrate PHP before upgrading to NC 35.

Check the PHP version used by your instance:

# In Docker
docker compose exec app php --version

# Native
php8.2 --version || php8.3 --version

In Docker — the nextcloud:35.x-apache image already includes PHP 8.3+: no manual PHP migration needed. Simply update the tag:

image: nextcloud:35.0.0-apache

Required PHP extensions for Nextcloud 35:

| Extension | Role |
|-----------|------|
| gd or imagick | Thumbnail generation |
| redis | Distributed cache and file locking |
| intl | Internationalization |
| bcmath, gmp | Cryptography |
| zip | Archive handling |
| opcache | PHP performance (required) |

Check for missing extensions:

docker compose exec -u www-data app php occ check

Nextcloud 35: Upgrade Path and Supported PHP Versions

Nextcloud 35.0.0 was released on September 16, 2026 (Hub 26 Summer). It requires a strict sequential upgrade path, PHP 8.3 as minimum (PHP 8.2 is abandoned), and introduces changes for MariaDB 11 environments.

PHP 8.3 minimum — PHP 8.2 abandoned

Nextcloud 35 officially supports PHP 8.3 (minimum required), 8.4, and 8.5 (recommended). An instance running PHP 8.2 will not start after upgrading to NC 35. Always pin to an explicit Docker tag:

image: nextcloud:35.0.0-apache

Mandatory sequential upgrade path: v33 → v34 → v35

# Step 1: upgrade to NC 34
docker compose exec -u www-data app php occ maintenance:mode --on
sed -i 's|nextcloud:[0-9.]*-apache|nextcloud:34.0.4-apache|g' docker-compose.yml
docker compose pull app && docker compose up -d app
docker compose exec -u www-data app php occ upgrade
docker compose exec -u www-data app php occ maintenance:mode --off

# Step 2: upgrade to NC 35
docker compose exec -u www-data app php occ maintenance:mode --on
sed -i 's|nextcloud:[0-9.]*-apache|nextcloud:35.0.0-apache|g' docker-compose.yml
docker compose pull app && docker compose up -d app
docker compose exec -u www-data app php occ upgrade
docker compose exec -u www-data app php occ maintenance:mode --off

Check the compatibility matrix at apps.nextcloud.com before each major version upgrade.

Check App Compatibility Before Upgrading to Nextcloud 35

Before upgrading to NC 35, run the built-in platform compatibility check:

docker exec -u www-data <container_name> php occ app:check-platform-compatibility

If an app returns a compatibility error, disable it before launching the upgrade:

docker exec -u www-data <container_name> php occ app:disable app_name

After the upgrade, always run occ check:

docker compose exec -u www-data app php occ check

Recognize v7 — Debugging the Silent 'sh: exec: line 1' Error

The Recognize app (image and face recognition) can fail silently with:

Classifier process output: sh: exec: line 1: recognize/bin/node: not found

This error does not appear in the admin interface — only in container logs. The app appears installed and active, but no tags are generated.

Main causes:
- CPU architecture mismatch: the Node.js binary bundled in Recognize is compiled for x86_64. On ARM64 (Raspberry Pi, ARM VPS), it is not executable.
- Missing or non-executable binary: incorrect permissions after a volume mount.

Diagnosis:

docker compose logs app | grep -i recognize
docker compose exec app sh -c "ls -la /var/www/html/apps/recognize/bin/"
docker compose exec app uname -m

Fix on x86_64:

docker compose exec -u www-data app php occ config:app:set recognize \
  tensorflow.gpu_enabled --value=false
docker compose exec -u www-data app php occ config:app:set recognize \
  node_binary --value=""
docker compose exec -u www-data app php occ recognize:classify

On ARM64: enable WASM mode in app settings (Administration → Recognize → Use WASM backend).

A Reliable VPS for Your Nextcloud Instance

Nextcloud needs an SSD VPS with good bandwidth for smooth file synchronization. Our VPS Cloud plans start at 2 GB RAM with daily snapshots — exactly what a stress-free Nextcloud instance needs.

Need help?

Browse our help center and FAQ, or reach our team — callback, WhatsApp or email. Support in French, English and Arabic.

Message us on WhatsAppopens in a new tab