Nextcloud Docker Compose setup with Postgres and Redis

Set up Nextcloud with Docker Compose from the official examples: PostgreSQL, Redis and a cron container, first login, updates, and when to use AIO instead.

By Toni LukeUpdated 6 min read
Contents12 sections

Before you start, read the warning at the top of that README. The image "is maintained by community volunteers and designed for expert use." For the quickest deployment with every Nextcloud Hub feature, the README points you to Nextcloud All-in-One (AIO), which Nextcloud GmbH maintains. There's a short section on AIO's own compose file near the end, so you can pick the right route.

Prerequisites

  • A 64-bit Linux host with Docker and the Compose plugin. The admin manual "strongly recommends" a 64-bit CPU, OS and PHP. On 32-bit, dates after 2038 break and some apps may not work.
  • RAM for your workload. Nextcloud doesn't publish one number. The manual gives 128MB per PHP process as the minimum and 512MB as the recommendation, and says total needs vary with users, apps and activity.
  • A reverse proxy, if the server will face the internet. The README's base examples provide "no TLS encryption", and it calls HTTPS "mandatory" for internet access.

The images used here are multi-arch. On 29 September 2026, Docker Hub listed nextcloud:35-apache, postgres:18-alpine and redis:alpine for both amd64 and arm64, so the same file works on a Raspberry Pi 5.

Step 1: pick the image variant

The README describes two variants:

  • apache: a full install with Apache built in, exposing port 80. It's the default for latest, and it's the one used here.
  • fpm: PHP-FPM only, on port 9000. You add your own web server, such as nginx, to serve static files and proxy requests.

Stick with apache unless you already run nginx and know why you'd want FPM.

Step 2: create the project folder and the database env file

bash
mkdir nextcloud && cd nextcloud

Create db.env. This is the file from the official Postgres example, and the app and database containers both read it:

ini
POSTGRES_PASSWORD=
POSTGRES_DB=nextcloud
POSTGRES_USER=nextcloud

Put a long random password after POSTGRES_PASSWORD=. Per the README, once all four database variables are known (the three above plus POSTGRES_HOST), the setup wizard won't ask for them. It also warns you to "ONLY use one database type."

Step 3: write compose.yaml

yaml
services:
  db:
    image: postgres:18-alpine
    restart: always
    volumes:
      - db:/var/lib/postgresql
    env_file:
      - db.env

  redis:
    image: redis:alpine
    restart: always

  app:
    image: nextcloud:35-apache
    restart: always
    ports:
      - 8080:80
    volumes:
      - nextcloud:/var/www/html
    environment:
      - POSTGRES_HOST=db
      - REDIS_HOST=redis
    env_file:
      - db.env
    depends_on:
      - db
      - redis

  cron:
    image: nextcloud:35-apache
    restart: always
    volumes:
      - nextcloud:/var/www/html
    entrypoint: /cron.sh
    depends_on:
      - db
      - redis

volumes:
  nextcloud:
  db:

This is adapted from two official sources. The db, redis, app and cron services come from the repository's with-nginx-proxy/postgres/apache example. The ports: 8080:80 mapping comes from the README's base apache example. Here's what changed:

  • Removed the nginx-proxy and acme-companion containers, along with their VIRTUAL_HOST and LETSENCRYPT_* variables and the proxy-tier network. Put your own reverse proxy in front instead (see the last section).
  • Pinned the image tags. The example uses postgres:alpine and nextcloud:apache, which move to new major versions on their own. The README says Nextcloud can only be upgraded one major version at a time, so an unpinned tag can jump too far. 35-apache is the current major (35.0.1, released 24 September 2026). PostgreSQL 18 is inside the manual's supported range of 14–18.
  • Dropped the SELinux :z/:Z volume suffixes. Keep them if your host runs SELinux.

The example has one comment worth keeping in mind: the cron and app containers' volumes config "must match."

Prefer MariaDB? The README's base apache example uses mariadb:lts with command: --transaction-isolation=READ-COMMITTED, the MYSQL_* variables and MYSQL_HOST=db. Use that instead of the Postgres service, not alongside it.

Step 4: start the stack

bash
docker compose up -d

The first start copies Nextcloud into the nextcloud volume and initialises the database, so give it a minute or two.

What you should see: per the README, Nextcloud at http://localhost:8080/ on the host, or http://your-server-ip:8080/ from another machine.

Step 5: finish setup in the browser

Because the database details are already set, the installation wizard asks only for an admin username and password. The README says that if you also set NEXTCLOUD_ADMIN_USER and NEXTCLOUD_ADMIN_PASSWORD, installation runs fully automatically with no wizard. If you set the database variables only partly, the wizard asks for them. Use db as the host and nextcloud as the database name and user.

Step 6: set trusted domains and check the config

Nextcloud only answers on hostnames it trusts. The image reads NEXTCLOUD_TRUSTED_DOMAINS, a space-separated list that's applied after install. For example, add this to the app service's environment::

yaml
      - NEXTCLOUD_TRUSTED_DOMAINS=cloud.example.com 192.168.1.50

To see the merged configuration, run the occ command the README gives. It hides passwords by default:

bash
docker compose exec -u33 app ./occ config:list system

(The README notes that on Alpine-based images the user ID is 82, not 33.) Don't rely on reading config.php directly. The image injects some settings through extra config files, so that file doesn't show everything.

Step 7: put it behind HTTPS

The README recommends a reverse proxy in front of Nextcloud that terminates TLS. So that Nextcloud sees the real client address and protocol, set these on the app service:

  • TRUSTED_PROXIES: your proxy's IP address, or a CIDR range for IPv4.
  • APACHE_DISABLE_REWRITE_IP=1, needed alongside TRUSTED_PROXIES.
  • If that doesn't work, the README's fallback is fixed values such as OVERWRITEHOST, OVERWRITEPROTOCOL=https and OVERWRITECLIURL.

One warning from the README: these values are written into config.php at install time, and removing the variables later doesn't remove them from the file. You'd have to edit config.php by hand. Where you can, set them before the first start.

For the proxy itself, see reverse proxy for a homelab: Caddy or Nginx Proxy Manager. Once the proxy handles traffic, you can remove the 8080:80 mapping.

Updating

With Compose, the README's update procedure is:

bash
docker compose pull
docker compose up -d

The container sees that the image version differs from the one in the volume and runs the upgrade itself. To move to the next major version, change 35-apache to 36-apache in both app and cron, then pull and start again. Never skip a major.

The alternative: Nextcloud AIO's compose file

If you'd rather not manage these containers yourself, AIO is Nextcloud's supported route, and its README suggests the compose file over docker run "for production usage." The core of AIO's compose.yaml is one mastercontainer:

yaml
name: nextcloud-aio
services:
  nextcloud-aio-mastercontainer:
    image: ghcr.io/nextcloud-releases/all-in-one:latest
    init: true
    restart: always
    container_name: nextcloud-aio-mastercontainer
    volumes:
      - nextcloud_aio_mastercontainer:/mnt/docker-aio-config
      - /var/run/docker.sock:/var/run/docker.sock:ro
    network_mode: bridge
    ports:
      - "80:80"
      - "8080:8080"
      - "8443:8443"
volumes:
  nextcloud_aio_mastercontainer:
    name: nextcloud_aio_mastercontainer

This is the official file with its inline comments stripped. Download the real one, because its comments explain which lines you must not change: the container name and the volume name both have to stay exactly as they are. Then open https://your-server-ip:8080 by IP address, not a domain. The AIO README warns that using a domain there is "likely to break later due to HSTS." AIO then creates the Nextcloud, database, Redis and backup containers for you.

AIO-specific cautions from its README:

  • Snap-based Docker isn't supported. It's generally only an issue on Ubuntu, and the README gives a command to check.
  • Some VPS hosts are on its "disrecommended" list. It says Hostinger's VPS "seem to miss a specific Kernel feature which is required for AIO to run correctly." It also flags older Strato VPS on Virtuozzo and hosts with a low numproc limit. The community image in this guide isn't named on that list.
  • Behind an existing reverse proxy, follow AIO's separate reverse-proxy docs. The basic steps assume nothing else is using ports 80 and 443.

Troubleshooting (documented issues only)

  • The wizard asks for database details anyway. You set only part of a database group. The README says you must set every variable for one database type, or it falls back to SQLite.
  • Proxy settings won't go away. See step 7: the values are in config.php now, so edit them there.
  • Upgrade refuses to run, or breaks. You probably skipped a major version. Go back to the previous major tag and step through them one at a time.
  • Background jobs don't run in a custom image. The examples README notes that a cron setup inside one container "must run as root or cron.php will not run." The separate cron service above avoids that.
  • AIO on Hostinger misbehaves. It's a known host limitation (above), not a problem with your config.

What to do next

Sources (8)Show
  1. nextcloud/docker README (official image docs: compose examples, environment variables, occ, updates) · accessed 2026-09-29
  2. nextcloud/docker example: with-nginx-proxy/postgres/apache compose.yaml and db.env · accessed 2026-09-29
  3. nextcloud/docker .examples README (cron notes) · accessed 2026-09-29
  4. Nextcloud All-in-One README (compose.yaml, ports, disrecommended VPS providers) · accessed 2026-09-29
  5. Nextcloud All-in-One compose.yaml · accessed 2026-09-29
  6. Nextcloud 35 Administration Manual: System requirements · accessed 2026-09-29
  7. Docker Hub tags checked: nextcloud:35-apache, postgres:18-alpine, redis:alpine (all list arm64 and amd64) · accessed 2026-09-29
  8. GitHub releases API: nextcloud/server (35.0.1, 2026-09-24), as recorded in the Nextcloud profile · accessed 2026-09-29