calcardbackup: Kalender- und Adressbuchbackup von ownCloud / Nextcloud

UPDATE 17.01.2020
Wegen der Übernahme von GitHub durch Microsoft ist das Repository von calcardbackup umgezogen zu:
https://codeberg.org/BernieO/calcardbackup
Nur dort ist auch die erste stabile Version 1.0 des Skripts zu finden.
Die Links und Installationsanweisungen im folgenden Text wurden entsprechend angepasst.

BEGINN UPDATE 11.11.2018
Da das Skript calcardbackup im Laufe der Zeit stetig weiterentwickelt wurde, ist dieser Artikel mittlerweile etwas in die Tage gekommen (veraltet!). Die wichtigsten Neuerungen sind:

  • einige Abhängigkeiten sind weggefallen (grep, sed und curl)
  • PostgreSQL wird unterstützt
  • das Backup-Dateien wird durch direktes Auslesen aus der Datenbank zusammengestellt
  • die Angabe von Nutzernamen und Klartextpasswörtern entfällt
  • Links zu abonnierten Kalendern werden ebenfalls gesichert
  • die Umgebungsvariablen OWNCLOUD_CONFIG_DIR, NEXTCLOUD_CONFIG_DIR werden unterstützt
  • nextcloud-snap wird unterstützt
  • viele kleinere Bugfixes, Optimierungen und Sicherheitsverbesserungen

Boris ist mir zuvorgekommen und hat wegen einer wichtigen Neuerung in Version 0.8.0 schon einen aktuelleren Beitrag verfasst.
Außerdem plane ich, das englische README.md des Repositories auf deutsch zu übersetzen. Ich werde dann an dieser Selle darauf verweisen, wenn ich damit fertig bin.
Das deutsche README ist fertig (20.11.2018): README_GER.md
ENDE UPDATE 11.11.2018

Wer einen eigenen caldav- und carddav-Server betreibt, um Kalender und Adressbücher über verschiedene Geräte hinweg synchron zu halten, sollte sich auch selbst um Sicherungen kümmern. Bei ownCloud / Nextcloud kann man aus dem Webfrontend Adressbücher und Kalender einzeln als .vcf- bzw. .ics-Datei exportieren. Das ist superpraktisch, denn man kann mithilfe solcher Dateien verlorene Adressbücher und Kalender sehr einfach wiederherstellen. Aber eigentlich ist der Export auch ziemlich umständlich – vor allem wenn man mehrere Kalender pflegt und ein Backup relativ regelmäßig herstellen möchte. Das wollte ich für mich unbedingt automatisieren!

Zunächst habe ich ein Bash-Skript geschrieben, das genau auf meinen Anwendungsfall zurecht geschnitten war. Im Lauf der Zeit wurde das Skript erweitert und verbessert, da neue Kalender angelegt wurden und auch zwei Freunde Bedarf für eine Backup von ownCloud-Kalendern und -Adressbüchern hatten.

Da die Anforderungen verschieden waren (z.B. ältere ownCloud-Version und aktuellere Nextcloud-Version) wurde das Skript immer umfangreicher. So kommt es mittlerweile mit ownCloud / Nextcloud ab Version 5.0, MySQL/MariaDB und SQLite3 zurecht. Ich habe Wert auf gute Rückmeldungen im Fehlerfall gelegt. Über verschiedene Optionen kann das Verhalten des Skripts angepasst werden.
Das Script könnte auch für andere ownCloud / Nextcloud Nutzer interessant sein, daher habe ich es auf GitHub Codeberg.org veröffentlicht: https://codeberg.org/BernieO/calcardbackup

Das Bash-Skript benötigt neben einer funktionierenden ownCloud / Nextcloud Installation nur die Pakete grep, sed und curl sowie das der Installation entsprechende Datenbankpaket (mysql-server / mariadb-server oder sqlite3). Alle diese Pakete müssten auf Systemen vorhanden sein auf denen ownCloud oder Nextcloud läuft. Getestet wurde das Skript unter Debian 7 (Wheezy), Debian 8 (Jessie) und Debian 9 (Stretch). Daher sind auch die Rückmeldungen des Skripts auf Debian zurechtgeschnitten. Nichtsdestotrotz dürfte das Skript auch unter anderen Distributionen funktionieren.

Was genau macht das Skript?

Das Skript liest Version, URL, Datenbanktyp und Datenbankzugangsdaten aus der Konfigurationsdatei config.php von ownCloud / Nextcloud aus. Danach werden aus der Datenbank alle Kalendernamen mit zugehörigen Benutzernamen eingelesen. Diejenigen Kalender, die Benutzern in der users.txt zugeordnet werden können, werden dann mit curl von ownCloud / Nextcloud exportiert und lokal gespeichert. Mit den Adressbüchern wird genauso verfahren. Anschließend werden die heruntergeladenen Dateien komprimiert. Das war auch schon alles. Zu keinem Zeitpunkt verlassen irgendwelche Daten das System.

Update-1 20.09.2018:
Mit Version 0.7.0 ist es über die option -f/--fetch-from-database möglich das Backup von Kalendern und Adressbüchern direkt von der Datenbank erstellen zu lassen. Das bringt die folgenden Vorteile mit sich:

  • die Datei users.txt mit Nutzernamen dazugehörigen Passwörtern wird nicht mehr benötigt: findet das Skript die Datei users.txt nicht, dann werden alle Kalender und Adressbücher aller Nutzer gesichert. Möchte man nur von einigen Nutzern die Kalender/Adressbücher sichern, kann man weiterhin die Datei users.txt benutzen – das Angeben von Passwörtern in dieser Datei ist aber nicht mehr nötig.
  • das Backup von Adressbüchern geht viel schneller und resourcenschonender vonstatten.

Wegen dieser Vorteile empfehle ich, das Skript immer mit dieser neuen Option zu benutzen. Sie wird mit Version 0.8.0 zur Voreinstellung werden.
Ende Update-1 20.09.2018

Installation

In ein Verzeichnis wechseln, in dem das Script gespeichert werden soll, und das Repository von Codeberg.org klonen und in das geklonte Verzeichnis wechseln (unbedingt außerhalb des Webserver-Verzeichnisses!):

cd /usr/local/bin
git clone https://codeberg.org/BernieO/calcardbackup.git
cd calcardbackup

Den ganzen Ordner dem Webserver-User (hier www-data) zu eigen machen:

chown -R www-data:www-data .

Dann kann auch schon das Script mit (zwingend als erstem Argument!) Pfadangabe zu ownCloud / Nextcloud (im Beispiel hier /usr/share/nginx/nextcloud und der Option -f gestartet werden. Da das Skript Zugriff auf den Ordner des Webservers braucht, wird es hier als User www-data gestartet. Falls noch etwas nachinstalliert werden muss, oder eine Konfigurationseinstellung fehlt, wird das in der Ausgabe des Scripts ersichtlich sein (z.B.: wenn das Zertifikat des Webserver selbst signiert wurde, muss dem Befehl am Ende vermutlich noch ein -s angehängt werden):

sudo -u www-data ./calcardbackup /usr/share/nginx/nextcloud -f

Nach erfolgreichem Durchlauf des Scripts findet sich das Backup im Ordner backups/. Backups mit der Endung tar.gz lassen sich mit folgendem Befehl entpacken:

cd /usr/local/bin/calcardbackup/backups/
tar -xzf calcardbackup-2017-03-23.tar.gz
ls -l calcardbackup-2017-03-23

Eine regelmäßige Ausführung kann man per cronjob veranlassen, indem man folgende Zeile in die Datei /etc/crontab einfügt (so wird täglich um 22:00 Uhr ein Backup angefertigt):

00 22   * * * www-data  /usr/local/bin/calcardbackup/calcardbackup -f

Das Verhalten des Skripts kann durch verschiedene Optionen beeinflusst werden. Details finden sich in der Datei README.md

Über die Option -i/--include-shares:
Die Passwörter aller Nutzer in einer Textdatei zu speichern ist nicht optimal. Daher wurde in Version 0.2.0 die Option -i/--include-shares eingeführt, um auch geteilte Kalender/Adressbücher zu sichern. Wenn man einen neuen Nutzer anlegt, mit dem alle zu sichernden Kalender/Adressbücher geteilt werden, muss man nur das Passwort dieses einen Nutzers in der Datei users.txt angeben. Falls die Datei mit dem Passwort in falsche Hände gerät, so ist nur dieses eine Nutzerkonto kompromittiert. Wenn es nur zu diesem Zweck angelegt wurde, kann es leicht gelöscht und von einem anderen nur für diesen Zweck neu angelegten Nutzerkonto ersetzt werden.
Einen Nachteil hat diese Vorgehensweise allerdings: von Nutzern neu hinzugefügte Kalender/Adressbücher werden nicht automatisch in das Backup mit aufgenommen, sondern erst, wenn sie mit dem Backup-Nutzer geteilt wurden.

Update-2 20.09.2018:
Durch die neue Option -f/--fetch-from-database ist die Datei users.txt und die Angabe von Passwörtern in dieser Datei obsolet.
Damit ist auch der Hauptzweck der Option -i/--include-shares hinfällig: durch Wegfall der Datei mit Nutzernamen und Kennwörtern, können auch keine Kennwörter mehr in falsche Hände geraten 🙂
Ende Update-2 20.09.2018:

Wenn jemand etwas mit dem Script anfangen kann, würde ich mich über Kommentare sehr freuen. Falls Fehler gefunden werden, versuche ich diese zu korrigieren.

Changelog:
25.04.2017: Text an aktuelle Version des Skripts angepasst (Verweis auf Optionen)
29.07.2017: Abschnitt über -i/--include-shares hinzugefügt
20.09.2018: diverse Updates wegen neuer Option -f/--fetch-from-database. Installation und Kommandos entsprechend angepasst.
11.11.2018: Bemerkung über neue Funktionen im Header hinzugefügt
20.11.2018: Hinweis auf deutsche Version von README.md
17.01.2020: Text angepasst wegen Umzug des Repositories zu https://codeberg.org/BernieO/calcardbackup

19 Kommentare on "calcardbackup: Kalender- und Adressbuchbackup von ownCloud / Nextcloud"


  1. hallo bob –

    wirklich tolles und brauchbares script! ich habe nextcloud 14 auf einem reseller am laufen, hab nur limitierten shell zugang. konnte aber alles aus git laden, direkt in den ordner cgi-bin. hab die conf datei sowohl mit datenbank abfrage und php abfrage ausprobiert – beides mal folgender output:

    /cgi-bin/calcardbackup> ./calcardbackup
    
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    +
    + Fri Oct 12 10:00:21 UTC 2018 —> START calcardbackup ver. 0.7.2 (19.09.2018), AGPL-3.0
    + Checking dependencies and preparing…
    + Using configuration file /cgi-bin/calcardbackup/calcardbackup.conf, ignoring all other command line options.
    + Using URL https://www.xy.z
    + Nextcloud 14.0.1 detected.
    + Database of chosen Nextcloud installation is MySQL/MariaDB.
    + Looking for calendars in your Nextcloud:
    Could not open required defaults file: /dev/fd/63
    Fatal error in defaults handling. Program aborted

    ich hab nur eine user (keinen extra web-user), und kann das script auch nicht mit sudo laufen lassen…
    gibt es hier eine lösung?

    danke schon mal im voraus, benjamin

    Antworten

    1. Hallo Benjamin,

      wir standen vor einiger Zeit schon per E-Mail in Kontakt wegen deines Kommentars. Nun kommt noch spät eine Antwort hier im Blog. Denn mit Version 2.0 kommt calcardbackup mit einem kleinen PHP-Skript mithilfe dessen calcardbackup möglicherweise auf Hosting Umgebungen ohne shell-Zugang ausgeführt werden kann. Details finden sich im README des Repo auf codeberg – daher spare ich mir hier weitere Erklärungen.

      Vielleicht hilft dir das ja weiter – vielleicht hast du aber auch schon eine andere Lösung gefunden.

      Viele Grüße
      Bernhard.

      Antworten

  2. Hi Bob,

    ich hab mal wieder ein kleines Problemchen mit deinem wunderbaren script.
    Bei mir mag das script die Datenbankabfrage nicht.

    Ich bin auf pgsql Datenbank geswitcht.
    Nun hakt das script an folgender Stelle:

    ############################################################
    [query_database() { # gets details of calendars/addressbooks from database # see next lines for description of arguments  and 
    table=““ # ${table_calendars} or ${table_addressbooks} item=““ # „calendar“ or „addressbook“, just a verbal description, needed for output messages _output echo „+ Looking for ${item}s in your ${productname}:“ # change of directory needed for SQLite3, because ${datadirectory} could contain spaces and # sqlite3 would then need „${dboptions}“ to avoid bashs word splitting, but mysql needs ${dboptions} word-splitted: [[ „${dbtype}“ == „sqlite3“ ]] && cd „${datadirectory}“ # check if table exists: [[ „${dbtype}“ == „mysql“ && „${snap}“ == „no“ ]] && check_table=“$(mysql —defaults-extra-file=<(printf „[client]\nuser = %s\npassword = \“%s\“\nhost = %s\n%s“ „${dbuser}“ „${dbpassword}“ „${dbhost}“ „${dbprotocol}“) „${dbname}“ -e „show tables like ‚${table}‘“)“ [[ „${dbtype}“ == „mysql“ && „${snap}“ == „yes“ ]] && check_table=“$(nextcloud.mysql-client —defaults-extra-file=<(printf „[client]\nuser = %s\npassword = \“%s\“\nhost = %s\n%s“ „${dbuser}“ „${dbpassword}“ „${dbhost}“ „${dbprotocol}“) „${dbname}“ -e „show tables like ‚${table}‘“)“ [[ „${dbtype}“ == „sqlite3“ ]] && check_table=“$(sqlite3 owncloud.db „SELECT name FROM sqlite_master WHERE type=‚table‘ AND name=‘${table}‘“)“
    
    #—————— Bis hierhier funnktioniert noch alles ———————-#
    [[ „${dbtype}“ == „pgsql“ ]] && check_table=“$(PGPASSWORD=“${dbpassword}“ psql „${dbhost}“ „${dbprotocol}“ -U „${dbuser}“ -d „${dbname}“ -qtc „SELECT * FROM ${table}“ 2>/dev/null)“
    
    #—————— Nach der Anweisung nicht mehr ———————-#
    if [[ „${check_table:-}“ == “” ]]; then _output echo „+ Tabelle existiert“]
    
    ############################################################

    Der Output des scipts sieht wie folgt aus.

    ….cloud/calcardbackup-master $ sudo -u www-data ./calcardbackup -c calcardbackup.conf
    
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    +
    + Mo 17. Sep 19:22:32 CEST 2018 —> START calcardbackup ver. 0.7.1 (13.09.2018), AGPL-3.0
    + Checking dependencies and preparing…
    + Using configuration file /home/pi/Nextcloud/calcardbackup-master/calcardbackup.conf, ignoring all other command line options.
    + Using URL „mein URL“
    + Nextcloud 13.0.4 detected.
    + Database of chosen Nextcloud installation is PostgreSQL.
    + Looking for calendars in your Nextcloud:
    
    ]

    Hast du hier einen Idee was das Problem sein könnte?

    Vielen Dank im voraus.
    Gruß Steffen

    Antworten

    1. Durch einen kurzen Mailwechsel hat sich herausgestellt, dass der Fehler an einem Tippfehler im Datenbankpasswort lag.
      Dass keine aussagekräftige Fehlermeldung ausgegeben wurde, ist in Version 0.7.2 vom 19.09.2018 behoben.

      Antworten

  3. Hallo Bob,

    vielen Dank für dieses tolle Script!

    Es läuft super, wenn ich die Username:Passwort – Kombination, für alle User in der user.txt verwende. Ich möchte aber gerne die „-i“ Variante nutzen und bekomme dann folgenden Fehler:

    su -c „/usr/local/bin/calcardbackup/calcardbackup ‚/var/www/html‘ -f -i“ www-data -s /bin/bash
    
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    +
    + Wed Aug 15 09:34:49 UTC 2018 —> START calcardbackup ver. 0.6.0 (08.08.2018), AGPL-3.0
    + Checking dependencies and preparing…
    + Using URL https://nc.XXXX.de
    + Nextcloud 13.0.4 detected.
    + Database of chosen Nextcloud installation is MySQL/MariaDB.
    + Looking for calendars in your Nextcloud:
    + Saving calendar Dasi-Personal.ics……success!
    + Saving calendar Dasi-Personal_shared_by_test.ics……success!
    + Looking for addressbooks in your Nextcloud:
    /usr/local/bin/calcardbackup/calcardbackup: line 731: temp_principal: unbound variable

    Was mache ich falsch?

    MfG.
    Heiner

    Antworten

    1. Hallo Heiner,
      du hast gar nichts falsch gemacht, sondern ich: das Skript meckert wegen einer nicht deklarierten Variable, weil es versucht, geteilte Adressbücher zu sichern. Bei deiner Installation sind aber keine geteilten Adressbücher der angegebenen Nutzer vorhanden.
      Ich habe den Fehler gerade mit Version 0.6.1 behoben.
      Danke für den Hinweis!

      Antworten

  4. Hi, i’ve a question, the calendars data is only stored in the DB? or some data is stored in de file system? Thanks!

    Antworten

  5. Hi Bob,

    echt cooles Tool von Dir. Danke schonmal
    Habe da nur eine kleine Frage zu dem Parameter --include-shares.

    Sollen damit Kalender von andere USERN gesichert werden, die diesen mit mir geteilt haben oder die Kalender von mir, den ich mit anderen geteilt habe.

    Ich habe den Kalender von meiner Freundin an mich geteilt. Dieser wird aber nicht mitgesichert. In meiner CONFIG habe ich den Parameter wie folgt gesetzt.

    < include_shares=„yes“ >

    Und mein Abruf sieht wie folgt aus:

    < sudo -u www-data ./calcardbackup -i -c calcardbackup.conf >
    Antworten

    1. Mit der Option -i|--include-shares werden Kalender von Benutzern gesichert, die diese mit einem User geteilt haben, der in der users.txt eingetragen ist. Bei deinem Aufruf des Skriptes kannst du das -i weglassen: wenn man eine Konfigurationsdatei (über die Option -c) benutzt, werden auf der Kommandozeile übergebene Optionen von den in der Konfigurationsdatei angegebenen Werten überschrieben.

      Nach etwas Mailwechsel mit mir hat Steffen herausgefunden, dass an Gruppen geteilte Kalender/Adressbücher von calcardbackup nicht berücksichtigt werden, obwohl mit der --include-shares-Option aufgerufen.
      Dies ist ein Fehler von calcardbackup, der in der nächsten Version des Skripts (v0.2.2) behoben sein wird.

      Antworten

  6. Hallo Bernhard,
    wieder mal ein Problem: Bin von NC10 und Raspbian umgestiegen auf NC12 und Archlinux (auf Raspi3).
    Kriege jetzt beim Backup folgenden Fehler:

    ERROR 2005 (HY000): Unknown MySQL server host ‚localhost:3306‘ (-2)

    Ich muß dazu sagen, daß ich in der my.cnf networking abgeschaltet habe, lt. Doku soll aber localhost weiter nutzbar sein.
    Habe mich jetzt mal versuchsweise ‚zu Fuß‘ eingeloggt und was lustiges gefunden:
    # mysql —host=localhost -u root -p – geht normal weiter, d.h. regulär eingeloggt.
    Mache ich aber:
    # mysql —host=localhost:3306 -u root -p – kommt – na rate mal –

    ERROR 2005 (HY000): Unknown MySQL server host ‚localhost:3306‘ (-2)

    Als Port ist bei mir 3306 eingestellt! Der Server ist 10.1.25-MariaDB.
    …grmpf….

    Meine manpage hat einen extra switch für den Port:

    -P, —port=# Port number to use for connection or 0 for default to, in order of preference, my.cnf, $MYSQL_TCP_PORT, /etc/services, built-in default (3306).

    Ich hoffe, Dir fällt dazu was ein…

    Schöne Grüße, Wolfgang

    Antworten

    1. Hallo Wolfgang,
      danke für den Hinweis. In Version 0.2.1 habe ich diesen Fehler behoben – calcardbackup beachtet nun auch in der config.php angegebene Portnummer/Socket für die Verbindung zu MySQL/MariaDB.
      Viele Grüße,
      Bernhard

      Antworten

  7. Hallo,
    erstmal tolle Sache so ein script zur Sicherung.
    Hab ich schon lange danach gesucht.

    Aber leider bekomme ich beim sichern meine Contacts immer folgenden Fehler calcardbackup:

    ERROR —
    — ERROR: the saved file is not a valid addressbook-file. Something went wrong.
    — My guess: either wrong configured URL to Nextcloud or a wrong combination of username/password in users.txt.
    — You may want to check the saved file for any hints what went wrong: /home/odroid/calcardbackup/backups/calcardbackup-2017-05-18/Fahrstunden-Contacts.vcf-ERROR.txt
    — calcardbackup: Exiting.

    in der Error Datei steht nichts und ich hab in diesem Benutzer eigentlich auch keine Kontakte.
    Danke und viele Grüße
    Andy

    Antworten

    1. Hallo Andy,
      das Problem war, dass curl >= 7.42.0 leere Dateien erzeugt, wenn es ein leeres Adressbuch empfängt. Ältere Versionen von curl erzeugen in dem Fall keine leere Datei.
      Ich habe das Skript korrigiert (v0.1.2) und kompatibel für neuere Versionen von curl gemacht.
      Danke für dein Feedback und viele Grüße,
      Bernhard

      Antworten

  8. Hallo Bernhard,
    habe gerade Dein Script ausprobiert, weil ich hier mit NC-10 auf nem Raspi rumprobiere und ich solche Sicherungen für ziemlich wichtig halte.

    Das Script zickt aber an einer Stelle, wo ich nicht so recht eingreifen möchte:

    root@raspberrypi:/usr/local/bin/calcardbackup# sudo -u www-data ./calcardbackup
    
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    +
    + Mit Mai 10 12:06:26 CEST 2017 —> START calcardbackup
    + Checking dependencies and preparing…
    + Using configuration file /usr/local/bin/calcardbackup/calcardbackup.conf, ignoring all other command line options.
    —
    — WARNING: Configured Nextcloud-URL differs from ‚overwrite.cli.url‘ in config.php
    — http://192.168.210.12/NC10/ ==> given with option -a/—address or found in config file.
    — http://localhost/ ==> detected in /var/www/NC10/config/config.php
    — Using the latter one!
    —
    + Using URL http://localhost
    — calcardbackup: ERROR —
    — ERROR: No Own-/Nextcloud Installation found at http://localhost !
    — calcardbackup: Exiting.

    Der Nextcloud-Installer hat in der php.ini diesen localhost-Eintrag gemacht, und damit läuft auch bisher alles.
    Wenn ich in der config was anderes angebe, solle er doch dann das nehmen – oder?

    Schöne Grüße Wolfgang

    Antworten

    1. Hallo Wolfgang,
      stimmt. Es wäre besser, wenn das Skript in so einem Fall nicht abbricht, sondern die gegebene URL nimmt und nur einen Hinweis ausgibt, dass die beiden URLs nicht übereinstimmen (was auf eine Fehlkonfiguration hindeuten könnte).
      Ich habe das Skript entsprechend geändert (v0.1.1). Jetzt dürfte es nicht mehr abbrechen – zumindest nicht an dieser Stelle 😉
      Danke für dein Feedback und viele Grüße,
      Bernhard

      Antworten

  9. Hi, ich würde den Cron-Eintrag in die Crontab des Users www-data vornehmen:

    crontab -u www-data -e

    editiert automatisch die richtige Crontab.

    Antworten

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.