Nextcloud als Docker produktiv machen – sicher, stabil und update-kontrolliert
Wie ich meine Nextcloud-Installation von „latest“-Überraschungen befreit, robuste Healthchecks eingebaut, Sicherheitswarnungen beseitigt und den Betrieb produktiv gemacht habe.
Ausgangslage
Nextcloud lief als Docker-Stack auf einer NAS und wurde über latest
automatisch aktualisiert. Das führte zu ungewollten Major-Upgrades (z. B. auf Hub 25/NC 32) und kurzzeitigen Ausfällen von Apps. Ziel war ein stabiler, reproduzierbarer Produktivbetrieb.
Ziele
- Keine Auto-Majorsprünge mehr – stattdessen feste Tags.
- Robuste Healthchecks, damit der Stack erst „grün“ ist, wenn die Services wirklich bereit sind.
- Watchtower/Auto-Updater entschärfen (Opt-out per Label).
- Sicherheits- & Einrichtungswarnungen systematisch abarbeiten.
1) Images „pinnen“ (statt latest
)
Der App-Container wurde auf den gewünschten Major-Zweig fixiert. Beispiel: nextcloud:32-apache
(nur Minor-Updates innerhalb von 32). Für maximale Kontrolle kann man sogar eine exakte Version oder einen Digest pinnen.
# Variante: stabiler Major-Zweig
image: nextcloud:32-apache
# Variante: exakte Version
# image: nextcloud:32.0.0-apache
# Variante: Digest (bombenfest)
# image: nextcloud@sha256:...
2) Watchtower-/Auto-Update Opt-out
Falls ein Auto-Updater aktiv ist, wird Nextcloud explizit ausgeschlossen:
labels:
com.centurylinklabs.watchtower.enable: "false"
3) Healthchecks, die wirklich prüfen
MariaDB war „unhealthy“, obwohl sie lief – Ursache war ein zu strenger/alter Healthcheck. Der neue Check verwendet zuerst den Applikations-User, fällt bei Bedarf auf Root zurück und gibt der DB Zeit zum Aufwärmen:
healthcheck:
test: ["CMD-SHELL",
"mariadb -h 127.0.0.1 -u\"$MYSQL_USER\" -p\"$MYSQL_PASSWORD\" -e \"SELECT 1\" \
|| mariadb-admin ping -h 127.0.0.1 -uroot -p\"$MYSQL_ROOT_PASSWORD\" \
|| exit 1"]
interval: 20s
timeout: 5s
retries: 15
start_period: 90s
Bei Redis und Nextcloud prüfen wir echte Endpunkte (redis-cli ping
, status.php
), damit der Stack erst „healthy“ ist, wenn alle Abhängigkeiten stehen.
4) Trusted Proxy & HTTPS korrekt setzen
Um Drosselungen durch die Brute-Force-Erkennung zu vermeiden, tragen wir den Reverse-Proxy als Trusted Proxy ein und erzwingen das richtige Protokoll:
environment:
TRUSTED_PROXIES: "10.0.0.21"
NEXTCLOUD_TRUSTED_DOMAINS: cloud.example.tld 10.0.0.5
OVERWRITEHOST: cloud.example.tld
OVERWRITEPROTOCOL: https
5) Sicherheits- & Einrichtungswarnungen aufräumen
- Fehlende Indizes:
occ db:add-missing-indices
- MIME-Type-Migrationen:
occ maintenance:repair --include-expensive
- Standard-Telefonregion:
occ config:system:set default_phone_region --value="DE"
- Wartungsfenster:
occ config:system:set maintenance_window_start --value="3"
(03:00). - Integritätsprüfung:
Core:
occ integrity:check-core
Apps (bei Bedarf):
occ integrity:check-app <appname>
, problematische App neu installieren oder EXTRA_FILE löschen.
6) Logging bändigen
Nach dem Aufräumen Log-Level auf „error“, dann rotieren:
occ log:manage --level error
occ log:manage --rotate
7) (Optional) Staging-Stack
Für künftige Major-Upgrades empfiehlt sich ein zweiter Stack mit separaten Volumes/DB und dem neuen Major-Tag. Erst nach erfolgreichem Test wird die Produktion angehoben.
Anonymisierte Compose-Basis
Die folgenden Snippets sind bewusst anonymisiert (keine realen IPs, Hostnamen, Passwörter):
MariaDB (mit robustem Healthcheck)
services:
mariadb:
image: mariadb:11.4-noble
container_name: nc-db
security_opt:
- no-new-privileges:true
command:
- --transaction-isolation=READ-COMMITTED
- --binlog-format=ROW
- --innodb-read-only-compressed=OFF
volumes:
- /srv/docker/nextcloud/db:/var/lib/mysql
- /srv/docker/nextcloud/mariadb-conf:/etc/mysql/conf.d
environment:
MYSQL_ROOT_PASSWORD: "REDACTED"
MYSQL_PASSWORD: "REDACTED"
MYSQL_DATABASE: nextcloud
MYSQL_USER: nextcloud
TZ: Europe/Berlin
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL",
"mariadb -h 127.0.0.1 -u\"$MYSQL_USER\" -p\"$MYSQL_PASSWORD\" -e \"SELECT 1\" \
|| mariadb-admin ping -h 127.0.0.1 -uroot -p\"$MYSQL_ROOT_PASSWORD\" \
|| exit 1"]
interval: 20s
timeout: 5s
retries: 15
start_period: 90s
labels:
com.centurylinklabs.watchtower.enable: "false"
Redis
redis:
image: redis:7.2.5
container_name: nc-redis
volumes:
- /srv/docker/nextcloud/redis:/data
environment:
TZ: Europe/Berlin
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "redis-cli ping || exit 1"]
interval: 30s
timeout: 10s
retries: 5
labels:
com.centurylinklabs.watchtower.enable: "false"
Nextcloud App + Cron (NC 32-Zweig, Watchtower-Opt-out)
nextcloud:
image: nextcloud:32-apache
container_name: nextcloud
depends_on: [mariadb, redis]
ports: ["8082:80"]
environment:
REDIS_HOST: redis
NEXTCLOUD_ADMIN_USER: admin
NEXTCLOUD_ADMIN_PASSWORD: "REDACTED"
NEXTCLOUD_TRUSTED_DOMAINS: cloud.example.tld 10.0.0.5
TRUSTED_PROXIES: "10.0.0.21"
OVERWRITEHOST: cloud.example.tld
OVERWRITEPROTOCOL: https
MYSQL_PASSWORD: "REDACTED"
MYSQL_DATABASE: nextcloud
MYSQL_USER: nextcloud
MYSQL_HOST: mariadb
TZ: Europe/Berlin
PHP_MEMORY_LIMIT: 1024M
PHP_UPLOAD_LIMIT: 1024M
volumes:
- /srv/docker/nextcloud/html:/var/www/html
- /srv/docker/nextcloud/custom_apps:/var/www/html/custom_apps
- /srv/docker/nextcloud/config:/var/www/html/config
- /srv/docker/nextcloud/data:/var/www/html/data
- /srv/docker/nextcloud/themes:/var/www/html/themes
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost/status.php"]
interval: 30s
timeout: 10s
retries: 5
labels:
com.centurylinklabs.watchtower.enable: "false"
cron:
image: nextcloud:32-apache
container_name: nextcloud-cron
entrypoint: /cron.sh
depends_on: [mariadb, redis]
volumes:
- /srv/docker/nextcloud/html:/var/www/html
- /srv/docker/nextcloud/custom_apps:/var/www/html/custom_apps
- /srv/docker/nextcloud/config:/var/www/html/config
- /srv/docker/nextcloud/data:/var/www/html/data
restart: unless-stopped
labels:
com.centurylinklabs.watchtower.enable: "false"
Lessons Learned
- Nie „latest“ in Produktion. Immer Tags/Digests pinnen.
- Healthchecks sind Gold wert. Sie verhindern „grüne“ Stacks mit halbfertigen Diensten.
- Sicherheitswarnungen sofort abarbeiten. Indizes & Migrations bringen messbare Performance und Ruhe in die Logs.
- Staging vor Produktion. Major-Upgrades zuerst testen, dann umstellen.
Mit diesen Schritten läuft Nextcloud bei mir jetzt stabil, reproduzierbar und ohne böse Überraschungen – genau so, wie eine Produktivumgebung sein soll.