Nextcloud: aus Alt mach Neu

Nextcloud: aus Alt mach Neu

Eine nette, kleine Aufgabe: Ziehe ein Nextcloud-System von einem Webserver auf einen anderen um. Klingt zu einfach - der Haken an der Geschichte war rasch gefunden: Nextcloud "alt" ist Version 24, aktuell ist die Version 29. Somit "alt" PHP 7.4, "neu" PHP 8.3. Auf dem alten System kann man nicht updaten, da das PHP zu alt und keine ausreichend neue Version vorhanden ist - auf dem neuen System kann man kein altes Nextcloud installieren, da das PHP dort zu neu und kein ausreichend altes PHP vorhanden ist. Dann halt ganz anders.

Achtung: ein sauberes Update von Nextcloud wird, gemäß Dokumentation, immer von einer auf die nächste Hauptversion gemacht. Also zuerst die aktuell laufende Version auf den letzten Patchstand gehoben, dann der Wechsel der Hauptversion. Also 24.x aktualisieren, dann der Wechsel auf 25. 25.x aktualisieren, dann der Wechsel auf 26. Und dies macht man so lange, bis man bei der aktuellsten Version angekommen ist.

Den Weg wollte ich allerdings nicht gehen - die Quelldistribution war mit RHEL 7 mindestens genauso alt wie Nextcloud 24, somit kam ein Update auf Ubuntu 24.04. Egal welche Distribution: die alte Umgebung hat ein altes PHP, die neue ein neues. Und irgendwie sind die nur bedingt kompatibel zueinander. Also hätte ich im ersten Schritt ein Ubuntu nehmen können, welches ebenfalls PHP 7.4 anbietet. Das grundlegend einrichten, Nextcloud 24 darauf migrieren. Solange Nextcloud Updates machen wie Nextcloud das zulässt. Sobald das Ende erreicht ist, kann man das Ubuntu auf das nächste Release heben. Mit dem nun aktuelleren PHP kann man Nextcloud weiter updaten. Bis auch hier nichts mehr geht, da das PHP zu alt ist. Also wieder Ubuntu auf die nächste Variante bringen und das Spiel nochmals von vorn.

Das wäre "sauber". Und wäre auch konsequenterweise richtig, wenn am Quellsystem regelmäßig Updates eingespielt worden wären. Dem war aber nicht so, ich bin derjenige der es korrigieren darf. Der obige Weg dauert mir zu lange, deswegen habe ich eine alternative Lösung gesucht.

Nextcloud ist eines der Systeme, welches nach einem Update erkennt, dass die Datenbank eine Aktualisierung braucht. Gegebenenfalls darf man via CLI und occ Befehl noch ein paar Indizies einfügen oder die ein oder andere Anpassung vornehmen. Das war es. Und an genau der Stelle setze ich an:

  • Ich installiere auf dem neuen Server ein aktuelles, leeres Nextcloud. Grundlegende Dinge richte ich bereits ein, allerdings nur das allernötigste. Die meisten Einstellungen werden durch die Übernahme der Daten aus dem Altsystem eh überschrieben. Du bist unsicher, was man bereits jetzt tun kann oder nicht? Dann warte bis zum Schluss.
  • Nun lösche ich die Datenbank und lege eine neue, aber leere Datenbank an.
  • Vom alten System kopiere ich die Datenbank auf den neuen Server.
  • Ebenso kopiere ich vom data Verzeichnis die Verzeichnisse der Benutzer. Achtung: Nicht alles, sondern wirklich nur dass, was ein Benutzer ist. Solche Dinge wie die Update-Daten sollte man wirklich überspringen.
  • Und nun beginnt die Magie: Es gibt Fälle, da ging der folgende Schritt per WebUI schief. Deswegen lieber die Kommandozeile verwenden. Sobald die Installation etwas größer wird, macht dies eh mehr Sinn. Also an die CLI gewechselt und occ upgrade aufgerufen. Nextcloud entdeckt, dass die Datenbankversion zu alt ist und beginnt deswegen mit den notwendigen Aktualisierungen.
  • Im nächsten Schritt meldete ich mich an der WebUI an. Ein grober Blick über die sichtbaren Daten sowie die Benutzer sollte jetzt bereits wieder erfolgreich sein.
  • Als Nächstes habe unter Administrationseinstellungen/Verwaltung/Übersicht die Sicherheits- und Einrichtungswarnungen angeschaut und entsprechend alles umgesetzt.
  • Hat das alte System Apps, die noch fehlen? Oder das neue, ein paar zu viel davon? Jetzt ist eine gute Gelegenheit.
  • Neue Systeme kennen neue Einstellungen. Mal alles auf Plausibilität prüfen - ob das so noch alles heute passt wie damals erdacht.
  • Testen, testen, testen …
  • Fertig

Das System läuft und ist zudem auf den aktuellsten Stand. Damit das so bleibt, kann man zum Beispiel folgenden Beitrag noch umsetzen: https://gehirn-mag.net/nextcloud-auto-update-via-cli/

Das Kopieren der Daten braucht halt die Zeit, die das Kopieren der Daten nun mal braucht. Allerdings habe ich mir die Update-Orgie erspart. Mal wieder die Welt eines Kunden gerettet, dieser ist glücklich. Mal schauen, welche Herausforderung mich als nächstes erwartet.

Nextcloud Auto-Update via cli

Nextcloud Auto-Update via cli

Ich habe einige Nextcloud Instanzen am laufen (https://nextcloud.com/). Und es erscheinen ebenso regelmäßig irgendwelche Updates. Das ist ja auch gut so weil zum einen Sicherheitslücken geschlossen werden, zum anderen zum Teils richtig nette Funktionen mit dazu kommen. Sobald in der Testumgebung alles geklappt hat und richtig läuft kommt die Fleißarbeit: Die ganzen Nextcloud Instanzen von Hand updaten. Hier hört der Spaß allerdings ganz schnell auf – bei mir zumindest. (mehr …)

Nextcloud Update Check

Nextcloud Update Check

Nextcloud zeigt einem in der Verwaltung an ob es Updates gibt. Nur mag ich hier nicht immer nachsehen müssen, zumal ich viele Nextcloud-Instanzen zu verwalten habe. Die Logik dahinter müsste man doch für einen Monitoring-Check verwenden können. Alternativen? Bisher habe ich keine gefunden deren Funktionsweise mich überzeugt oder der über einen längeren Zeitraum problemlos funktioniert hätte. Es muss also eine eigene Lösung her!

Prolog

Nextcloud auf verfügbare Updates prüfen

Ich würde jetzt einfach mal vermuten, dass jeder der diesen Artikel tatsächlich liest Nextcloud kennt. Oder zumindest ownCloud. Sicherheitshalber nochmal nachschauen? Bitte, das geht hier https://nextcloud.com/ bzw. hier https://owncloud.org/. Da ich selbst inzwischen nur noch wenig mit ownCloud zu tun habe und fast alle Installation mit Nextcloud betreibe beziehe ich mich in diesem Blogbeitrag ausschließlich auf Nextcloud.

Wie in einem anderen Blogbeitrag beschrieben mag ich keine Mails welche mich auf verfügbare Updates hinweisen (Statusmails? Nein Danke!). Das wären schlichtweg zu viele Systeme die sich da innerhalb kürzester Zeit melden würden. Ebenso, auch wenn das für eine Plattform reichen täte, bin ich kein Fan davon in Nextcloud nachzusehen. Wenn es für die erste installierte Plattform Updates gibt, dann auch für alle anderen. Unterm Strich viel zu mühsam. Zumal wir auch Kunden haben die Ihre Cloud-Installation selbst betreuen. Hier könnte der Check als Hinweis für den Kunden dienen. Oder für mich als Serverbetreiber Grund genug sein mal wieder den Telefonhörer in die Hand zu nehmen und den Kunden gefühlvoll mit dem notwendigen Nachdruck davon zu überzeugen doch bitte Updates zu installieren. Sicherheit und so. Klappt richtig gut 😉

status.php Ausgabe von Nextcloud.

Bleibt die Frage wie prüfen. Ein paar Checks habe ich gefunden welche die lokale Version ermitteln in dem Sie die version.php-Datei im Dateisystem direkt auslesen oder einfach https://<deine.nextcloud>/status.php aufrufen. In diesem JSON-String findet sich die Versionsnummer. Eine aufbereitete Fassung der JSON-Daten siehst Du links im Screenshot. So oder so, der Teil mit der lokalen Versionsnummer ist leicht. Bleibt noch die Frage wie man heraus findet ob es überhaupt Updates gibt. Hierfür habe ich einige verschiedene Ansätze gefunden:

  1. 1Einer zum Beispiel war die Releases auf dem Nextcloud-Server auszuwerten https://download.nextcloud.com/server/releases/. Klar, das mag funktionieren. Aber richtig warm werde ich mit dieser Lösung nicht. Also weiter suchen.
  2. 2Sehr interessant fand ich die Variante wie unter https://github.com/janvonde/check_nextcloud beschrieben. Hierfür wird der Nextcloud Security Scan verwendet: https://scan.nextcloud.com/. Neben der Update-Prüfung erhält man hier gleich noch ein Sicherheitsrating oben drauf mit dazu. Super Grundgedanke. Jetzt das aber dabei, dass sich wie folgt auf der zugehörigen GitHub Seite liest: "Please don't run this check too often. There is an API limit at the scan.nextcloud.com server at the /api/queue endpoint with arround 250 POST requests a day. I personally run it every 24h". Eine Update-Prüfung einmal am Tag reicht mir absolut aus, jedoch habe ich wohl zu viele verschiedene Instanzen hier am laufen - die Meldung welche auf die Limitüberschreitung hinwies hat nur wenige Tage auf sich warten lassen. Das ist schade. Weil vom Ansatz her war der Check richtig super.
  3. 3Also musste eine andere Lösung her. Nextcloud selbst weiß doch auch ob es gerade ein Update gibt. Also habe ich mich hier auf die Suche begeben. Unter updater/index.php bin ich fündig geworden.
private function getUpdateServerResponse() {
        $this->silentLog('[info] getUpdateServerResponse()');

        $updaterServer = $this->getConfigOption('updater.server.url');
        if($updaterServer === null) {
                // FIXME: used deployed URL
                $updaterServer = 'https://updates.nextcloud.org/updater_server/';
        }
        $this->silentLog('[info] updaterServer: ' . $updaterServer);

        $releaseChannel = $this->getCurrentReleaseChannel();
        $this->silentLog('[info] releaseChannel: ' . $releaseChannel);
        $this->silentLog('[info] internal version: ' . $this->getConfigOption('version'));

        $updateURL = $updaterServer . '?version='. str_replace('.', 'x', $this->getConfigOption('version')) .'xxx'.$releaseChannel.'xx'.urlencode($this->buildTime).'x'.PHP_MAJOR_VERSION.'x'.PHP_MINOR_VERSION.'x'.PHP_RELEASE_VERSION;
        $this->silentLog('[info] updateURL: ' . $updateURL);

        // Download update response
        $curl = curl_init();
        curl_setopt_array($curl, [
                CURLOPT_RETURNTRANSFER => 1,
                CURLOPT_URL => $updateURL,
                CURLOPT_USERAGENT => 'Nextcloud Updater',
        ]);

 

In Zeile 7 ist der Update-Server angegeben und in Zeile 15 findet sich der Aufbau der URL. Einige dieser Bestandteile finden sich in der bereits angesprochenen version.php, der Rest sind Versionsnummern der lokal verwendeten PHP-Installation. Dies wird mit reichlich "x" getrennt zu einer langen URL zusammen gesetzt welche z.B. so aussieht:

https://updates.nextcloud.org/updater_server/?version=14x0x4x2xxxstablexx2018-11-22T13%3A16%3A37%2B00%3A00+d25e8a774a30f78017acdc366a79460cebbb552fx7x2x10

Diese Adresse geöffnet ergibt folgende Antwort:

<?xml version="1.0" encoding="UTF-8"?>
<nextcloud>
 <version>15.0.0.10</version>
 <versionstring>Nextcloud 15.0.0</versionstring>
 <url>https://download.nextcloud.com/server/releases/nextcloud-15.0.0.zip</url>
 <web>https://docs.nextcloud.com/server/15/admin_manual/maintenance/upgrade.html</web>
 <changes>https://updates.nextcloud.com/changelog_server/?version=15.0.0</changes>
 <autoupdater>1</autoupdater>
 <eol>0</eol>
 <signature>c4llfwhYTKaEiTWVivJ1NgTIS5q2mxJVJkyew0nd/setTzpXt2H9zXKGQLmjUcy7
fSeW5+wkUfGD2J3XrcLKifGZMjxrhtAW97L1g/o8gp84ZO1WbrOKfneTLDXWkmwg
nztf/5z0F0nppOyUX6HR84UhwDbhET7U8JV/1Ik7OO6D361U4sxELUhvg6GyQbdS
oJ/t4MvMe1Fs+F5Q7dZzczivxu5oB0n2cVu9WMh8VnV6MiYcKV4/w7poibHMO16k
4IHl6E2hTF3un0obMKy7SRY4xXJ0Ohmj5Ne/8iDRjM7oop5Tzpnf1nPLEJJOZPSN
fq4UospVzAmRe4UGPTUiqQ==</signature>
</nextcloud>

 

In diesem Beispiel ist die Version 15.0.0.10 als aktuellere Version zur angefragten 14.0.4.2 verfügbar. Falls keine xml-Datei ausgeliefert wird ist die Nextcloud Installation auf aktuellem Stand.

Das war es mit dem Verfahren zur Prüfung ob es Updates gibt. Bleibt noch die Umsetzung über. Obwohl dies sehr einfach in PHP selbst zu realisieren wäre ist bei mir die Wahl auf Python3 gefallen. Ich wollte schon längst mal wieder was in Python machen um meine angestaubten Python-Kenntnisse aufzufrischen und vor allem zu vertiefen. Also wurde die Sprache der Wahl die aktuelle Version von Python3. Die versions.php ist eine relativ einfach PHP-Datei welche sich gut auslesen lassen sollte. Fehlen noch die benötigten PHP-Versionsnummern. Ein an dieser Stelle gern genommener Trick ist in der vermeintlichen anderen Sprache die benötigten Daten in ein Array zu packen und dieses per JSON auszugeben. Die so umgewandelten Daten lassen sich dann super weiterverarbeiten:

ncVersion = json.loads(subprocess.check_output([
    args.php, '-r',
    'include \'' + args.file + '\';' + '''
    $g = array();
    foreach($GLOBALS as $key => $val) {
      if(preg_match('/^OC_/', $key)) {
        $g[$key] = $val;
      }
    }
    echo json_encode(
      array(
        'pv'   => PHP_VERSION,
        'pmav' => PHP_MAJOR_VERSION,
        'pmiv' => PHP_MINOR_VERSION,
        'prv'  => PHP_RELEASE_VERSION,
        'g'    => $g
      )
    );
    '''
]))

 

Noch ein kleiner Tipp für alle die PHP an der Stelle nicht so gut kennen: Man könnte einfach das Array $GLOBALS ausgeben, da wären alle Werte drin. Nur gibt es in $GLOABLS eine Referenz auf sich selbst da ja auch $GLOBALS eine globale Variable ist. Und an genau der Stelle steigt json_encode() aus da diese Funktion mit Referenzen nicht umgehen kann. In der versions.php fangen aber alle interessanten Variablen mit "OC_" an und lassen sich somit super filtern ;-).

Den kompletten Check, eine Makro gestützte Beispiel-Konfig für Icinga2 sowie eine kurze Anleitung findet Ihr in meinem GitLab-Account: https://gitlab.com/Gehirn-Mag.net/icinga-and-nagios-plugins/. Bis jetzt liegt da nur der Nextcloud-Update-Check drin, weitere werden aber folgen.

Und so sieht das dann im icingaweb2 aus:

check_nextcloud.py Ausgabe in icingaweb2

Was jetzt noch fehlt ist die Prüfung der Addons auf Aktualität. Auch hierfür sollte sich der passende Anfragestring irgendwo im Quellcode von Nextcloud finden lassen. Mir reicht jedoch vorerst die Prüfung von Nextcloud selbst. Ich bin also vorerst zufrieden. Wer weiß, ggf. reiche ich in ein paar Wochen die Erweiterung für die Addons nach.

Viel Spaß beim benutzen. Feedback und Anregungen gerne via Mail oder hier in den Kommentaren hinterlassen.

Achtung:

Nachtrag

An dieser Stelle sind alle Dinge gesammelt die sich seit der Erstellung des Checks und des obigen Beitrages geändert haben. Sollte es zu viel werden wird dieser Beitrag als veraltet markiert und ein neuer verfasst. Bis dahin gilt diese Übersicht.

Geänderter Update Channel

Es ist möglich den Update Channel in Nextcloud zu ändern. Diese Einstellung findet sich jedoch nicht in der versions.php sondern in der config/config.php. Sollte dort der Channel definiert sein wird dieser verwendet, ansonsten der aus der versions.php. Das hat jedoch zur Folge, dass via -c jetzt noch zusätzlich die config.php mit angegeben werden muss.

Anmerkung zur Icinga Config: Die config.php darf vermutlich vom Benutzer welcher Icinga ausführt nicht gelesen werden. Deswegen ist im CheckCommand ein Aufruf von sudo mit enthalten.

Python vor 3.6

Bei Python Versionen bis 3.5.x erscheint die Fehlermeldung "CRITICAL Cannot parse file /var/www/nextcloud/version.php". Ab Version 3.6 ist dieses Problem behoben.

Falls kein Update auf Pyhton 3.6.x möglich ist kann der Check wie folgt angepasst werden:

// Die import Liste um chardet erweitern - muss ggf. vorher noch installiert werden
import chardet

// Den ersten try: Block wie folgt bearbeiten
try:
    jsonResponse = subprocess.check_output([
        args.php, '-r',
        'include \'' + args.file + '\';include \'' + args.config + '\';' + '''
        $g = array();
        foreach($GLOBALS as $key => $val) {
          if(preg_match('/^(OC_|CONFIG$)/', $key)) {
            $g[$key] = $val;
          }
        }
        echo json_encode(
          array(
            'pv'   => PHP_VERSION,
            'pmav' => PHP_MAJOR_VERSION,
            'pmiv' => PHP_MINOR_VERSION,
            'prv'  => PHP_RELEASE_VERSION,
            'g'    => $g
          )
        );
        '''
    ])
    print(jsonResponse)
    ncVersion = json.loads(jsonResponse.decode(chardet.detect(jsonResponse)['encoding']))