Skip to content

Deploy Nextcloud

A production-ready Nextcloud deployment on dockmesh: app container, PostgreSQL database, Redis cache, automatic HTTPS via the embedded Caddy, and nightly encrypted backups to S3.

  • Nextcloud at cloud.example.com with a valid Let’s Encrypt cert
  • Data stored in a named volume (backed up nightly)
  • PostgreSQL 16 for database
  • Redis for file locking (critical for multi-user installations)
  • Nginx-free config — dockmesh’s Caddy handles TLS and reverse proxying
  • Encrypted backups of the entire nextcloud_data volume + pg_dumpall of Postgres to S3
  • dockmesh installed on a host with ~50 GB of free disk (depends on your data volume)
  • DNS cloud.example.com → your dockmesh host’s public IP
  • Embedded Caddy enabled (setup)
  • An S3-compatible bucket for backups (AWS, Wasabi, Backblaze B2, MinIO — see Backup docs)

Stacks → New stack → name nextcloud → paste:

services:
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: nextcloud
POSTGRES_USER: nextcloud
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- db:/var/lib/postgresql/data
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD}
app:
image: nextcloud:29-apache
restart: unless-stopped
depends_on: [db, redis]
environment:
POSTGRES_HOST: db
POSTGRES_DB: nextcloud
POSTGRES_USER: nextcloud
POSTGRES_PASSWORD: ${DB_PASSWORD}
REDIS_HOST: redis
REDIS_HOST_PASSWORD: ${REDIS_PASSWORD}
NEXTCLOUD_TRUSTED_DOMAINS: cloud.example.com
TRUSTED_PROXIES: 172.16.0.0/12
OVERWRITEPROTOCOL: https
OVERWRITECLIURL: https://cloud.example.com
volumes:
- nextcloud_data:/var/www/html
cron:
image: nextcloud:29-apache
restart: unless-stopped
depends_on: [db, redis]
entrypoint: /cron.sh
volumes:
- nextcloud_data:/var/www/html
volumes:
db:
nextcloud_data:

In the stack’s Environment tab, define:

  • DB_PASSWORD — random 32 chars (use the Generate button)
  • REDIS_PASSWORD — random 32 chars

Both should be marked as secret (auto-detected by name).

Click Deploy. First pull takes ~2 min. Watch the logs — the app container does first-time setup automatically (Nextcloud CLI installer).

Once all four containers are running and healthy, move to step 4.

Stack detail → Proxy → Add route:

FieldValue
Domaincloud.example.com
Target containernextcloud_app_1
Target port80
TLSAutomatic

Caddy provisions a Let’s Encrypt cert (takes ~30s). Visit https://cloud.example.com — you should see the Nextcloud login page.

Nextcloud auto-generates an admin user on first boot. Check the logs:

Creating admin account ...
Admin user: admin
Admin password: <random-generated>

Log in, change the password immediately, create your real user accounts.

Backups → Jobs → New job:

  • Stacks: nextcloud
  • Target: your S3 target
  • Schedule: Daily 02:00
  • Pre-backup hook: preset PostgreSQL · pg_dumpall
  • Retention: Keep last 14
  • Encryption passphrase: (store in password manager)

The first backup runs whenever you click Run now. Subsequent backups run on schedule.

Exec into the app container (Containers → nextcloud_app_1 → Terminal) and run:

Terminal window
# Install recommended apps
php occ app:enable files_external
php occ app:enable admin_audit
# Set phone region (silences a warning)
php occ config:system:set default_phone_region --value=DE
# Set default share expiration
php occ config:app:set core shareapi_default_expire_date --value=yes

“Your installation has no default phone region” — run the php occ config:system:set default_phone_region command above.

“Memcache is not configured” — check REDIS_HOST in env; make sure Redis container is healthy.

Slow file syncs — enable cron properly (the cron service above does this). Verify php occ status shows last_cron: <recent>.

To update Nextcloud:

  1. Update image: nextcloud:29-apache to new major version (e.g. 30)
  2. Deploy — Nextcloud handles migrations in-container
  3. Bump PostgreSQL major once a year (separate migration step; see Nextcloud DB migration docs)