Timeouts in Nextcloud News   Vor kurzem aktualisiert!


cURL-Timeouts: DNS-Optimierung mit Unbound

Tritt in den Log-Dateien von Nextcloud sporadisch oder in regelmäßigen Abständen folgender Fehler auf?

cURL error 28: Resolving timed out after 3000 milliseconds

Dieser Fehler betrifft besonders häufig die Nextcloud News App. Die Ursache liegt oft nicht an Nextcloud selbst, sondern an Trägheiten in der DNS-Auflösung des zugrundeliegenden Systems – speziell im Zusammenspiel mit IPv6.

Nextcloud News, Cron & Unbound

Um das Problem zu verstehen, hilft ein Blick auf das Zusammenspiel der beteiligten Komponenten:

  • Nextcloud News: Eine RSS/Atom-Feed-Reader-App für Nextcloud. Sie ruft im Hintergrund regelmäßig externe Webseiten und RSS-Feeds (wie rss.sueddeutsche.de oder tagesschau.de) ab.
  • Nextcloud Cron (cron.php): Nextcloud führt Hintergrundaufgaben nicht permanent aus, sondern verlässt sich auf den Linux-System-Cron. Dieser stößt periodisch (z. B. alle 5 Minuten) Aufgaben an. Aus diesem Grund tauchen die Timeout-Meldungen im Log oft schlagartig in Blöcken auf, wenn der Cronjob Dutzende Feeds gleichzeitig aktualisieren möchte.
  • Unbound: Ein performanter, validierender und cachender DNS-Resolver, der lokal auf dem Server läuft. Er sorgt dafür, dass DNS-Anfragen nicht bei jedem Aufruf ins Internet geschickt werden müssen, sondern blitzschnell aus dem RAM beantwortet werden.

Fehlersuche im System

Um festzustellen, ob DNS-Timeouts das System ausbremsen, bieten sich unter Linux verschiedene Suchstrategien an.

1. Nextcloud-Log gezielt durchsuchen

Das Nextcloud-Logfile (nextcloud.log) liegt meist im Datenverzeichnis. Mit grep lässt sich gezielt nach cURL-Fehlern filtern:

grep -i "cURL error 28" /var/www/nextcloud/data/nextcloud.log

Da Nextcloud-Logs im JSON-Format geschrieben werden, hilft das Tool jq für eine lesbare Darstellung:

tail -n 1000 /var/www/nextcloud/data/nextcloud.log | jq 'select(.message | contains("cURL error 28")) | {time: .time, message: .message}'

2. Systemd-Journal prüfen

Wird der Nextcloud-Cron über Systemd-Timers ausgeführt, gibt der Blick ins Journal Aufschluss über abgebrochene Durchläufe:

journalctl -u nextcloud-cron.service -e --no-pager

Ursachenforschung: Träge IPv6-Namensauflösung

In der Datei /etc/resolv.conf wird festgelegt, welche Nameserver das System nutzt. Bei lokalem Unbound-Einsatz sieht das typischerweise so aus:

nameserver ::1
nameserver 127.0.0.1

Der Resolver fragt standardmäßig zuerst den IPv6-Loopback (::1) ab. Über den Befehl time dig lässt sich die Antwortzeit des DNS-Servers messen:

# Abfrage über IPv6 (Loopback)
time dig @::1 rss.sueddeutsche.de

# Abfrage über IPv4 (Loopback)
time dig @127.0.0.1 rss.sueddeutsche.de

Das Symptom im Test

  • Die Abfrage über @127.0.0.1 liefert nach dem ersten Cachen Ergebnisse in 0 ms.
  • Die Abfrage über @::1 benötigt hingegen >1500 ms für eine einzige Domain.

Wenn Unbound bei externen Root- und Authoritative-Nameservern versucht, Feeds über IPv6 aufzulösen, die externe IPv6-Anbindung/MTU des Hosters jedoch hakelt oder blockiert ist, läuft die Abfrage in Timeouts. Da die News-App im Cronjob viele Feeds parallel oder sequentiell abruft, überschreiten die Summe der DNS-Abfragen das harte cURL-Limit von 3000 ms (3 Sekunden).

Die Lösung: IPv6-zu-IPv4-Strategie in Unbound

Die naheliegende Idee, IPv6 in Unbound komplett abzuschalten (do-ip6: no), hat einen Fallstrick: Sie deaktiviert auch den lokalen Listener auf ::1. Das führt beim Aufruf über IPv6 sofort zu einem connection refused.

Richtiger Ansatz: prefer-ip4: yes

Die saubere Strategie besteht darin, Unbound weiterhin auf IPv6 (::1) lauschen zu lassen, ihn aber anzuweisen, für die externe Rekursion im Internet bevorzugt IPv4 zu nutzen.

1. Unbound-Konfiguration anlegen

Man erstellt eine neue Konfigurationsdatei im Unbound-Drop-in-Verzeichnis:

nano /etc/unbound/unbound.conf.d/prefer-ipv4.conf

Füge folgenden Block ein:

Plaintext

server:
    prefer-ip4: yes

2. Konfiguration validieren und Unbound neustarten

Bash

unbound-checkconf
systemctl restart unbound

Ergebnis und Überprüfung

Um die Optimierung zu testen, wird der DNS-Cache geleert und eine frische Domain über den IPv6-Listener abgefragt:

# Unbound-Cache leeren
unbound-control flush_zone .

# Testabfrage durchführen
time dig @::1 www.tagesschau.de

Während die Abfrage vorher über 1,5 Sekunden dauerte oder fehlschlug, liegt die Antwortzeit für eine ungecachete, komplexe Rekursion nun konstant unter 500 ms. Folgeanfragen aus dem Cache antworten direkt in 0 ms.

Damit stehen cURL in Nextcloud beim nächsten Cronjob-Durchlauf alle Antworten sofort zur Verfügung, und die cURL error 28-Warnungen gehören der Vergangenheit an.