Nextcloud auf VPS mit Docker Compose einrichten
Installieren Sie Nextcloud sicher auf einem VPS mit Docker Compose, Postgres und Redis. Diese Anleitung zeigt die korrekte TLS-Konfiguration und ein zuverlässiges Backup-Skript.
Was Sie tatsächlich aufbauen
Diese Anleitung betreibt Nextcloud auf einem VPS mit Docker Compose, schaltet Let's Encrypt TLS davor und richtet ein Backup ein, das sich tatsächlich wiederherstellen lässt. Vier Container und ein Proxy: das offizielle nextcloud-Image, das auf dem Loopback-Interface lauscht, Postgres für sämtliche Dateimetadaten, Redis für die Dateisperren, eine zweite Instanz des Nextcloud-Images ausschließlich für den Cron-Job sowie nginx auf dem Host, der die TLS-Terminierung für alle Dienste übernimmt. Die Installation selbst dauert zwanzig Minuten, doch darauf kommt es nicht an. Zwei Entscheidungen in der ersten Stunde bestimmen, ob Ihre Dateien auch in einem Jahr noch vorhanden sind: eine echte Datenbank statt SQLite und ein Backup, das das Datenverzeichnis, die Datenbank und config.php als einen konsistenten Satz erfasst.
Dies setzt Ubuntu 24.04 LTS oder Debian 13, die Docker Engine mit dem Compose v2-Plugin aus dem offiziellen Docker-Repository sowie einen bereits auf den VPS zeigenden DNS A-Eintrag (plus AAAA bei vorhandenem IPv6) für cloud.example.com voraus. All dies erfordert einen Server unter Ihrer Kontrolle; TLS-Terminierung und Datenbank-Dumps lassen sich nicht auf einer fremden SaaS-Plattform umsetzen.
Dimensionierung: Was verbraucht tatsächlich Arbeitsspeicher
Der Speicherverbrauch von Nextcloud wird von drei Faktoren dominiert, von denen keiner direkt "Nextcloud" selbst ist.
PHP-Worker. Das -apache-Image bedient jede gleichzeitige Anfrage über einen Worker-Prozess, der einen PHP-Interpreter enthält. Jeder Worker kann bis zu PHP_MEMORY_LIMIT belegen, bevor PHP die Anfrage abbricht. Ihr Worst-Case-Speicherbedarf entspricht in etwa gleichzeitige Anfragen × Speicherlimit. Der Desktop-Sync-Client öffnet pro Benutzer mehrere parallele Verbindungen. Nicht die Anzahl der Benutzer, sondern die Gleichzeitigkeit bestimmt den Bedarf.
Die Datenbank. Postgres startet pro Verbindung einen Backend-Prozess und hält Shared Buffers im Arbeitsspeicher. Das Working-Set skaliert mit der Anzahl der Dateien, nicht mit der Anzahl der Bytes: oc_filecache führt eine Zeile pro Datei und Benutzer. Hunderttausend kleine Dateien belasten die Datenbank stärker als hundert große.
Vorschaubilder-Generierung. Beim Erstellen eines Thumbnails wird das Quellbild in voller Auflösung in den Arbeitsspeicher dekodiert. Videovorschauen nutzen ffmpeg. Die Ausführung von occ preview:generate-all führt diese Lastspitzen wiederholt hintereinander aus und ist der häufigste Grund, warum ein kleiner VPS durch den OOM-Killer beendet wird.
Redis ist vergleichsweise ressourcenschonend. Alles, was Sie später hinzufügen – Collabora, Volltextsuche, ein Antiviren-Scanner –, ist ein eigenständiger Dienst mit einem eigenen Speicherbedarf. Planen Sie dies bei der Dimensionierung ein, bevor Sie die Funktionen aktivieren.
Die Stellschrauben bei knappem RAM: Reduzieren Sie PHP_MEMORY_LIMIT, begrenzen Sie preview_max_x / preview_max_y / preview_max_filesize_image, beschränken Sie enabledPreviewProviders auf die Formate, die Sie tatsächlich verwenden, und konfigurieren Sie trashbin_retention_obligation sowie versions_retention_obligation so, dass das Datenverzeichnis nicht unbemerkt auf ein Vielfaches der Dateigröße anwächst. Richten Sie eine Swap-Datei ein. Swap ist langsam, aber ein OOM-Kill während eines Upgrades ist schlimmer.
Warum SQLite zu Problemen führt
Nextcloud wird mit SQLite-Unterstützung ausgeliefert und das offizielle Image verwendet diese standardmäßig. Verwenden Sie diese jedoch nicht. SQLite serialisiert Schreibvorgänge durch eine datenbankweite Sperre: Es kann immer nur ein Schreibvorgang gleichzeitig auf die gesamte Datei zugreifen. Nextcloud schreibt jedoch ständig Daten, wie Dateisperren, Aktivitätseinträge, Cache-Daten, Job-Status und Synchronisierungsanfragen eines Desktop-Clients, die viele parallele Anfragen erzeugen. Bei diesem Zugriffsmuster treten SQLSTATE[HY000]: General error: 5 database is locked und HTTP 500-Fehler auf. Das Versagen tritt genau dann ein, wenn die Instanz beginnt, produktiv genutzt zu werden.
Eine spätere Konvertierung ist mit occ db:convert-type möglich, stellt jedoch eine langwierige Alles-oder-Nichts-Migration auf einem aktiven Datensatz dar. Beginnen Sie direkt mit Postgres oder MariaDB.
Die Compose-Datei
Speichern Sie dies in /srv/nextcloud/compose.yaml, wobei Secrets in einer benachbarten .env-Datei mit dem Modus 600 abgelegt werden.
services:
db:
image: postgres:16-alpine
restart: unless-stopped
volumes:
- db:/var/lib/postgresql/data
environment:
POSTGRES_DB: nextcloud
POSTGRES_USER: nextcloud
POSTGRES_PASSWORD: ${DB_PASSWORD}
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD}
app:
image: nextcloud:35-apache
restart: unless-stopped
depends_on: [db, redis]
ports:
- "127.0.0.1:8080:80"
volumes:
- html:/var/www/html
- /srv/nextcloud/data:/var/www/html/data
environment:
POSTGRES_HOST: db
POSTGRES_DB: nextcloud
POSTGRES_USER: nextcloud
POSTGRES_PASSWORD: ${DB_PASSWORD}
REDIS_HOST: redis
REDIS_HOST_PASSWORD: ${REDIS_PASSWORD}
NEXTCLOUD_ADMIN_USER: admin
NEXTCLOUD_ADMIN_PASSWORD: ${ADMIN_PASSWORD}
NEXTCLOUD_TRUSTED_DOMAINS: cloud.example.com
TRUSTED_PROXIES: 172.16.0.0/12
OVERWRITEPROTOCOL: https
OVERWRITECLIURL: https://cloud.example.com
APACHE_DISABLE_REWRITE_IP: "1"
PHP_MEMORY_LIMIT: 512M
PHP_UPLOAD_LIMIT: 10G
cron:
image: nextcloud:35-apache
restart: unless-stopped
entrypoint: /cron.sh
depends_on: [db, redis]
volumes:
- html:/var/www/html
- /srv/nextcloud/data:/var/www/html/data
volumes:
db:
html:Fixieren Sie das Major-Tag und prüfen Sie das aktuelle Tag auf Docker Hub, bevor Sie 35 unverändert übernehmen. Stand 21. Oktober 2026 pflegt Nextcloud die Versionen 33, 34 und 35. Version 31 erreichte das Ende des Lebenszyklus im Februar 2026 und 32 im September 2026; ein aus einer älteren Anleitung kopiertes Tag installiert somit eine Version, die keine Fehlerbehebungen mehr erhält. latest führt bei einem zukünftigen docker compose pull ein Upgrade über eine Major-Grenze hinweg durch, was von Nextcloud nicht unterstützt wird.
Das Datenverzeichnis ist bewusst als Bind-Mount und nicht als Named-Volume konfiguriert: Ein Pfad, auf den ein Backup-Tool direkt zugreifen kann, ist wertvoller als eine saubere Struktur. Erstellen Sie es mit der UID www-data des Images und den von Nextcloud geforderten Berechtigungen:
sudo mkdir -p /srv/nextcloud/data
sudo chown -R 33:33 /srv/nextcloud/data
sudo chmod 0770 /srv/nextcloud/dataBeachten Sie die Port-Freigabe: 127.0.0.1:8080:80. Docker veröffentlicht Ports durch das Schreiben von DNAT-Regeln, die ausgewertet werden, bevor die INPUT-Chain von ufw das Paket überhaupt sieht. Ein bloßes 8080:80 stellt ein unverschlüsseltes Nextcloud ins öffentliche Internet, ungeachtet der ufw-Einstellungen. Die Bindung an das Loopback-Interface hält den Dienst von der öffentlichen Schnittstelle fern. Die Firewall muss dann nur noch den Proxy zulassen. Wenn Sie SSH nicht für das gesamte Internet offen lassen möchten, ermöglicht der Zugriff auf den VPS über ein selbst gehostetes WireGuard VPN, den Port 22 vollständig aus den öffentlichen Regeln zu entfernen:
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enableStarten Sie den Dienst mit docker compose up -d und beobachten Sie anschließend docker compose logs -f app. Der erste Start kopiert den gesamten Anwendungsbaum in das Volume und führt den Installer aus; der Container antwortet erst, wenn dieser Vorgang abgeschlossen ist.
TLS und der Reverse Proxy
Installieren Sie nginx und certbot aus den Paketquellen der Distribution, erstellen Sie einen einfachen Port-80-Server-Block mit dem korrekten server_name und lassen Sie certbot diesen anschließend umschreiben. Die Funktionsweise der HTTP-01-Challenge, der Erneuerungs-Timer und die Fehlerursachen werden ausführlich in Ausstellen von Let's Encrypt-Zertifikaten mit certbot und nginx unter Ubuntu 24.04 behandelt:
sudo apt install nginx certbot python3-certbot-nginx
sudo certbot --nginx -d cloud.example.comCertbot fügt die ssl_certificate-Zeilen sowie den :80 → :443-Redirect hinzu und installiert einen systemd-Timer, der das 90-Tage-Zertifikat erneuert. Überprüfen Sie dessen Existenz mit systemctl list-timers | grep certbot; ein nicht aktivierter Erneuerungs-Timer ist eine 90-Tage-Zeitbombe.
Der Proxy-Block selbst:
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name cloud.example.com;
# certbot manages ssl_certificate / ssl_certificate_key here
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
client_max_body_size 10G;
client_body_timeout 300s;
location = /.well-known/carddav { return 301 /remote.php/dav; }
location = /.well-known/caldav { return 301 /remote.php/dav; }
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_request_buffering off;
proxy_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}Fügen Sie bei nginx 1.25.1 und neuer http2 on; hinzu. Diese Direktive existiert in 1.25.0 nicht, und nginx startet nicht, wenn sie dort vorhanden ist. Ubuntu 24.04 liefert einen älteren Build aus, bei dem das Äquivalent listen 443 ssl http2; lautet. nginx -t zeigt Ihnen an, welche Variante Ihr Build akzeptiert.
Wenn client_max_body_size zu klein gewählt ist, lehnt nginx einen großen Upload direkt mit einem 413-Fehler ab. Sind die Read-Timeouts zu kurz, bricht der Upload mittendrin ab. Die oben genannten Werte verhindern beides. proxy_request_buffering off streamt den Upload direkt durch, anstatt die gesamte Datei zuerst auf die Festplatte des Proxys zu schreiben.
nginx auf dem Host ist die einfachste funktionierende Lösung für eine einzelne Anwendung. Wenn Nextcloud sich den VPS mit anderen Containern teilen soll, verlagert Betrieb von Traefik als Docker Compose Reverse Proxy für mehrere Anwendungen das Routing und die Zertifikatsausstellung in Container-Labels; die gleichen Bedenken hinsichtlich client_max_body_size und Timeouts treten dort als Middleware- und Transport-Einstellungen erneut auf.
trusted_proxies und overwriteprotocol
Hier machen die meisten selbst gehosteten Nextcloud-Instanzen Fehler, wobei die Symptome oft nichts mit der eigentlichen Ursache zu tun haben.
X-Forwarded-Proto: https wird nur berücksichtigt, wenn die Anfrage von einer Adresse stammt, die in trusted_proxies aufgeführt ist. Wenn dies nicht der Fall ist, geht Nextcloud davon aus, dass die Anfrage über unverschlüsseltes HTTP erfolgt, und generiert http://-URLs. Der Proxy leitet diese auf HTTPS um, der Browser folgt der Weiterleitung, und Nextcloud generiert erneut http://. Dies führt zu einer Redirect-Schleife. OVERWRITEPROTOCOL: https erzwingt das Protokoll unabhängig davon.
Die Falle bei TRUSTED_PROXIES besteht darin, dass die Adresse, die Nextcloud sieht, nicht 127.0.0.1 ist. nginx läuft auf dem Host und verbindet sich mit einem veröffentlichten Port, sodass der Container das Docker-Bridge-Gateway sieht, also eine Adresse aus 172.x. Ermitteln Sie das tatsächliche Subnetz:
docker network inspect nextcloud_default \
-f '{{range .IPAM.Config}}{{.Subnet}}{{end}}'Tragen Sie diese CIDR (oder das abdeckende 172.16.0.0/12) in TRUSTED_PROXIES ein. Ist der Bereich zu weit gefasst, kann jeder Client X-Forwarded-For fälschen. Ist er falsch konfiguriert, erscheint jeder Login so, als käme er von der Gateway-Adresse. Der Brute-Force-Schutz sperrt dann die gesamte Instanz auf einmal, und die Admin-Übersicht zeigt die Meldung: "Die Konfiguration des Reverse-Proxy-Headers ist falsch, oder Sie greifen über einen nicht vertrauenswürdigen Proxy auf Nextcloud zu."
OVERWRITECLIURL ist für den cron-Container wichtig, da dieser keine eingehende Anfrage hat, von der er einen Hostnamen ableiten könnte. Ohne diese Einstellung generieren Hintergrundprozesse Links zu localhost, und E-Mail-Benachrichtigungen enthalten unbrauchbare URLs.
Hintergrund-Jobs: cron statt AJAX
Der Standard-Job-Runner von Nextcloud ist AJAX: Jobs werden als Nebeneffekt ausgeführt, wenn ein Benutzer eine Seite lädt. Da um 04:00 Uhr niemand surft, bleiben das Löschen von Papierkörben, die Bereinigung von Versionen, die Erstellung von Vorschaubildern und föderierte Wiederholungsversuche hängen. Das erste Symptom ist ein Datenverzeichnis, das unaufhörlich wächst. Der oben genannte cron-Dienst führt die offizielle /cron.sh-Schleife auf denselben Volumes aus. Konfigurieren Sie Nextcloud so, dass es diesen Dienst verwendet:
docker compose exec -u www-data app php occ background:cronJeder occ-Befehl folgt diesem Schema: docker compose exec -u www-data app php occ <command>. Es lohnt sich, dafür einen Alias anzulegen.
Backups: drei Dinge oder gar keine
Ein reines Dateisystem-Backup führt bei der Wiederherstellung zu einer defekten Instanz. Das Datenverzeichnis enthält die Bytes; Postgres verwaltet den Datei-Cache, Freigaben, Benutzer und den Anwendungsstatus; config.php speichert die Datenbank-Zugangsdaten, die Instanz-ID und das Passwort-Salt. Stellen Sie die Dateien ohne die Datenbank wieder her, kann Nextcloud sie nicht sehen. Stellen Sie die Datenbank ohne config.php wieder her, kann sie die Datenbank nicht öffnen. Stellen Sie eine alte Datenbank gegen ein neueres Datenverzeichnis wieder her, zeigen Freigaben auf Dateien, die verschoben wurden.
Sichern Sie alle drei Komponenten von einer in den Wartungsmodus versetzten Instanz:
#!/usr/bin/env bash
set -euo pipefail
cd /srv/nextcloud
DEST="/var/backups/nextcloud/$(date -u +%Y%m%dT%H%M%SZ)"
mkdir -p "$DEST"
occ() { docker compose exec -T -u www-data app php occ "$@"; }
occ maintenance:mode --on
trap 'occ maintenance:mode --off' EXIT
docker compose exec -T db \
pg_dump -U nextcloud --clean --if-exists nextcloud | gzip > "$DEST/db.sql.gz"
docker compose exec -T app \
tar -C /var/www/html -cf - config custom_apps themes > "$DEST/app.tar"
rsync -a --delete /srv/nextcloud/data/ /var/backups/nextcloud/data/Der Wartungsmodus sorgt dafür, dass der Dump und die Dateikopie konsistent sind. Überspringen Sie diesen Schritt, erfassen Sie unter Umständen eine Datenbank, die auf eine Datei verweist, die rsync noch nicht erreicht hat. Beachten Sie, dass das Skript datierte Datenbank-Dumps aufbewahrt, aber nur einen rollierenden Spiegel des Datenverzeichnisses erstellt. rsync --delete überschreibt diesen bei jedem Durchlauf, sodass nur der neueste Dump mit der Dateikopie zusammenpasst.
Übertragen Sie die Daten anschließend vom Server. Ein Backup, das auf demselben VPS liegt wie das zu sichernde System, ist lediglich eine Kopie, kein Backup. restic in Richtung Objektspeicher oder auf einen zweiten Host ist die übliche Lösung; dessen Deduplizierung geht mit dem Datenverzeichnis deutlich effizienter um als ein nächtlicher tarball. Die vollständige Einrichtung, von der Repository-Initialisierung über den nächtlichen Timer bis hin zur Wiederherstellungsübung, finden Sie unter Off-Box-VPS-Backups mit restic.
Die Wiederherstellung ist nicht einfach der umgekehrte Vorgang. Ein frisch gestarteter Stack führt den Installer aus und schreibt eine brandneue config.php, eine neue Instanz-ID und ein neues Passwort-Salt. Der Import des Dumps über diese neue Identität führt zu defekten Sitzungen und ungültigen Freigabe-Tokens. Stellen Sie zuerst die alte Identität wieder her, und zwar in dieser Reihenfolge:
docker compose up -d && docker compose stop app cron # create the volumes, then halt the app
sudo rsync -a --delete /var/backups/nextcloud/data/ /srv/nextcloud/data/
docker compose run --rm -T --entrypoint "" app \
tar -C /var/www/html -xf - < app.tar # the original config.php returns
gunzip -c db.sql.gz | docker compose exec -T db psql -U nextcloud -d nextcloud
docker compose start app cron
docker compose exec -T -u www-data app php occ maintenance:mode --off
docker compose exec -T -u www-data app php occ files:scan --allfiles:scan gleicht den Datei-Cache mit dem tatsächlichen Zustand auf der Festplatte ab. Üben Sie diesen Vorgang einmal auf einem separaten VPS, bevor Sie ihn im Ernstfall benötigen. Die gleiche Trennung zwischen Bytes auf der Festplatte und Metadaten in Postgres gilt für jede andere Anwendung dieser Art. Deshalb führt ein Immich-Backup, das die Bibliothek, aber nicht die Datenbank erfasst, zu einer leeren Zeitleiste.
Upgrades: Immer nur eine Hauptversion gleichzeitig
Nextcloud unterstützt Upgrades von exakt einer Hauptversion auf einmal. Mit dem offiziellen Docker-Image führt ein Sprung von 29 auf 31 niemals zum Upgrader. Der Entrypoint vergleicht die Hauptversionen, bevor er occ upgrade ausführt, gibt Can't start Nextcloud because upgrading from <installed version> to <image version> is not supported. gefolgt von It is only possible to upgrade one major version at a time. aus und beendet sich. Der Container startet nicht (mit restart: unless-stopped startet er immer wieder neu und gibt dieselben Zeilen aus), der Wartungsmodus wird nicht aktiviert, und die Daten sowie die Datenbank bleiben unverändert. Setzen Sie das Tag auf die nächste Hauptversion und starten Sie erneut.
Das Docker-Upgrade läuft wie folgt ab: Erstellen Sie ein Backup, ändern Sie das Tag in den Diensten app und cron um eine Hauptversion nach oben (von 35 auf 36, sobald 36 erscheint, was Nextcloud für Februar 2027 plant), führen Sie dann docker compose pull && docker compose up -d und anschließend docker compose logs -f app aus. Der Entrypoint des Images erkennt den neueren Code im Vergleich zu den vorhandenen Daten und führt occ upgrade selbstständig aus. Unterbrechen Sie diesen Vorgang nicht. Wenn die Logs keine Aktivität mehr zeigen, führen Sie docker compose exec -u www-data app php occ status aus und prüfen Sie versionstring sowie ob die Apps wieder aktiviert wurden.
Zwei Regeln bewahren Sie vor Problemen: Erhöhen Sie immer nur um eine Hauptversion, verifizieren Sie den Erfolg und erhöhen Sie dann erst weiter. Ändern Sie niemals das Tag beim Dienst app, ohne cron entsprechend anzupassen; zwei unterschiedliche Nextcloud-Versionen, die auf dieselbe Datenbank zugreifen, führen zu Datenkorruption.
Die Fehler, die Sie tatsächlich sehen werden
"Your data directory is readable by other people. Please change the permissions to 0770 so that the directory cannot be listed by other people." Die letzte Ziffer des Modus-Werts für das Verzeichnis, die für andere Benutzer steht, ist nicht null. Jedes gesetzte Lese-, Schreib- oder Ausführungs-Bit für andere löst diese Meldung aus. Gruppen-Bits werden nicht geprüft, da 0770 der Gruppe bereits vollen Zugriff gewährt. Nextcloud versucht zunächst, chmod 0770 selbstständig durchzuführen, und warnt nur bei einem Fehlschlag. Bei einem Bind-Mount bedeutet dies meist, dass das Verzeichnis nicht dem Benutzer mit der UID 33 gehört. sudo chown -R 33:33 /srv/nextcloud/data und sudo chmod 0770 /srv/nextcloud/data.
"Your data directory is invalid. Ensure there is a file called ".ncdata" in the root of the data directory." Der Bind-Mount zeigt auf einen Pfad, den Nextcloud nie initialisiert hat, es liegt ein Tippfehler im Pfad vor oder ein leeres Verzeichnis wurde unter einer laufenden Instanz untergeschoben. Prüfen Sie, ob der Host-Pfad mit der Volume-Definition übereinstimmt.
"Access through untrusted domain." Der Hostname in der Anfrage ist nicht in trusted_domains enthalten. NEXTCLOUD_TRUSTED_DOMAINS gilt nur bei der Erstinstallation; danach muss die Einstellung live angepasst werden: occ config:system:set trusted_domains 1 --value=cloud.example.com.
502 Bad Gateway, mit connect() failed (111: Connection refused) while connecting to upstream in /var/log/nginx/error.log. nginx konnte unter 127.0.0.1:8080 keinen Dienst erreichen. Entweder initialisiert der Container noch (prüfen Sie docker compose logs app), er wurde beendet (docker compose ps) oder die Port-Freigabe stimmt nicht mit dem proxy_pass-Port überein. Überprüfen Sie dies mit ss -ltnp | grep 8080.
Eine Redirect-Schleife oder "insecure"-Warnungen in der Admin-Übersicht. OVERWRITEPROTOCOL: https fehlt oder TRUSTED_PROXIES enthält nicht das Docker-Gateway-Subnetz. Siehe dazu den Abschnitt über Proxys weiter oben.
LockedException: "files/..." is locked. Wenn REDIS_HOST konfiguriert ist, nutzt das Image Redis als Locking-Backend, wodurch veraltete Sperren selten sind. Ohne diese Einstellung verbleiben Sperren in der Datenbanktabelle oc_file_locks; eine während des Schreibvorgangs abgebrochene Anfrage hinterlässt dort Datensätze. Stellen Sie sicher, dass Redis tatsächlich verwendet wird – occ config:system:get memcache.locking sollte die Redis-Klasse zurückgeben –, bevor Sie Sperr-Einträge manuell löschen.
"The PHP memory limit is below the recommended value of 512 MB." Erhöhen Sie PHP_MEMORY_LIMIT und erstellen Sie den Container neu. Beachten Sie dabei die Auswirkungen auf den maximalen Speicherverbrauch im Worst-Case-Szenario.
Was bei Skalierung fehlschlägt
Die erste Hürde ist das Datenverzeichnis, das über das Volume hinauswächst. Die Vergrößerung eines Volumes auf einem VPS erfordert ein Resizing sowie eine Erweiterung des Dateisystems. Dies ist bei einer geplanten Durchführung deutlich weniger problematisch als bei einer Auslastung von 100 %. Richten Sie daher jetzt eine Überwachung der Festplattenbelegung ein, nicht erst später.
Die zweite Hürde ist oc_filecache. Dateiauflistungen und Synchronisations-Scans verlangsamen sich mit steigender Zeilenanzahl. Die Lösung liegt in der Datenbankoptimierung: Betreiben Sie Postgres auf schnellem Speicher, stellen Sie ausreichend Shared Memory bereit und bereinigen Sie veraltete Daten sowie Versionen über Aufbewahrungsrichtlinien, anstatt sie unbegrenzt ansammeln zu lassen.
Die dritte Hürde ist die Vorschau-Generierung, die mit allen anderen Prozessen konkurriert. Beschränken Sie auf kleinen Systemen die Vorschau-Anbieter und führen Sie occ preview:generate-all niemals während der Arbeitszeit aus. Wenn der Großteil Ihrer Daten aus Fotos von Mobiltelefonen besteht, sollte die Erstellung der Vorschaubilder auf einen dedizierten Fotoserver ausgelagert werden. Vergleich von PhotoPrism und Immich hinsichtlich RAM, Smartphone-Apps und Backup-Befehlen erläutert die Anforderungen dieser Lösungen im Vergleich zu einer Nextcloud-Instanz.
Darüber hinaus ist die ehrliche Antwort, dass Zusatzdienste eigene Maschinen benötigen. Collabora und die Volltextsuche sind eigenständige, speicherintensive Dienste. Sie auf dem Server zu betreiben, der gleichzeitig Ihre einzige Dateikopie enthält, vergrößert den Fehlerbereich ohne nennenswerten Vorteil. Wenn Sie Dokumente im Browser bearbeiten möchten, entscheiden die vom Anbieter vorgegebenen RAM-Mindestanforderungen und Verbindungslimits, die OnlyOffice von Collabora unterscheiden, welche Lösung auf einem VPS mit 2 bis 4 GB RAM überhaupt betrieben werden kann. Lagern Sie die Dateispeicherung auf S3-kompatiblen Speicher aus, sobald das Volume nicht mehr ausreicht. Beachten Sie dabei, dass dies Backups erschwert, nicht vereinfacht: Die Datenbank enthält weiterhin die Metadaten und muss synchron mit dem Bucket gesichert werden.
Sobald die Instanz von echten Benutzern verwendet wird, schalten Sie Uptime Kuma davor, damit Sie von Ausfallzeiten erfahren, bevor die Sync-Clients dies tun. Eine Private Cloud lässt sich gut mit einem eigenen Mailserver kombinieren. Wenn Sie Dienste nicht manuell miteinander verknüpfen möchten, vergleichen Cloudron, CasaOS und Coolify die Plattformen, die dies für Sie übernehmen. Falls als Nächstes eine selbst gehostete Suchmaschine geplant ist, erwarten Sie eine andere Art von Problemen als die oben genannten: Die 429-Fehler von SearXNG resultieren entweder aus dem eigenen Rate-Limiter oder daraus, dass die Upstream-Suchmaschinen Ihre VPS-IP blockieren. Nur das Logfile verrät Ihnen, welche Ursache vorliegt.
FAQ
Kann ich Nextcloud mit SQLite statt Postgres betreiben?
Das ist möglich und das offizielle Image erlaubt dies, aber ein einzelner Desktop-Sync-Client, der parallele Anfragen sendet, wird auf SQLSTATE[HY000]: General error: 5 database is locked und HTTP 500-Fehler stoßen. SQLite setzt eine datenbankweite Schreibsperre, während Nextcloud permanent schreibt: Dateisperren, Aktivitätszeilen und Job-Status. Beginnen Sie direkt mit Postgres oder MariaDB; occ db:convert-type existiert zwar, ist aber eine langwierige Alles-oder-Nichts-Migration bei laufendem Betrieb.
Wie viel RAM benötigt ein Nextcloud-VPS tatsächlich?
Planen Sie nach der Anzahl der gleichzeitigen Zugriffe, nicht nach der Anzahl der Benutzer. Der Worst-Case für den Arbeitsspeicher entspricht in etwa der Anzahl der parallelen Anfragen multipliziert mit PHP_MEMORY_LIMIT, zuzüglich der Postgres Shared Buffers und einem Backend-Prozess pro Verbindung, sowie der Lastspitzen bei der Vorschaubild-Generierung. Ein 2 GB-Server reicht für eine kleine Instanz im Haushalt, wenn Sie die Vorschau-Generierung begrenzen und Swap hinzufügen; fügen Sie Collabora oder eine Volltextsuche hinzu, müssen Sie ein zweites Set an residenten Diensten einplanen.
Warum schlagen große Uploads hinter dem nginx Reverse Proxy fehl?
Zwei Einstellungen am Proxy sind dafür meist verantwortlich. Wenn client_max_body_size auf dem Standardwert von 1 MB belassen wird, weist nginx jede größere Anfrage direkt mit einem 413 (Request Entity Too Large) ab, was im nginx-Error-Log und nicht als Teil-Datei erscheint. Zu kurze proxy_read_timeout / proxy_send_timeout-Werte brechen lange Übertragungen mittendrin ab. Setzen Sie beide Werte großzügig, stellen Sie proxy_request_buffering off auf Streaming statt Spooling um und erhöhen Sie PHP_UPLOAD_LIMIT im App-Container entsprechend.
Warum leitet Nextcloud in einer Endlosschleife weiter oder warnt vor dem Reverse Proxy?
Der Container sieht nginx nicht unter 127.0.0.1, sondern das Docker-Bridge-Gateway, welches sich in 172.x befindet. Wenn diese Adresse in TRUSTED_PROXIES fehlt, wird der X-Forwarded-Proto: https-Header ignoriert, Nextcloud generiert http://-URLs und der Proxy leitet diese zurück. Setzen Sie TRUSTED_PROXIES auf das tatsächliche Bridge-Subnetz und fixieren Sie OVERWRITEPROTOCOL: https.
Kann ich Nextcloud direkt von 29 auf 31 aktualisieren?
Nein. Nextcloud unterstützt pro Upgrade-Vorgang nur eine Hauptversion. Beim offiziellen Docker-Image prüft der Entrypoint die Hauptversionen, bevor er occ upgrade ausführt, gibt It is only possible to upgrade one major version at a time. aus und beendet den Prozess. Der Container startet also nicht und Ihre Daten sowie die Datenbank bleiben unverändert. Setzen Sie das Tag stattdessen auf 30: Erstellen Sie ein Backup, erhöhen Sie das Tag bei den app- und cron-Diensten um eine Hauptversion, führen Sie docker compose pull && docker compose up -d aus, prüfen Sie den Status mit occ status und wiederholen Sie den Vorgang anschließend.