Fully verified36,647

Editorial pickCloud storage

Nextcloud

Nextcloud is cloud storage on your own server: files sync with a computer and a phone, folders open to colleagues by link or by name, and a calendar, contacts, and notes sit on top. The recipe brings up the server, PostgreSQL, Valkey, and a separate container for background jobs.

Overview

Nextcloud is cloud storage that lives on your own server. Files sync with a computer and a phone, folders open to colleagues by name or through a public link, and on top of the files sits the familiar set: calendar, contacts, notes, tasks, and collaborative document editing. It fits a family, a small team, or anyone leaving Google Drive and Microsoft 365.

What separates it from plain file synchronisation is permissions and collaboration. There are accounts, groups, quotas, link expiry dates, passwords on public folders, and an activity log. Nextcloud is not “a folder on several devices” but a server with users.

The recipe brings up four containers: Nextcloud itself, PostgreSQL, Valkey for file locking and caching, and a separate container for background jobs. Without the last one Nextcloud falls back to AJAX mode and only runs maintenance while someone has the interface open. The code, apps, and config.php live in a Docker volume; user files live in a host directory.

The reliable level is declared partial: the database is a separate service and there are healthchecks and a background worker, but the recipe sets no resource limits and adds no external monitoring.

Nextcloud takes more maintenance than the other apps in this catalogue. Upgrades go one major version at a time, and after each one it is worth checking the security warnings page.

Security assessment

The containers run without privileged, host networking, or Docker socket access, and use no-new-privileges; only the web port is published, and only on 127.0.0.1. PostgreSQL and Valkey are reachable only inside the Compose network.

The administrator and database passwords are set in .env and end up in the container environment: keep the file at mode 600, out of Git, and replace the example values before the first start. After installation, enable two-factor authentication — Nextcloud holds the files, calendars, and contacts of several people at once.

The app store deserves particular care: add-ons execute code on the server with Nextcloud’s privileges, so install only the ones you trust. The built-in “Security & setup warnings” page shows what your particular installation is missing; after publishing over HTTPS it is worth walking the list and closing the warnings.

The main image is scanned with Trivy; the critical CVEs it found are listed on the card — mostly issues in the Debian system libraries the image is built on, which upstream closes with the next release. PostgreSQL and Valkey are pinned separately from the Nextcloud version and are outside the automated check.

Update tracking

These are stored results of separate checks, not real-time data. An unknown status means the check has not been performed yet.

New releases

Recipe version compared with the latest known upstream release. A version number, not a reading of what changed.

Current version v34.0.3Aug 31, 2026, 9:31 AM UTC

Breaking updates

A new major version is found by comparing version numbers. A compatibility verdict is entered by hand after reading the release notes and the migration steps.

Not checkedNot checked

compose.yaml

Upstream Compose changes relative to the verified recipe.

Upstream Compose is not trackedNot checked

Outdated Docker images

Pinned image tags checked for newer versions.

All images are currentAug 31, 2026, 9:47 AM UTC

From observation to action

Update plan

The recipe already pins the latest known release. The steps below show the evidence retained for that version.

v34.0.3v34.0.3
  1. Open the release evidence

    Open this release on GitHub ↗ The link is evidence to review, not proof of compatibility.

  2. Review the version boundary

    The version numbers do not cross a major compatibility boundary. No compatibility verdict has been recorded.

  3. Prepare image-tag changes

    No image-tag change is currently planned.

  4. Follow the documented migration shape

    Migration, majors cannot be skipped. Release-specific migration steps still come from the release notes and installation guide.

  5. Protect the rollback point

    No version change is currently planned. The recipe includes a backup procedure. Restore has been tested.

  6. Verify the updated recipe

    An exact Fully verified check for this target was recorded on 2026-08-31.

Read the update procedure in the installation guide ↓

Specifications

Security and exposure

Installation levels

The status shows how fully the published recipe meets each level's requirements.

Ready

For home

A minimal setup for a local network or access through a VPN.

  • Single server
  • Local access
  • Minimum components

The recipe covers every requirement at this level.

Ready

For a VPS

A public deployment with protected access and backups.

  • Domain
  • HTTPS via reverse proxy
  • Off-server backup

The recipe covers every requirement at this level.

Partial

Reliable

A setup designed for predictable operations and observability.

  • Separate database
  • Healthcheck
  • External monitoring
  • CPU and memory limits

You still need to add: external monitoring, cpu and memory limits.

Tailored to your server

Configuration generator

Answer five questions and download a ready-to-run Nextcloud bundle.

Runs locally
01 Do you have a domain?
02 Which reverse proxy?
03 Server architecture
04 Where should data be stored?

Use an absolute path for a separate disk, such as /srv/nextcloud.

05 Is VPN access required?

Your bundle is ready

The archive is created in your browser. Your answers are never sent anywhere.

Screenshots

Screenshots have not been added yet.

Quick start

Read the full guide first: it explains external access, backups, and data locations.

Prepare settingscp .env.example .env
Launchdocker compose up -d
Check statusdocker compose ps

Step-by-step guide

1. Check your Ubuntu or Debian server

For this recipe budget at least 2 CPU cores, 2 GB of RAM, and 20 GB of disk for the server itself; 4 GB of RAM is recommended. This is a conservative estimate for the recipe: upstream publishes requirements for PHP and the database but not for the machine as a whole, and usage depends on the number of users and the enabled apps. Count storage for the files separately. You need Ubuntu 22.04+ or Debian 12+ with Docker Engine and Docker Compose v2.24+.

docker --version
docker compose version
nproc && free -m && df -h /srv

2. Prepare the files and variables

mkdir -p ~/services/nextcloud
cd ~/services/nextcloud
cp .env.example .env
chmod 600 .env
sudo mkdir -p /srv/nextcloud/data
sudo chown -R 33:33 /srv/nextcloud/data
sed -i "s|^NEXTCLOUD_DATA_LOCATION=.*|NEXTCLOUD_DATA_LOCATION=/srv/nextcloud/data|" .env

Inside the container Nextcloud runs as www-data with UID 33, so the data directory has to belong to that user.

Always replace both example passwords:

sed -i "s|^NEXTCLOUD_DB_PASSWORD=.*|NEXTCLOUD_DB_PASSWORD=$(openssl rand -hex 24)|" .env
sed -i "s|^NEXTCLOUD_ADMIN_PASSWORD=.*|NEXTCLOUD_ADMIN_PASSWORD=$(openssl rand -base64 24)|" .env

NEXTCLOUD_VERSION pins the image; NEXTCLOUD_PORT sets the local port; NEXTCLOUD_DATA_LOCATION is the directory with user files; NEXTCLOUD_HTML_VOLUME and NEXTCLOUD_DB_VOLUME name the volumes for the code and the database; NEXTCLOUD_DB_* and NEXTCLOUD_ADMIN_* configure database access and the first account; NEXTCLOUD_TRUSTED_DOMAINS lists the domains allowed to serve the instance; NEXTCLOUD_TRUSTED_PROXIES and NEXTCLOUD_OVERWRITE_* are needed behind a reverse proxy; NEXTCLOUD_PHP_* set the PHP limits; TZ sets the time zone.

The database password and user can only be changed before the first start: once PostgreSQL is initialised, the variable will not create a new account.

3. Start the stack

docker compose pull
docker compose up -d
docker compose ps
ssh -L 8080:127.0.0.1:8080 user@server.example

The first start takes longer than usual: the container unpacks the code and runs the installation. The administrator is created automatically from the variables, so there is no setup wizard in the browser — open http://localhost:8080 and log straight in.

Check that background jobs run in their own container rather than through the browser:

docker compose exec -u www-data app php occ config:app:get core backgroundjobs_mode

The answer must be cron.

Running on a VPS

On a VPS keep the 127.0.0.1 bind, block port 8080 from outside, and publish the service only through an HTTPS reverse proxy. Check the stack:

docker compose up -d
docker compose ps
curl --fail http://127.0.0.1:8080/status.php

All four containers must be up, and app, database, and redis must be healthy. Keep in mind that preview generation and background jobs load a small VPS noticeably: on a single shared core it is worth disabling preview generation for large files.

Access from a local network

Without TLS use an SSH tunnel or a VPN. If the reverse proxy runs on another host in a trusted LAN, replace 127.0.0.1 in compose.yaml with the server’s LAN address, add that address to NEXTCLOUD_TRUSTED_DOMAINS, and restrict the port to the proxy address in the firewall.

Nextcloud refuses a request from a domain that is not in NEXTCLOUD_TRUSTED_DOMAINS: instead of the interface you get an untrusted domain message.

Domain and HTTPS

Replace cloud.example.com with your single domain in the file you pick from proxy/, and put it in .env:

NEXTCLOUD_TRUSTED_DOMAINS=cloud.example.com
NEXTCLOUD_TRUSTED_PROXIES=172.16.0.0/12
NEXTCLOUD_OVERWRITE_PROTOCOL=https
NEXTCLOUD_OVERWRITE_CLI_URL=https://cloud.example.com

proxy/Caddyfile obtains a certificate automatically; proxy/nginx.conf expects a Certbot certificate; proxy/traefik.yaml uses the letsencrypt resolver. For Traefik in a container, replace 127.0.0.1 with a host gateway it can reach.

All three samples do two things without which Nextcloud misbehaves: they lift the upload size limit and redirect /.well-known/carddav and /.well-known/caldav to /remote.php/dav — otherwise calendar and contacts do not connect in clients.

docker compose up -d
curl --fail https://cloud.example.com/status.php

Backup

chmod +x backup.sh restore.sh
./backup.sh

The script enables maintenance mode, takes a PostgreSQL dump, archives the volume with the code, apps, and config.php, then turns maintenance mode off. Without maintenance mode the database and file copies can drift apart.

User files are not in the archive: their directory can grow to terabytes and is better copied incrementally:

rsync -a --delete /srv/nextcloud/data/ /mnt/backup/nextcloud-data/

A full restore needs three parts: the database dump, the code volume, and the file directory. Keep them consistent, and keep at least one copy off the server.

One detail that trips people up when backing up by hand: the Nextcloud installer creates a separate PostgreSQL role named oc_<admin name> for normal operation, and the tables belong to it rather than to the user from .env. That is why backup.sh dumps the role list alongside the database — without it the dump will not load into a clean PostgreSQL.

Restore

Restoring replaces the database and the code completely:

./restore.sh ./backups/nextcloud-YYYYMMDDTHHMMSSZ.tar
docker compose ps
curl --fail http://127.0.0.1:8080/status.php

Before replacing anything the script takes a safety copy of the current state, removes the database volume, and loads the dump into a clean database. The user file directory is untouched: if it was lost, restore it from your own copy before starting, otherwise Nextcloud shows entries without files.

After a restore it is worth rescanning the files:

docker compose exec -u www-data app php occ files:scan --all

Update

Take a backup and read the release notes. Upgrade strictly one major version at a time: you cannot jump from 32 to 34, the installer will stop the transition.

./backup.sh
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 app
docker compose exec -u www-data app php occ status

After the upgrade, look at Administration → Overview: new recommendations and warnings appear there when something is configured wrong.

Rollback

Nextcloud database migrations are irreversible: an older image will not start against a database a newer version has upgraded. Restore the pinned NEXTCLOUD_VERSION in .env and restore the archive taken before the update:

docker compose pull
./restore.sh ./backups/nextcloud-before-update.tar
docker compose up -d

Files uploaded after the update stay on disk, but the restored database has no records of them: bring them back with occ files:scan --all.

Stopping and complete removal

docker compose down removes the containers but keeps the database, the code, and the files. Complete, irreversible removal after verifying a backup:

docker compose down
docker volume rm nextcloud-html nextcloud-database
sudo rm -rf /srv/nextcloud/data
rm -rf ~/services/nextcloud

Sources: Docker installation, administration manual, reverse proxy, background jobs, caching and locking, and backup.

Troubleshooting

“Access through untrusted domain”

Nextcloud only accepts requests from domains on its list. Add yours to .env and restart:

grep NEXTCLOUD_TRUSTED_DOMAINS .env
docker compose up -d
docker compose exec -u www-data app php occ config:system:get trusted_domains

The variable is applied at container start; to change the list on a running instance use occ config:system:set trusted_domains 1 --value=cloud.example.com.

Behind a reverse proxy Nextcloud does not know the outside is HTTPS. Fill in NEXTCLOUD_TRUSTED_PROXIES, NEXTCLOUD_OVERWRITE_PROTOCOL=https, and NEXTCLOUD_OVERWRITE_CLI_URL in .env, then restart the stack.

Calendar and contacts do not connect in clients

Clients look for /.well-known/caldav and /.well-known/carddav. Those addresses have to redirect to /remote.php/dav — the samples in proxy/ already carry the rules. Check with:

curl -sI https://cloud.example.com/.well-known/caldav | head -3

Background jobs do not run

docker compose ps cron
docker compose exec -u www-data app php occ config:app:get core backgroundjobs_mode
docker compose logs --tail=50 cron

The mode must be cron. The value is written the first time cron.php runs, so right after installation the field can be empty — the cron container executes the job every five minutes.

Large files fail to upload

The limit usually comes from the reverse proxy rather than PHP. Nginx needs client_max_body_size, Caddy needs request_body max_size, and Traefik needs the buffering middleware; the samples in proxy/ are already configured. On the PHP side the size comes from NEXTCLOUD_PHP_UPLOAD_LIMIT.

Permission error on the data directory

Inside the container Nextcloud runs as UID 33:

ls -ld /srv/nextcloud/data
sudo chown -R 33:33 /srv/nextcloud/data

Files appeared on disk but not in the interface

Nextcloud keeps the file list in the database and does not scan the directory on its own. After copying files by hand, run:

docker compose exec -u www-data app php occ files:scan --all

The instance is stuck in maintenance mode

That happens when an upgrade was interrupted:

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

If the server complains about an unfinished upgrade, run occ upgrade first, and restore from an archive if that fails.

The checks page shows warnings

That is a normal state right after installation: some checks concern HTTPS and headers that only appear once the instance is published through a reverse proxy. Walk the list under Administration → Overview and close the items one by one — each links to the relevant documentation.

The server does not start after an update

docker compose logs --tail=200 app | grep -i "error\|upgrade\|migration"

You cannot skip a major version: upgrade one at a time. Downgrades are not supported — the only way back is restoring the archive taken before the update.

Official sources

Latest release: 2026-08-13 · GitHub Stars: 36,647 · metadata checked Aug 31, 2026, 9:31 AM UTC

Disclaimer

Fossary is an independent informational catalog and is not affiliated with the developers of the listed applications. We collect information from public sources and verify published recipes, but we do not develop, distribute, or control these applications.

A listing or validation status is not a requirement, endorsement, or personal recommendation to use an application. You decide whether it is suitable and use it at your own risk. We do not warrant an application's security, availability, or fitness for purpose and, to the extent permitted by law, are not liable for resulting loss or damage. Review its license, security settings, data processing, and backup procedures before installation.