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 notesNC 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-columnsIf 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
Step 1 — Create the project structure
Create
/opt/nextcloud/docker-compose.ymlwith MariaDB 10.11, Redis 7-alpine, and Nextcloudnextcloud:34.0.4-apache. Bind the app to127.0.0.1:8080:80. Setdepends_on: dbandredis.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 EOFStep 3 — Start the containers
docker compose up -d docker compose logs -f appFirst startup takes 2 to 4 minutes. Wait for
Nextcloud was successfully installed.Step 4 — Configure Nginx with TLS
Install Nginx and Certbot, create the Nextcloud site with
client_max_body_size 10G;and proxy headers, then runcertbot --nginx -d cloud.yourdomain.com.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 statusVulnerable 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 upgradeOptimize 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 redisIf 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 redisThe occ check command lists all detected configuration issues. It is the first diagnostic to run on any existing Nextcloud instance.
Uploads over 40 GB behind Cloudflare: the lost assembly
Nextcloud does not send a large file in one piece: the client splits it into chunks, stored in a temporary folder, then asks the server to assemble them with a final MOVE …/.file request.
Issue nextcloud/server #65408, opened on October 12, 2026 against Nextcloud 35, shows what breaks: a file of about 43 GB dropped through a public share link, every chunk accepted (201), then an assembly of about 17 minutes. Cloudflare cuts a response that exceeds its read timeout (125 seconds by default according to its documentation, about 100 seconds measured by the reporter through Cloudflare Tunnel) and returns a 524.
The public share entry point, publicremote.php, does not call ignore_user_abort(true), unlike remote.php: PHP aborts the assembly when the connection closes, then the browser deletes the chunks with a DELETE request. Files of 4 to 5 GB still go through. As of October 22, 2026, the issue is open, with no published fix.
The limits to align, from the CDN down to PHP
- Cloudflare request body — 100 MB per request on Free and Pro, 200 MB on Business, up to 5 GB on Enterprise; beyond that, a
413response. Every chunk must stay below it. - Chunk size —
files.chunked_upload.max_sizedefaults to 104857600 bytes (100 MiB), slightly more than 100 MB: go down to 50 MiB on Free or Pro. - CDN timeout — 125 seconds, raisable up to 6,000 seconds on Enterprise only: this is the limit the assembly exceeds.
- nginx —
proxy_request_buffering offpasses the body on as it arrives instead of reading it in full;proxy_read_timeoutdefaults to 60 seconds. - PHP — the Nextcloud documentation suggests
max_execution_timeandmax_input_timeat 3600;ignore_user_abort = Onlets the assembly finish after the proxy drops the connection.
Configure Nextcloud for very large uploads
Move heavy uploads off the proxy
Cloudflare recommends a non-proxied subdomain (DNS-only) for requests running over 125 seconds. Create
upload.your-domain.comas DNS-only, add it withdocker compose exec -u www-data app php occ config:system:set trusted_domains 1 --value=upload.your-domain.com, thencertbot --nginx -d upload.your-domain.com. This name exposes the server IP: reserve it for heavy transfers.Reduce the chunks
docker compose exec -u www-data app php occ config:system:set files.chunked_upload.max_size --type int --value 52428800sets 50 MiB (value in bytes).Adjust nginx
In
location /, addproxy_request_buffering off;andproxy_send_timeout 3600s;, keepproxy_read_timeout 3600s;, thennginx -t && systemctl reload nginx.Adjust PHP
Create
/opt/nextcloud/php-uploads.iniwithignore_user_abort = On,max_execution_time = 3600andmax_input_time = 3600, mount it in theappservice:- ./php-uploads.ini:/usr/local/etc/php/conf.d/zz-uploads.ini:ro, thendocker compose up -d app.Check and test
docker compose exec app php -i | grep ignore_user_abortmust showignore_user_abort => On => On. Then upload a file of several gigabytes through the subdomain and followdocker compose logs -f app.Choose what goes through Cloudflare
The main domain can stay proxied, with only the heavy-transfer subdomain switched to DNS-only: see our guide to the Cloudflare proxy.
Troubleshooting large uploads: the real messages
Error 524: a timeout occurred — the response to the final MOVE …/.file did not arrive within Cloudflare's timeout. Fix: the non-proxied subdomain.
413 Request entity too large — a chunk exceeds the Cloudflare plan ceiling or client_max_body_size. Fix: reduce files.chunked_upload.max_size.
Could not open file: web-file-upload-<id>/75 … file doesn't seem to exist — reported in issue #65408: assembly was still running while the browser had deleted the chunks. The reporter blocks the DELETE request on /public.php/dav/uploads/; the UploadCleanup job then purges abandoned chunks after 24 hours. With nginx, the equivalent is a location ^~ /public.php/dav/uploads/ block containing if ($request_method = DELETE) { return 403; } and the same proxy_pass. Unofficial workaround, to remove once a fix ships.
504 Gateway Time-out during the MOVE — nginx gives up: the Nextcloud documentation cites fastcgi_read_timeout for PHP-FPM, here proxy_read_timeout.
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 --offNote 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 --versionBackup 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 --offRestore:
gunzip -c $BACKUP_DIR/db-$DATE.sql.gz | \
docker compose exec -T db mariadb -u nextcloud -p${MYSQL_PASSWORD} nextcloudNote: 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.
Office 2021 End of Life: Enable Co-editing with Collabora Online or OnlyOffice
Microsoft Office 2021 reached end of life on October 13, 2026: no further security patches will be released. For teams co-editing .docx, .xlsx, and .pptx files inside Nextcloud, two open-source office suites cover this need directly from the web interface.
Collabora Online is the online version of LibreOffice, distributed under the AGPL license. It integrates with Nextcloud via the *Nextcloud Office* app and runs in a separate container based on collabora/code:latest, communicating with Nextcloud over WebSocket.
OnlyOffice Document Server offers an interface closer to Microsoft Office — ribbon menus and toolbars familiar to Windows users. It is also AGPL-licensed and integrates via the *ONLYOFFICE* app from the Nextcloud App Store.
Install via the Nextcloud App Store:
# Collabora Online
docker compose exec -u www-data app php occ app:install richdocuments
# OnlyOffice
docker compose exec -u www-data app php occ app:install onlyofficeSeparate Docker deployment — Collabora Online example:
Add this service to your docker-compose.yml:
collabora:
image: collabora/code:latest
restart: unless-stopped
environment:
domain: cloud\.yourdomain\.com
username: admin
password: ${COLLABORA_PASSWORD}
extra_params: --o:ssl.enable=false --o:ssl.termination=true
ports:
- '127.0.0.1:9980:9980'
cap_add:
- MKNODThen configure the Collabora server URL in Nextcloud (Administration → Office → Collabora Online server URL: https://office.yourdomain.com).
Memory footprint: Collabora Online adds approximately +300 MB RAM per active process (one process per simultaneously open document). OnlyOffice is slightly heavier: +400 MB per active instance. On a 2 GB VPS, limit simultaneous use to 2–3 documents or upgrade to 4 GB.
Supported formats: both apps read and write Microsoft Office formats (.docx, .xlsx, .pptx) as well as OpenDocument formats (.odt, .ods, .odp).
Collabora Online or OnlyOffice: Which to Choose?
Scroll the table
| Criterion | Collabora Online | OnlyOffice Docs |
|---|---|---|
| User interface | Familiar LibreOffice — adaptation curve for Windows users | Ribbon identical to Microsoft Office — immediate adoption |
| Compatibility .docx/.xlsx/.pptx | Good; .odt/.ods excellent | Very faithful to Microsoft originals |
| Estimated RAM | ~300 MB/active process | ~400 MB/active instance |
| SSO/SAML Nextcloud | Native integration | Additional configuration required |
| Simultaneous connections | Depends on the edition (CODE or enterprise) | Limited (community edition) |
| Community | Very active LibreOffice, frequent updates | Solid, Microsoft-compatibility focused |
Which editor to choose?
For a mixed Linux/Windows team working primarily with Microsoft Office files, OnlyOffice reduces adoption friction. For a team already on LibreOffice or with tight memory constraints, Collabora Online is the natural choice. Both apps are compatible with Nextcloud 35.
Office 2021: what ends, and troubleshooting Collabora
According to Microsoft's lifecycle page, Office 2021 (Home and Business, Home and Student, Professional, Mac versions included) and Office LTSC 2021 for Windows no longer receive fixes since October 13, 2026; only Office LTSC 2021 for Mac moves to extended support.
When enabling Collabora, "Could not establish connection to the Collabora Online server." (Administration → Office) means Nextcloud cannot reach the declared URL. Test from the container: docker compose exec app curl -sI https://office.your-domain.com/hosting/discovery. To reconfigure and diagnose: docker compose exec -u www-data app php occ richdocuments:activate-config --wopi-url=https://office.your-domain.com; an answer of Failed to fetch discovery endpoint from … points to the network or TLS. The warning "You have not configured the allow-list for WOPI requests" goes away once the Collabora server IP is declared in the WOPI allow list. Detailed comparison: Collabora Online or OnlyOffice.
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 --offPHP 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 --versionIn 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-apacheRequired 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 checkNextcloud 35: Upgrade Path and Supported PHP Versions
Nextcloud 35.0.0 was released on September 15, 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-apacheMandatory 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 --offCheck 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-compatibilityIf an app returns a compatibility error, disable it before launching the upgrade:
docker exec -u www-data <container_name> php occ app:disable app_nameAfter the upgrade, always run occ check:
docker compose exec -u www-data app php occ checkRecognize 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 foundThis 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 -mFix 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:classifyOn ARM64: enable WASM mode in app settings (Administration → Recognize → Use WASM backend).