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 Nextcloud / ownCloud 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 Nextcloud-Kalendern und -Adressbüchern hatten.
Da die Anforderungen verschieden waren (z.B. ältere ownCloud-Version und aktuellere Nextcloud-Version) wurde das Skript immer umfangreicher. Inzwischen funktioniert das Skript mit Installationen von Nextcloud / ownCloud >= 5.0 mit MySQL/MariaDB, PostgreSQL oder SQLite3. Ich habe Wert auf gute Rückmeldungen im Fehlerfall gelegt. Es stehen verschiedene Optionen zur Verfügung, um das Verhalten des Skripts zu beeinflussen.
Das Skript könnte auch für andere ownCloud / Nextcloud Nutzer interessant sein, daher hatte ich es auf GitHub veröffentlicht. Nach der Übernahme GitHubs durch Microsoft erfolgte 2020 ein Umzug des Repositories zu Codeberg – seitdem ist nur dort die aktuelle Version zu finden:
https://codeberg.org/BernieO/calcardbackup
Das Bash-Skript benötigt neben einer Nextcloud / ownCloud Installation nur das Clientprogramm der zugehörigen Datenbank (mysql / mariadb, psql oder sqlite3). Das dürfte sowieso auf Systemen vorhanden sein auf denen Nextcloud oder ownCloud läuft. Entwickelt wird das Skript unter Debian. Die Rückmeldungen des Skripts sind daher auf Debian zurechtgeschnitten. Erfolgreich getestet wurde das Skript aber auch mit Ubuntu, FreeBSD, SunOS und Darwin.
Was genau macht das Skript?
Das Skript liest Versionsnummer, Datenbanktyp und Datenbankzugangsdaten aus der Konfigurationsdatei config.php von Nextcloud / ownCloud aus. Danach werden in der Datenbank vorhandene Kalender und Adressbücher aller Benutzer exportiert und in einer komprimierten Datei lokal gespeichert. Das war auch schon alles. Zu keinem Zeitpunkt verlassen irgendwelche Daten das System.
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 das Skript mit Pfadangabe zu Nextcloud / ownCloud (im Beispiel hier /var/www/nextcloud) aufgerufen 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.
sudo -u www-data ./calcardbackup /var/www/nextcloud
Nach erfolgreichem Durchlauf des Scripts findet sich das Backup im Ordner backups/. Die Backups mit der Endung tar.gz lassen sich mit folgendem Befehl entpacken:
tar -xzf calcardbackup-2017-03-23.tar.gz
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 /var/www/nextcloud
Das Verhalten des Skripts kann durch verschiedene Optionen beeinflusst werden (unter ihnen auch eine, um Nextcloud Deck-Boards zu exportieren). Details finden sich in den beiden README-Dateien des Repositories. Diese werden aktuell gehalten, erklären alle Optionen ausführlich und enthalten zahlreiche Beispiele auf Deutsch und Englisch.
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:
23.02.2026: komplette Überarbeitung und Entfernung von zahlreichen veralteten Textabschnitten. In diesem Blogbeitrag steht nun nur noch Grundlegendes über calcardbackup. Eine aktuelle ausführliche Anleitung mit Beispielen findet sich in den README-Dateien des Repositories ( Deutsch / Englisch ).
Hallo Bernhard,
gibt es Erfahrungen zur Installation und Einrichtung in TrueNAS Scale? Und beruht das Skript darauf, das ein db_dump durchgeführt wurde? Ich finde keine *_cards Dateien oder ähnliches in meinem postgres-Ordner.
Wie man merkt: Ich kriege aktuell keinen Fuß an den Boden und wäre unheimlich dankbar für Support – das Skript ist per-se genau, was ich suche.
Beste Grüße
Ben
Hallo Ben,
mit TrueNAS Scale kenne ich mich nicht aus.
Das Script greift jedenfalls über den Datenbankserver auf die Daten zu. Mit einem Datenbank-dump oder mit den Rohdateien der Datenbank kann das Script nichts anfangen.
Wenn Nextcloud/ownCloud läuft, genügt dem Script normalerweise die Angabe des Pfads zur Nextcloud/ownCloud Installation wie im README beschrieben.
Viele Grüße
Bernhard.
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:
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
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.
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 ${1} and ${2} table=“${1}“ # ${table_calendars} or ${table_addressbooks} item=“${2}“ # „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.
Hast du hier einen Idee was das Problem sein könnte?
Vielen Dank im voraus.
Gruß Steffen
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.
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:
Was mache ich falsch?
MfG.
Heiner
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!
Hi, i’ve a question, the calendars data is only stored in the DB? or some data is stored in de file system? Thanks!
Hi Mauricio,
Nextcloud and ownCloud store the data of calendars or addressbooks only in the database.
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.
Und mein Abruf sieht wie folgt aus:
Mit der Option
-i|--include-shareswerden 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-iweglassen: 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.
Hallo Bernhard,
wieder mal ein Problem: Bin von NC10 und Raspbian umgestiegen auf NC12 und Archlinux (auf Raspi3).
Kriege jetzt beim Backup folgenden Fehler:
Ich muß dazu sagen, daß ich in der
my.cnfnetworking 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 –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:
Ich hoffe, Dir fällt dazu was ein…
Schöne Grüße, Wolfgang
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
Funktioniert perfekt. Sehr praktisch, danke!
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:
in der Error Datei steht nichts und ich hab in diesem Benutzer eigentlich auch keine Kontakte.
Danke und viele Grüße
Andy
Hallo Andy,
das Problem war, dass
curl>= 7.42.0 leere Dateien erzeugt, wenn es ein leeres Adressbuch empfängt. Ältere Versionen voncurlerzeugen in dem Fall keine leere Datei.Ich habe das Skript korrigiert (v0.1.2) und kompatibel für neuere Versionen von
curlgemacht.Danke für dein Feedback und viele Grüße,
Bernhard
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:
Der Nextcloud-Installer hat in der
php.inidiesen 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
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
Hi, ich würde den Cron-Eintrag in die Crontab des Users
www-datavornehmen:editiert automatisch die richtige Crontab.
Das geht auch – in dem Fall müsste dann die Angabe des Users
www-dataaus der Zeile entfernt werden.