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.deodertagesschau.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.1liefert nach dem ersten Cachen Ergebnisse in 0 ms. - Die Abfrage über
@::1benö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.