Nextcloud ist eine beliebte Software wenn es darum geht eine eigene Cloud-Infrastruktur aufzubauen und zu verwalten. Neben der Dateispeicherung und -teilung ermöglicht Nextcloud auch eine nahtlose Integration von Kontakten und Kalendern in verschiedene Systeme, sowohl auf dem PC als auch auf mobilen Endgeräten. Doch was ist, wenn man sicherstellen möchte, dass persönliche Daten wie Kontakte und Kalender auch außerhalb der Nextcloud sicher und verfügbar bleiben? Die Antwort liegt im Exportieren dieser Daten. In diesem Beitrag zeige ich, wie man Nextcloud Kontakte und Kalender effektiv exportieren und als Backup speichern kann.
Zum Kapitel springen Standardisierte Dateien
Nextcloud bietet sowohl für die Kontakte als auch die Kalender einfache Möglichkeiten diese herunterzuladen. Kalender und Kontakte werden in spezifischen Dateien gespeichert.
Typ | Datei | Standard |
---|---|---|
Kalender | .ics - Kalender-Austauschformat | RFC 5545 |
Kontakte | .vcf - vCard; "Elektronische Visitenkarte" | RFC 6350 |
Das besondere an diesen Dateien ist, dass diese den kompletten Kalender bzw. das komplette Adressbuch beinhalten - nicht nur einzelne Einträge. Da es sich bei den Dateien um einen nach RFC definierten Standard handelt, können diese Dateien auf so gut wie jedem System mit einer Kalender- oder Kontaktfunktion importiert werden. Im Falle eines Ausfalls kann man die gesicherten Daten also ohne Probleme wiederherstellen, ohne große Verluste hinnehmen zu müssen.
Zum Kapitel springen Manuelles Backup
Die wohl einfachste Möglichkeit ist es, die Daten manuell zu sichern. Hierfür bietet Nextcloud sowohl für die Kontakte als auch die Kalender eine einfache Möglichkeit die jeweiligen Daten direkt herunterzuladen.
Zum Kapitel springen Für Kontakte
Navigiere innerhalb der Nextcloud auf die Seite der Kontakte und öffne das Menü Kontakte-Einstellungen
über die Sidebar.
In dem Modal findest du nun eine Liste aller verfügbaren Adressbücher. Über den jeweiligen Eintrag kann das Adressbuch direkt als Datei heruntergeladen werden. Das Adressbuch wird mit seinem Namen und dem aktuellen Datum gespeichert.
kontakte-2024-04-08.vcf
Die Datei kann nun abgelegt werden. Das Backup war erfolgreich.
Du kannst den Link auch direkt aufrufen um die Datei herunterzuladen:
https://cloud.example.com/remote.php/dav/addressbooks/users/cooper.bin/kontakte/?export
Zum Kapitel springen Für Kalender
Gehe in den Reiter "Kalender" und öffne die Einstellungen für den betroffenden Kalender über die Sidebar. Dies geht über das Pencil-Icon.
Am unteren Rand des Modal-Fensters siehst du direkt einen Button zum Exportieren des Kalenders.
Auch hier wird der Download direkt angestoßen und der Kalender wird mit passenden Namen und dem aktuellen Datum gespeichert.
aufgaben-blog-artikel-2024-04-08.ics
Das aufmerksame Auge sieht, dass der Dateiname beim Export nicht derselbe ist, den der Kalender trägt. Das ist nicht weiter schlimm, denn in der Datei selbst ist der Name des Kalenders korrekt hinterlegt. Beim Importieren wird auf diesen Namen zugeriffen.
Ein Blick in die Datei verrät es:
BEGIN:VCALENDAR
VERSION:2.0
CALSCALE:GREGORIAN
PRODID:-//SabreDAV//SabreDAV//EN
X-WR-CALNAME:Blog-Artikel Aufgaben
X-APPLE-CALENDAR-COLOR:#F67300
REFRESH-INTERVAL;VALUE=DURATION:PT4H
X-PUBLISHED-TTL:PT4H
[...]
Auch hier gilt:
Du kannst den Link des Downloads auch hier direkt aufrufen:
https://cloud.example.com/remote.php/dav/calendars/cooper.bin/aufgaben-blog-artikel/?export
Zum Kapitel springen Programmiertes Backup
Ein programmiertes Backup ist nicht ohne Weiteres möglich - man braucht gewisse Tools. Am einfachsten kann das Backup direkt über die besprochenen Links durchgeführt werden.
Die Datei hinter dem Link ist durch eine Authentifizierung abgesichert und kann nur von authentifizierten Clients heruntergeladen werden. Für einem programmierten Download müssen die Zugangsdaten in der HTTP-Anfrage übermittelt werden.
Ich habe dazu ein paar Snippets für verschiedene Systeme und Programmiersprachen vorbereitet. Bei allen Snippets müssen dabei jeweils die Zugangsdaten zur Cloud und die Links zu den Downloads angepasst werden. Es lassen sich in jedem Snippet mehrere Links hinterlegen. Kalender und Kontakte werden unterstützt. Der Name der jeweiligen Datei wird aus dem Download übernommen. Beim Ausführen des jeweiligen Codes werden die definierten Dateien in das Verzeichnis des ausgeführten Scripts Heruntergeladen.
Die folgenden Snippets sind so geschrieben, dass sie mit den Standardbibliotheken arbeiten. Es müssen keine Bibliotheken installiert werden.
Zum Kapitel springen Javascript - Node.JS
node backup.js
const fs = require('fs').promises;
// Benutzername, Passwort
const username = 'BENUTZERNAME';
const password = 'PASSWORD';
// Liste von URLs
const urls = [
"https://cloud.example.com/remote.php/dav/calendars/cooper.bin/persnlich/?export"
// weitere Einträge können hinzugefügt werden
];
const auth = 'Basic ' + Buffer.from(username + ':' + password).toString('base64');
urls.forEach(url => {
fetch(url, { headers: { 'Authorization': auth } })
.then(response => {
if (!response.ok) throw new Error(`Error beim Fetch: ${response.statusText}`);
const disposition = response.headers.get('content-disposition');
// Fallback-Dateiname
let filename = "defaultFilename.txt";
if (disposition && disposition.indexOf('attachment') !== -1) {
const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
const matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) {
filename = matches[1].replace(/['"]/g, '');
}
}
response.arrayBuffer().then(arrayBuffer => {
const buffer = Buffer.from(arrayBuffer);
fs.writeFile(filename, buffer)
.then(() => console.log(`${filename} wurde erfolgreich gespeichert.`))
.catch(err => console.error(`Fehler beim Speichern der Datei: ${err}`));
});
})
.catch(err => console.error(`Fehler beim Herunterladen von ${url}: ${err}`));
});
Zum Kapitel springen Windows Powershell
PowerShell -NoProfile -ExecutionPolicy Bypass -File "backup.ps1"
# Benutzername, Passwort
$username = "BENUTZERNAME"
$password = "PASSWORD"
# Liste aller Download-URLs
$downloadLinks = @(
"https://cloud.example.com/remote.php/dav/calendars/cooper.bin/persnlich/?export"
# weitere Einträge können hinzugefügt werden
)
# Die Zugangsdaten in Base64 umwandeln für den Authorization Header
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$($username):$($password)"))
# Schleife durch jede URL in der Liste
foreach ($downloadLink in $downloadLinks) {
# HTTP-Anfrage senden, um Headers zu erhalten
$response = Invoke-WebRequest -Uri $downloadLink -Headers @{Authorization = "Basic $base64AuthInfo"} -Method Head
# Versuchen, den Dateinamen aus dem Content-Disposition Header zu extrahieren
$filename = $response.Headers["Content-Disposition"] -replace 'attachment; filename="(.*)"', '$1'
if (-not $filename) {
# Fallback, falls kein Dateiname im Header gefunden wurde
# Als Fallback verwenden wir den letzten Teil der URI als Dateinamen
$filename = $uri.Split('/')[-1]
if(-not $filename) {
$filename = "defaultFilename.txt" # Standarddateiname oder eine andere Logik zur Benennung
}
}
Write-Output "Download der Datei: $filename von $downloadLink"
# Download mit dem extrahierten Dateinamen durchführen
Invoke-WebRequest -Uri $downloadLink -Headers @{Authorization = "Basic $base64AuthInfo"} -OutFile "./$filename"
}
Zum Kapitel springen Linux Bash Script
bash backup.sh
#!/bin/bash
# Benutzername, Passwort
username="BENUTZERNAME"
password="PASSWORD"
# Liste von URLs
downloadLinks=(
"https://cloud.example.com/remote.php/dav/calendars/cooper.bin/persnlich/?export"
# weitere Einträge können hinzugefügt werden
)
for downloadLink in "${downloadLinks[@]}"
do
# Der `-J` Schalter sagt curl, den Dateinamen aus dem Content-Disposition Header zu verwenden
# Der `-O` Schalter speichert die Datei unter ihrem ursprünglichen Namen
# Die Option `-L` erlaubt curl, Weiterleitungen zu folgen
# Authentifizierungsdaten werden mit der Option `-u` übergeben
echo "Downloading from $downloadLink..."
curl -L -J -O -u "$username:$password" "$downloadLink" --create-dirs -o "./$(basename "$url")"
done
echo "Download abgeschlossen."
Zum Kapitel springen Python
python backup.py
import urllib.request
from urllib.parse import urlparse
import os
from pathlib import Path
import base64
import re
# Benutzername, Passwort
username = 'BENUTZERNAME'
password = 'PASSWORD'
# Liste der URLs
urls = [
"https://cloud.example.com/remote.php/dav/calendars/cooper.bin/persnlich/?export"
# weitere Einträge können hinzugefügt werden
]
credentials = ('%s:%s' % (username, password)).encode('utf-8')
base64_credentials = base64.b64encode(credentials).decode('utf-8')
for url in urls:
# Erstellen einer Anfrage mit dem Authorization-Header
request = urllib.request.Request(url)
request.add_header('Authorization', 'Basic %s' % base64_credentials)
# Anfrage senden
with urllib.request.urlopen(request) as response:
# Versuch, den Dateinamen aus dem Content-Disposition Header zu extrahieren
cd = response.info().get('Content-Disposition')
if cd:
filename = re.findall('filename="(.+)"', cd)
if filename:
filename = filename[0]
else:
# Fallback, falls kein Dateiname im Content-Disposition Header gefunden wurde
parsed_url = urlparse(url)
filename = os.path.basename(parsed_url.path)
else:
# Fallback, falls kein Content-Disposition Header vorhanden ist
parsed_url = urlparse(url)
filename = os.path.basename(parsed_url.path)
if not filename:
filename = 'default_filename'
# Dateiinhalt schreiben
with open(filename, 'wb') as f:
f.write(response.read())
print(f'Datei {filename} wurde erfolgreich heruntergeladen.')