Es gibt Fehler, die sind kaputt genug um zu nerven, aber nicht kaputt genug um sich vernünftig zu melden. Genau so einer ist mir letztens untergekommen: nextcloud hinter nginx, Login-Maske aufgerufen, Nutzer und Kennwort eingegeben, abgeschickt – und dann dreht sich die Anmelde-Animation. Und dreht sich. Und dreht sich.
Das Symptom
Der Ablauf war jedes Mal identisch, egal mit welchem Konto:
- Korrekte Zugangsdaten: die Animation läuft endlos weiter.
- Browser neu laden (F5): wir sind angemeldet, alles funktioniert.
- Falsches Kennwort: die Fehlermeldung kommt sofort.
- Android-App: verbindet sich gar nicht erst.
Der letzte Punkt ist eigentlich der interessanteste. Die App macht nämlich nichts anderes, als das Web-Login in einem eingebetteten Browser zu öffnen. Klemmt das Web-Login, klemmt die App gleich mit.
Warum die Anmeldung hängt
Die Ursache liegt weder bei nginx noch bei nextcloud allein. Sie sitzt im Missverständnis zwischen beiden. TLS wird auf dem nginx terminiert, dahinter läuft nextcloud im Klartext auf einem anderen Port. Von außen ist das https, intern ist es http – und nextcloud weiß davon nichts.
Also baut nextcloud seine URLs so, wie es die Welt sieht: mit einem http:// vorne dran. Der Login-POST selbst geht durch, die Session wird gesetzt. Nur verweist die Antwort auf eine unverschlüsselte Adresse. Der Browser blockt das als aktiven Mixed Content, das JavaScript im Login-Formular bekommt nie eine Rückmeldung – und dreht weiter seine Runden.
Damit erklärt sich auch der Rest. Nach F5 sind wir drin, weil das Session-Cookie längst gesetzt ist. Der Reload holt schlicht die Seite, die der Redirect nicht liefern konnte.
Ein falsches Kennwort wird sofort quittiert, weil dieser Pfad gar keinen Redirect erzeugt. Die Fehlermeldung landet direkt in der bereits geladenen Seite. Und die App scheitert am Login Flow v2: sie fragt einen Endpunkt an und bekommt JSON mit zwei URLs zurück. Stehen die als http:// drin, bricht sie ab.
Erst prüfen, dann schrauben
Ein einziges Kommando reicht, um die Vermutung zu bestätigen:
curl -s -X POST https://cloud.example.com/index.php/login/v2 | jq
Steht in den zurückgegebenen Adressen http:// statt https://, haben wir unseren Übeltäter gefunden.

Der Fix in der config.php
'overwriteprotocol' => 'https',
'trusted_proxies' => ['10.0.0.5'],
'overwrite.cli.url' => 'https://cloud.example.com',
'trusted_domains' => ['cloud.example.com'],
Der eigentliche Schalter ist overwriteprotocol. Damit sagen wir nextcloud: egal was du auf deinem Port siehst, nach außen ist das https. Anschließend php-fpm neu laden, fertig.
Bei trusted_proxies lohnt ein zweiter Blick. Dort gehört die IP hinein, mit der nginx das Backend tatsächlich anspricht. In Container-Setups ist das die Adresse aus dem Container-Netz, nicht die LAN-IP des Hosts. Ein Blick ins Access-Log des Backends klärt die Frage in Sekunden.
Ein Wort zu overwrite.cli.url
Dieser Wert wird gerne übersehen und steht in vielen Setups auf der internen Adresse – bei mir zum Beispiel lange auf https://192.168.1.3:8080. Er liefert die Basis-URL für alles, was ohne HTTP-Request abläuft: Cronjobs, Benachrichtigungsmails, Freigabe-Links aus Hintergrund-Jobs.
Die Folge ist unspektakulär, aber ärgerlich. Freigabe-Links zeigen dann auf eine Adresse, die von außen niemand erreicht. Für den Login spielt der Wert keine Rolle, für den Alltag schon.
Und overwritehost? Den brauchen wir in den meisten Fällen gar nicht. Solange nginx den Host-Header sauber durchreicht, leitet nextcloud den Hostnamen selbst korrekt ab. Wer ihn trotzdem setzt, verliert nebenbei den direkten Zugriff auf die interne Adresse – sämtliche Assets und Redirects zeigen ab dann auf die öffentliche Domain.
Die nginx-Seite
location / {
proxy_pass http://192.168.1.3:8080;
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_set_header X-Forwarded-Port 443;
}
Der wichtigste Header ist hier X-Forwarded-Proto. Fehlt er, hat nextcloud ohne overwriteprotocol überhaupt keine Chance, das Schema korrekt zu erraten. Die Details zu den einzelnen Direktiven stehen in der Dokumentation des nginx-Proxy-Moduls, die Gegenseite beschreibt das Admin-Handbuch von nextcloud.
Wer ohnehin gerade an der Proxy-Konfiguration schraubt: eine Wartungsseite für streikende Backends passt gut daneben.
Und wenn es danach immer noch hängt?
Dann lohnt ein Blick auf die Bruteforce-Protection. Ohne korrekt gesetztes trusted_proxies sieht nextcloud sämtliche Anmeldungen von einer einzigen IP kommen – nämlich der des Proxys. Nach ein paar Fehlversuchen wird exponentiell gedrosselt, bis zu rund 30 Sekunden pro Request. Die Fehlversuche können dabei von völlig anderen Nutzern stammen.
occ security:bruteforce:attempts <proxy-ip>
Ein Detail spricht allerdings dagegen: bei einer Drosselung würde auch das falsche Kennwort verzögert quittiert. Kommt die Fehlermeldung sofort, ist die Bruteforce-Protection nicht die Ursache.
Fazit
Der Fehler sieht nach nextcloud aus, sitzt aber im Zusammenspiel mit dem Proxy. Wer TLS auf dem nginx terminiert, muss das dem Backend explizit mitteilen. Zuverlässig erraten wird es nicht.
Und für das nächste Mal, wenn wir vor einer endlos drehenden Animation sitzen: der Netzwerk-Tab im Browser ist schneller als jede Vermutung. Den POST auf /login ansehen, in den Location-Header schauen. Dort steht die Antwort meistens schon.