Vom eigenen VPS zum gemeinsamen Kalender
FL-Pro-Selbstlern-Kurs · Stand 02.10.2026
Du richtest eine eigene Nextcloud ein, legst getrennte Benutzerkonten an und organisierst gemeinsam Termine und Aufgaben. Zum Schluss prüfst Du Freigaben, Gerätesynchronisierung und eine Wiederherstellung. Die Grundlage ist der vorhandene Kurs Self-Hosting & VPS. Wenn Du noch keinen Server hast, beginnst Du dort.
Praxisstand: Nextcloud 35.0.1, Calendar 6.6.2 und Tasks 0.18.1. Serverbetrieb, Freigaben, CalDAV, Aufgaben, Buchungen und Wiederherstellung wurden praktisch geprüft. Die Geräteanleitungen folgen den verlinkten Herstellerdokumentationen; Android, iOS und Thunderbird wurden hier nicht auf eigenen Geräten eingerichtet. Das Kursbeispiel verwendet ausschließlich fiktive Personen. Prüfprotokoll und Beispieldateien findest Du am Kursende.
Dein Ergebnis
Die fiktive Familie Mira, Alex und Sam organisiert Robins Betreuung. Sie benötigt eine Übersicht über Aufenthalte, einen Schulkalender und eine Aufgabenliste. Mira und Sam führen daneben Beratungsgespräche. Alex soll die Familiendaten sehen, aber keine Kundentermine. Jede Person hat außerdem einen privaten Kalender.
| Bereich | Mira | Alex | Sam | Außenstehende |
|---|---|---|---|---|
| Robin – Betreuung & Übergaben | Bearbeiten | Bearbeiten | Bearbeiten | Kein Zugriff |
| Robin – Schule & Termine | Bearbeiten | Bearbeiten | Bearbeiten | Kein Zugriff |
| Robin – Elternaufgaben | Bearbeiten | Bearbeiten | Bearbeiten | Kein Zugriff |
| Beratung – Termine | Bearbeiten | Kein Zugriff | Bearbeiten | Kein interner Zugriff |
| Persönlicher Kalender | Nur eigene Daten | Nur eigene Daten | Nur eigene Daten | Kein Zugriff |
Eine Buchungsseite ist eine eigene Freigabeentscheidung. Sie kommt erst nach dem privaten Kalender. Aufgaben und Termine haben in Nextcloud jeweils eine eigene Ansicht.
Aus dem VPS-Kurs hierher wechseln
Ausgangszustand: Du brauchst einen Linux-VPS mit Docker Compose, SSH-Zugang und administrativen Rechten. Nginx Proxy Manager (NPM) übernimmt bereits HTTPS. Du kannst DNS-Einträge Deiner Domain bearbeiten. Ein eigener Testbereich enthält ausschließlich Beispieldaten.
Im VPS-Kurs führen Dich Stufen 1–4 durch Server, SSH und Absicherung, Stufe 6 durch DNS und Stufe 7 durch den Reverse Proxy. Der Docker-Kurs erklärt Volumes und Compose. Bestehende Dienste werden in ihren bisherigen Ordnern betrieben; Nextcloud erhält einen eigenen Stack.
Öffne Dein lokales Terminal, verbinde Dich mit Deinem bereits eingerichteten SSH-Alias und arbeite anschließend in der Linux-Shell des Servers. Beispiel: ssh meinserver. Der Alias stammt aus Deiner SSH-Einrichtung und ist kein Nextcloud-Befehl.
Prüfe auf dem VPS:
docker version
docker compose version
free -h
df -h /
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Ports}}'
docker network ls
Ergebnis: Docker und Compose antworten. Du findest Deinen NPM-Container und siehst freien Arbeitsspeicher und Speicherplatz. Der Beispielstack begrenzt Web, Cron, Datenbank und Redis zusammen auf gut 2 GiB; Betriebssystem, andere Dienste und Sicherungen benötigen zusätzliche Reserven. Diese Limits sind ein Startwert für eine kleine Kalenderinstanz.
Hilfe: Ist der VPS schon knapp ausgelastet, zuerst den Bedarf klären. Keine fremden Container stoppen. Ist /opt/nextcloud-kalender bereits vorhanden, dort nichts überschreiben; bestehende Einrichtung prüfen und einen neuen Übungsordner wählen.
Domain und Verbindung zum Proxy vorbereiten
Ausgangszustand: NPM läuft; Du kennst seinen tatsächlichen Containernamen. Für das Beispiel heißt die neue Adresse kalender.example.org. Ersetze sie durch Deine eigene Subdomain. example.org und 203.0.113.10 sind Dokumentationsbeispiele.
Lege beim DNS-Anbieter einen A-Eintrag an: Name kalender, Wert die IPv4-Adresse Deines VPS. Ein AAAA-Eintrag gehört nur dazu, wenn der Dienst auch über die eingetragene IPv6-Adresse erreichbar ist. Prüfe auf Deinem Rechner, beispielsweise mit PowerShell:
Resolve-DnsName kalender.example.org -Type A
Auf dem VPS liest Du Domain und NPM-Container ein. Die Variablen bleiben für die nächsten Stufen in derselben Servershell erhalten:
read -r -p 'Deine Kalender-Domain, ohne https://: ' CALENDAR_DOMAIN
read -r -p 'Name des laufenden NPM-Containers: ' NPM_CONTAINER
test -n "$CALENDAR_DOMAIN" && test -n "$NPM_CONTAINER"
docker inspect "$NPM_CONTAINER" --format '{{.State.Running}}'
docker inspect "$NPM_CONTAINER" --format '{{json .NetworkSettings.Networks}}'
Die Verbindung zum Vorgängerkurs: Dort wird für die Dienste das Netz web verwendet. Ein vorhandener Server kann beispielsweise web-proxy verwenden. Entscheidend ist, dass NPM und der neue Webcontainer dasselbe Docker-Netz erreichen. Datenbank und Redis gehören nicht in dieses Proxy-Netz.
Für den Kurs legst Du ein eigenes Verbindungsnetz an und verbindest ausschließlich NPM damit. Seine bisherigen Netze bleiben erhalten. Prüfe vorher, dass dieser Name nicht bereits für einen anderen Zweck verwendet wird:
docker network inspect nextcloud-proxy
Bei „network … not found“ anlegen und NPM verbinden:
docker network create nextcloud-proxy
docker network connect nextcloud-proxy "$NPM_CONTAINER"
Bei einer vorhandenen eigenen Kursinstallation beide Schritte überspringen, wenn NPM schon angeschlossen ist. Trage die Verbindung zusätzlich in der vorhandenen NPM-Compose-Datei ein, damit sie bei einer Neuerstellung von NPM erhalten bleibt. Ergänze beim tatsächlichen NPM-Service nextcloud-proxy zu seinen bisherigen Netzwerken; die bisherigen Netzwerke, Ports und Volumes erhalten. Für einen NPM-Service, der bisher das Standardnetz nutzt, sieht die Ergänzung so aus:
services:
npm:
# image, ports, volumes und übrige vorhandene Einstellungen erhalten
networks: [default, nextcloud-proxy]
networks:
default:
nextcloud-proxy:
external: true
Dies ist eine Ergänzung, keine vollständige Ersatzdatei. Nutzt Dein Proxy bereits andere benannte Netze, behältst Du diese statt default bei. Führe docker compose config --quiet im NPM-Ordner aus. Nach dessen nächster Neuerstellung prüfst Du die Verbindung erneut. Die momentane Verbindung besteht bereits durch docker network connect.
Lies die Proxy-IP dieses Netzes aus:
NPM_PROXY_IP=$(docker inspect "$NPM_CONTAINER" \
--format '{{with index .NetworkSettings.Networks "nextcloud-proxy"}}{{.IPAddress}}{{end}}')
test -n "$NPM_PROXY_IP"
Ergebnis: Die Domain zeigt auf Deinen VPS; die Verbindung zum Proxy ist vorbereitet. Öffentlich werden später nur die bestehenden NPM-Ports 80 und 443 verwendet.
Einen eigenen Compose-Stack anlegen
Ausgangszustand: Du arbeitest weiterhin auf dem VPS. Die Variablen aus Stufe 2 sind vorhanden. Du erstellst einen neuen Ordner mit geschützten Zugangsdaten.
sudo -i
Achtung: Falls Du soeben von einem normalen Benutzer zu root gewechselt bist, wiederhole die Variableneingabe und IP-Ermittlung aus Stufe 2 in der neuen Shell. Die folgenden Befehle setzen root-Rechte voraus.
test ! -e /opt/nextcloud-kalender || { echo 'Ordner vorhanden: zuerst prüfen'; exit 1; }
umask 077
mkdir /opt/nextcloud-kalender
cd /opt/nextcloud-kalender
test -n "$CALENDAR_DOMAIN" && test -n "$NPM_PROXY_IP"
DB_SECRET=$(openssl rand -hex 24)
ADMIN_SECRET=$(openssl rand -hex 24)
cat > .env <<EOF
POSTGRES_DB=nextcloud
POSTGRES_USER=nextcloud
POSTGRES_PASSWORD=$DB_SECRET
POSTGRES_HOST=db
REDIS_HOST=redis
NEXTCLOUD_ADMIN_USER=kalender-admin
NEXTCLOUD_ADMIN_PASSWORD=$ADMIN_SECRET
NEXTCLOUD_TRUSTED_DOMAINS=$CALENDAR_DOMAIN
TRUSTED_PROXIES=$NPM_PROXY_IP
OVERWRITEHOST=$CALENDAR_DOMAIN
OVERWRITEPROTOCOL=https
OVERWRITECLIURL=https://$CALENDAR_DOMAIN
PHP_MEMORY_LIMIT=512M
PHP_UPLOAD_LIMIT=64M
TZ=Europe/Berlin
EOF
unset DB_SECRET ADMIN_SECRET
chmod 600 .env
Die .env gehört in Deinen geschützten Einrichtungsbereich, nicht in ein Git-Repository oder eine Supportnachricht. Den Adminzugang über Deinen privaten SSH-Zugang in einen Passwortmanager übernehmen. Keine Zugangsdaten in Screenshots zeigen.
Erstelle docker-compose.yml im gerade angelegten Ordner, z. B. mit nano docker-compose.yml:
name: nextcloud-kalender
x-nextcloud: &nextcloud
image: nextcloud:35.0.1-apache@sha256:b1ae671e9815401b0e837b19b9c778e89887721d67f0c8f9d34aa1d27a9a208f
restart: unless-stopped
env_file: .env
volumes:
- ./html:/var/www/html
networks: [intern]
services:
db:
image: postgres:17-bookworm@sha256:639ab7ceb90e13123085b741fb31ef493fba25463002f6da665352e7b534b652
restart: unless-stopped
mem_limit: 512m
env_file: .env
volumes:
- ./postgres:/var/lib/postgresql/data
networks: [intern]
healthcheck:
test: [CMD-SHELL, 'pg_isready -U "$$POSTGRES_USER" -d "$$POSTGRES_DB"']
interval: 10s
timeout: 5s
retries: 12
redis:
image: redis:7-alpine@sha256:858f009f9709ce576febc734aa78b8f6d624b82571f9ddb6bda4377c833b3499
restart: unless-stopped
mem_limit: 128m
command: [redis-server, --maxmemory, 96mb, --maxmemory-policy, noeviction]
networks: [intern]
web:
<<: *nextcloud
container_name: nextcloud-kalender-web
mem_limit: 1g
networks: [intern, proxy]
volumes:
- ./html:/var/www/html
- ./apache-workers.conf:/etc/apache2/conf-enabled/kalender-workers.conf:ro
depends_on:
db: {condition: service_healthy}
redis: {condition: service_started}
cron:
<<: *nextcloud
mem_limit: 512m
entrypoint: /cron.sh
depends_on: [web]
networks:
intern:
proxy:
external: true
name: nextcloud-proxy
Web und Cron teilen sich die Nextcloud-Dateien; PostgreSQL speichert die Datenbank. Redis unterstützt Sperren und Cache. Es gibt kein ports: für diese Dienste. Die vier Container ergänzen den bestehenden Proxy. Die Versionen und Digests sind ein geprüfter Stand vom 02.10.2026; sie ersetzen keine spätere Updateprüfung.
Erstelle außerdem apache-workers.conf:
<IfModule mpm_prefork_module>
StartServers 1
MinSpareServers 1
MaxSpareServers 1
ServerLimit 2
MaxRequestWorkers 2
MaxConnectionsPerChild 500
</IfModule>
Und den CLI-Helfer occ.sh:
#!/usr/bin/env bash
set -euo pipefail
cd -- "$(dirname -- "$0")"
exec docker compose exec -T -u www-data web php -d apc.enable_cli=1 occ "$@"
chmod 700 occ.sh
docker compose config --quiet
docker compose pull
docker compose up -d
docker compose ps
./occ.sh status --output=json
Ergebnis: Nach der ersten Installation meldet status installed: true, maintenance: false und needsDbUpgrade: false. db ist gesund. Die Anzeige enthält in diesem Entwurf keine tatsächliche Testausgabe.
Hilfe: Bei „database not ready“ kurz warten und docker compose ps prüfen. Bei Neustarts gezielt docker compose logs --tail=80 web db lesen. Keine vollständige Compose-Konfiguration mit Passwörtern in öffentliche Nachrichten kopieren. docker compose down -v ist kein Diagnosebefehl.
Grundlage: Docker-Image und Konfiguration.
HTTPS und CalDAV-Discovery einschalten
Ausgangszustand: Der Stack läuft intern. Die Domain ist korrekt aufgelöst. Du öffnest Deine vorhandene NPM-Verwaltung über den bereits eingerichteten geschützten Zugang.
Lege einen Proxy Host an:
| NPM-Feld | Wert |
|---|---|
| Domain Names | Deine Kalender-Subdomain |
| Scheme | http – die interne Containerverbindung |
| Forward Hostname / IP | nextcloud-kalender-web |
| Forward Port | 80 |
| Access List | Keine zusätzliche HTTP-Basic-Auth vor CalDAV |
| SSL | Neues Let's-Encrypt-Zertifikat anfordern, danach Force SSL |
Unter Advanced / Custom Nginx Configuration ergänzen:
proxy_hide_header Upgrade;
location = /.well-known/caldav {
return 301 https://$host/remote.php/dav/;
}
location = /.well-known/carddav {
return 301 https://$host/remote.php/dav/;
}
Nextcloud braucht den korrekten HTTPS-Host, einen gezielt vertrauten Proxy und diese Discovery-Weiterleitungen. Reverse-Proxy-Dokumentation.
Auf dem VPS prüfen:
curl --fail --silent --show-error "https://$CALENDAR_DOMAIN/status.php"
curl --head "http://$CALENDAR_DOMAIN/"
curl --head "https://$CALENDAR_DOMAIN/.well-known/caldav"
Ergebnis: status.php liefert JSON. HTTP führt zu HTTPS. Die CalDAV-Adresse führt zu /remote.php/dav/. Im Browser öffnet sich die Anmeldung mit gültigem Zertifikat.
Hilfe: 502 weist häufig auf ein falsches Ziel oder ein fehlendes gemeinsames Netz hin. „Untrusted domain“ verlangt einen Vergleich mit NEXTCLOUD_TRUSTED_DOMAINS. Eine Zertifikatswarnung zuerst beheben; TLS-Prüfungen nicht mit curl -k umgehen. Scheitert die Zertifikatsanforderung, DNS, AAAA-Eintrag und Erreichbarkeit von 80/443 kontrollieren.
Calendar, Tasks und eigene Benutzer
Ausgangszustand: Du kannst Dich als kalender-admin über HTTPS anmelden. Dieses Konto dient der Verwaltung. Familienmitglieder bekommen eigene Alltagskonten.
Auf dem Server:
cd /opt/nextcloud-kalender
./occ.sh app:install calendar
./occ.sh app:install tasks
./occ.sh background:cron
./occ.sh app:list
Wenn eine App schon installiert ist, nicht erneut installieren: Zustand lesen und gegebenenfalls ./occ.sh app:enable calendar bzw. tasks verwenden. Im Stand 02.10.2026 sind Calendar 6.6.2 und Tasks 0.18.1 mit Nextcloud 35 kompatibel. Beim späteren Durcharbeiten die angebotene kompatible Version prüfen.
Im Adminmenü öffnest Du Benutzer und legst mira, alex und sam an. Jede Person bekommt ein eigenes Passwort. Keine Mitgliedschaft in der Gruppe admin; diese bleibt beim Verwaltungskonto. E-Mail-Adressen nur eintragen, wenn Du sie kennst. Mit Übungskonten keine echten Einladungsempfänger verwenden.
Melde Dich ab und als Mira wieder an. Stelle unter den persönlichen Einstellungen Sprache, Zeitzone und gegebenenfalls E-Mail-Adresse ein. Prüfe vor dem ersten Termin Europe/Berlin. Richte für Geräte in den Sicherheitseinstellungen ein eigenes App-Passwort ein. Eine verlorene Geräteverbindung lässt sich so einzeln widerrufen. Gerätezugänge.
Ergebnis: Drei getrennte Alltagskonten, ein Verwaltungskonto und die beiden Apps sind vorhanden. Im Verwaltungsbereich ist Cron ausgewählt; der Cron-Container läuft. Hintergrundjobs.
Hilfe: Eine Mailadresse macht aus dem Konto keine Anmeldung über diesen Mailanbieter. Änderungen an .env setzen keine vorhandenen Benutzerpasswörter zurück.

Kalender teilen und Rechte wirklich prüfen
Ausgangszustand: Mira öffnet die Calendar-App. Ein persönlicher Kalender ist vorhanden. Alex und Sam können sich mit ihren eigenen Konten anmelden.
Mira erstellt links über Neuer Kalender die vier Kalender aus der Tabelle am Anfang. Im Menü des jeweiligen Kalenders öffnet sie die Freigabe, sucht den gewünschten Benutzer und aktiviert die Bearbeitungsmöglichkeit. Betreuung, Schule und Elternaufgaben gehen an Alex und Sam. Beratung geht nur an Sam. Der persönliche Kalender bleibt privat.
Lege mit Mira im Schulkalender einen fiktiven Termin „TEST – Elternabend“ an: 09.10.2026, 18:00–19:00, Europe/Berlin, Beschreibung „Mira nimmt teil“. Keine Teilnehmeradressen eintragen: Freigaben zwischen Benutzerkonten brauchen keine Veranstaltungseinladung.
Öffne mit Alex ein separates Browserprofil oder privates Fenster. Alex ergänzt „Formular mitbringen“. Mira muss dieselbe Änderung sehen. Prüfe mit Alex außerdem, dass Beratung und Miras persönlicher Kalender fehlen. Ein Browserfenster mit einer alten Mira-Sitzung wäre kein Berechtigungstest.
Ergebnis: Die freigegebenen Termine sind gemeinsam bearbeitbar. Die gezielt privaten Bereiche sind im anderen Konto nicht sichtbar. Entferne den Testtermin nach der Prüfung.
Hilfe: Sichtbarkeit und Schreibrecht sind unterschiedliche Einstellungen. Ein öffentlicher Kalenderlink ist eine andere Funktion als das Teilen mit einem Benutzer. Für Familien- und Kundendaten verwende hier Benutzerfreigaben. Kalenderfreigaben.

Betreuung, Serien und Elternaufgaben organisieren
Ausgangszustand: Die Freigaben funktionieren. Jetzt prüfst Du den Arbeitsablauf mit Beispielen.
Lege „TEST – Robin bei Alex“ im Betreuungskalender als wiederkehrenden Zeitraum an. Verschiebe anschließend eine einzelne Wiederholung, nicht die gesamte Serie. Kontrolliere auch eine Wiederholung nach einer Zeitumstellung: Ein Termin um 17 Uhr soll lokal um 17 Uhr bleiben.
Stelle den Betreuungskalender auf die Kalendertransparenz „Nie als beschäftigt anzeigen“, sofern die aktuelle Oberfläche diese Einstellung anbietet. Ein Aufenthaltsblock beschreibt, wo Robin ist. Er sagt noch nicht, welche erwachsene Person zu welcher Zeit gebunden ist. Sam trägt eine tatsächliche Abholpflicht deshalb zusätzlich als beschäftigten Termin in Sams persönlichen Kalender ein. Diese Trennung später bei Buchungen gezielt prüfen.
Wechsle zur Tasks-App. Lege dort die gemeinsame Liste „Robin – Elternaufgaben“ an, falls sie noch nicht existiert, und teile sie gezielt mit Alex und Sam. Listen verwenden CalDAV-Kalender; der gleichnamige Bereich kann bereits vorhanden sein. Bestehende Liste verwenden, nicht doppelt anlegen.
Erstelle die Aufgabe „TEST – Schulformular abgeben“ mit Fälligkeit 09.10.2026 und Beschreibung:
Zuständig: Sam
Ergebnis: Formular ausgefüllt und abgegeben.
Rückmeldung: Datum der Abgabe hier ergänzen.
Sam öffnet die Liste, ergänzt die Rückmeldung und markiert die Aufgabe als erledigt. Mira kontrolliert den Status. Die Beschreibung hält die Zuständigkeit fest; daraus folgt keine automatische Zuweisung oder garantierte Benachrichtigung. Tasks-Funktionen.
Ergebnis: Eine Serienausnahme verändert nur den gewählten Termin. Eine Aufgabe hat Fälligkeit, nachvollziehbare Zuständigkeit und gemeinsamen Erledigungsstatus. Entferne die Übungsserie und Aufgabe anschließend.
Hilfe: Zeigt ein Endgerät die Aufgaben nicht, kann trotzdem die Terminsynchronisierung funktionieren. VTODO-Aufgaben benötigen eine passende Aufgaben-App. Die Nextcloud-Datei-App allein ersetzt keinen CalDAV-Client.

Mehrere Kalender auf dem Gerät anzeigen
Ausgangszustand: Die Nextcloud-Kalender funktionieren im Browser. Für Dein Gerät legst Du unter persönlichen Sicherheitseinstellungen ein eigenes App-Passwort an. Du verwendest das Alltagskonto, nicht das Admin-Konto.
Der Hauptweg für die Übung ist Thunderbird am Rechner:
- Öffne die Kalenderansicht und lege einen neuen Kalender im Netzwerk an.
- Verwende Deinen Nextcloud-Benutzernamen und
https://DEINE-DOMAIN/remote.php/dav/als Adresse.DEINE-DOMAINhier durch die Domain aus Stufe 2 ersetzen. - Melde Dich mit dem App-Passwort an und wähle die gewünschten gefundenen Kalender.
- Erstelle „TEST – Synchronisierung“ in einem freigegebenen Nextcloud-Kalender.
- Prüfe den Termin im Nextcloud-Browser. Ändere dort die Beschreibung und synchronisiere Thunderbird erneut.
Bei Problemen kopiere die konkrete CalDAV-Adresse aus den Nextcloud-Kalendereinstellungen statt eines selbst erratenen Kalenderpfads. Thunderbird-Anleitung.
Zusätzliche Gerätewege: Android verwendet beispielsweise DAVx⁵ zur CalDAV-Synchronisierung und eine Kalender-App zur Ansicht. Unter iOS legst Du ein CalDAV-Konto an; die genaue Menüposition hängt von der iOS-Version ab. Verwende auch hier pro Gerät ein eigenes App-Passwort. Android, iOS.
Deinen vorhandenen mailbox.org-Kalender dazunehmen
Lege in derselben Kalender-App ein zweites CalDAV-Konto für mailbox.org an. Server: https://dav.mailbox.org/caldav/, Benutzername: Deine vollständige mailbox.org-Adresse. Verwende einen nach Deinen mailbox.org-Sicherheitseinstellungen gültigen Zugang. Die Zugangsdaten gehören ausschließlich auf Deine eigenen Geräte. mailbox.org-Verbindungsdaten.
Ergebnis: Die App kann Nextcloud und mailbox.org zusammen anzeigen. Die Daten bleiben jeweils beim zugehörigen Anbieter. Beim Erstellen eines Termins entscheidet das Kalenderfeld, wo Du ihn speicherst: Ein neuer gemeinsamer Schultermin gehört in den Nextcloud-Schulkalender.
Die Nextcloud-Webansicht erhält durch das zweite Gerätekonto keinen Zugriff auf den mailbox.org-Kalender. Ebenso werden mailbox.org-Termine dadurch nicht automatisch zu Sperrzeiten einer Nextcloud-Buchungsseite. Eine spätere serverseitige Synchronisierung wäre eine eigene Einrichtung.
Eine externe Buchung getrennt ausprobieren
Ausgangszustand: Deine privaten Kalender sind korrekt freigegeben. Du kennst die konkreten Regeln für ein einfaches Beratungsgespräch. Die folgenden Schritte sind eine Übung mit fiktiven Daten, kein fertiges Angebot für Sitzungen oder Gruppen.
Öffne in Calendar den Bereich Terminpläne / Appointments. Trage zuvor Deine E-Mail-Adresse in den persönlichen Einstellungen ein; ohne sie bietet die Oberfläche keine Einrichtung an. Erstelle ein Probeangebot: „TEST – Kennenlerngespräch“, 30 Minuten, ein Gastgeber, begrenzte Verfügbarkeiten. Prüfe, welche Vorlauf-, Puffer- und Konfliktkalenderoptionen die installierte Version tatsächlich anbietet. Wähle den persönlichen Kalender mit den echten Sperrzeiten des Gastgebers und den Beratungskalender gezielt aus. Betreuung und mailbox.org sind nicht automatisch passende Konfliktkalender.
Prüfe vor externen Tests den E-Mail-Versand. Als Admin: Verwaltungseinstellungen → Grundeinstellungen → E-Mail-Server. Für mailbox.org beispielsweise SMTP, SSL/TLS, smtp.mailbox.org, Port 465, Authentifizierung und vollständiger Benutzername. Den Absender nur auf eine Adresse setzen, für die Dein Konto senden darf. Passwörter privat eingeben; erst eine Testmail an Dich selbst senden. Hier den UI-Weg verwenden, keine zusätzlichen SMTP_*-Werte in .env, die ihn überschreiben. mailbox.org SMTP.
Teste die Buchungsseite ausschließlich selbst in einem privaten Browserfenster:
- Welche Daten sieht ein Gast? Private Termintitel und Familienkalender dürfen dort nicht erscheinen.
- Blockiert ein bewusst belegter persönlicher Termin den Slot?
- Verschwindet ein per E-Mail bestätigter Slot für die nächste Buchung? Eine noch unbestätigte Anfrage kann weiterhin buchbar sein; den Bestätigungslink deshalb wirklich öffnen.
- Kommen die nötigen Bestätigungen an, und ist der Zeitpunkt der verbindlichen Buchung klar?
- Funktionieren Absage und Zeitzonenanzeige nach den Regeln des Angebots? Einen automatischen Absagelink nicht voraussetzen; der dokumentierte Kalenderablauf sieht eine Kontaktaufnahme zum Gastgeber vor.
Nur die Buchungsseite darf später extern verlinkt werden, kein interner Familienkalender. Eine erforderliche manuelle Annahme, mehrere Gastgeber oder Gruppenplätze sind eigene Anforderungen; erst prüfen, ob die gewählte Funktion sie abbildet. Appointment-Dokumentation.
Ergebnis: Du kannst einen einfachen eigenen Buchungsablauf erklären und seine Grenzen benennen. Erst nach erfolgreicher Prüfung und passenden Website-Informationen wird aus dem Probeangebot ein öffentliches Angebot.
Sichern, wiederherstellen und Updates durchführen
Ausgangszustand: Deine Testinstanz funktioniert. Ein Container-Neustart ist kein Backup. Termine, Freigaben und Aufgaben benötigen die Datenbank; zusätzlich müssen Konfiguration, Apps und Dateien gesichert werden. Backup-Grundlagen.
Für die kleine Kursinstanz stoppen wir Web und Cron während der Sicherung kurz. Datenbank und Dateikopie stammen so aus demselben ruhenden Zustand. Das Skript startet die beiden Dienste auch bei einem Sicherungsfehler wieder.
Erzeuge auf dem VPS als root einen getrennten Schlüssel. Übernimm eine geschützte Kopie in Deinen privaten Backupbereich außerhalb des VPS. Ohne Schlüssel lässt sich die Sicherung nicht entschlüsseln:
umask 077
test ! -e /root/.nextcloud-kalender-backup.key || { echo 'Schlüssel bereits vorhanden: nicht überschreiben'; exit 1; }
openssl rand -hex 32 > /root/.nextcloud-kalender-backup.key
mkdir -p /var/backups/nextcloud-kalender
Erstelle /opt/nextcloud-kalender/backup.sh:
#!/usr/bin/env bash
set -euo pipefail
umask 077
cd /opt/nextcloud-kalender
key=/root/.nextcloud-kalender-backup.key
target=/var/backups/nextcloud-kalender
test -s "$key"
mkdir -p "$target"
exec 9>/run/lock/nextcloud-kalender-backup.lock
flock -n 9 || exit 0
tmp=$(mktemp -d /opt/nextcloud-kalender/.backup-XXXXXXXX)
stopped=0
cleanup() {
result=$?
trap - EXIT
if [ "$stopped" = 1 ]; then
docker compose start web cron || result=1
fi
case "$tmp" in /opt/nextcloud-kalender/.backup-*) rm -rf -- "$tmp" ;; esac
exit "$result"
}
trap cleanup EXIT
stamp=$(date -u +%Y%m%dT%H%M%SZ)
archive="$target/$stamp.tar.gz.enc"
stopped=1
docker compose stop web cron
docker compose exec -T db sh -c \
'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" --format=custom' > "$tmp/database.dump"
cp docker-compose.yml .env apache-workers.conf occ.sh backup.sh "$tmp/"
cp -a html "$tmp/html"
tar -czf - -C "$tmp" . | openssl enc -aes-256-cbc -salt -pbkdf2 \
-iter 200000 -pass file:"$key" -out "$archive.partial"
openssl enc -d -aes-256-cbc -pbkdf2 -iter 200000 -pass file:"$key" \
-in "$archive.partial" | tar -tzf - >/dev/null
mv -- "$archive.partial" "$archive"
sha256sum "$archive" > "$archive.sha256"
echo "Sicherung erstellt: $stamp"
cd /opt/nextcloud-kalender
chmod 700 backup.sh
bash -n backup.sh
./backup.sh
docker compose ps
Die Sicherungen sind nur für root lesbar. Dein normaler SSH-Benutzer aus dem VPS-Kurs braucht deshalb eine geschützte Exportkopie; Root-Login bleibt deaktiviert. Zuerst auf dem VPS als root:
read -r -p 'Dein normaler SSH-Benutzer (nicht root): ' BACKUP_SSH_USER
test "$BACKUP_SSH_USER" != root
BACKUP_SSH_GROUP=$(id -gn "$BACKUP_SSH_USER")
BACKUP_SSH_HOME=$(getent passwd "$BACKUP_SSH_USER" | cut -d: -f6)
test -n "$BACKUP_SSH_HOME" && test -d "$BACKUP_SSH_HOME"
install -d -m 700 -o "$BACKUP_SSH_USER" -g "$BACKUP_SSH_GROUP" \
"$BACKUP_SSH_HOME/nextcloud-backups" "$BACKUP_SSH_HOME/nextcloud-schluessel"
for BACKUP_EXPORT_FILE in /var/backups/nextcloud-kalender/*.tar.gz.enc /var/backups/nextcloud-kalender/*.sha256; do
test -f "$BACKUP_EXPORT_FILE" || continue
install -m 600 -o "$BACKUP_SSH_USER" -g "$BACKUP_SSH_GROUP" \
"$BACKUP_EXPORT_FILE" "$BACKUP_SSH_HOME/nextcloud-backups/"
done
install -m 600 -o "$BACKUP_SSH_USER" -g "$BACKUP_SSH_GROUP" \
/root/.nextcloud-kalender-backup.key "$BACKUP_SSH_HOME/nextcloud-schluessel/backup.key"
Dann im lokalen Windows-Terminal; den SSH-Alias ersetzen. Die Schlüsselkopie liegt in einem getrennten, auf Dein Windows-Konto begrenzten Ordner:
New-Item -ItemType Directory -Force ./nextcloud-backups | Out-Null
New-Item -ItemType Directory -Force ./nextcloud-schluessel | Out-Null
$BackupIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
icacls ./nextcloud-schluessel /inheritance:r /grant:r "${BackupIdentity}:(OI)(CI)F"
scp 'meinserver:nextcloud-backups/*.tar.gz.enc' ./nextcloud-backups/
scp 'meinserver:nextcloud-backups/*.sha256' ./nextcloud-backups/
scp 'meinserver:nextcloud-schluessel/backup.key' ./nextcloud-schluessel/
Get-FileHash ./nextcloud-backups/*.tar.gz.enc -Algorithm SHA256
Vergleiche den Hash mit dem entsprechenden Wert in der .sha256-Datei. Er prüft die Übertragung; er ist keine Signatur. Die gewählte OpenSSL-Verschlüsselung bietet Vertraulichkeit, aber keine integrierte Authentizitätsprüfung. Schlüssel und Sicherungen deshalb geschützt aufbewahren. Plane Rotation und freien Speicher; dieses einfache Kursskript löscht keine alten Sicherungen.
Wiederherstellung in einem eigenen Teststack
Erstelle einen markierten Übungstermin vor der Sicherung. Stelle diese Sicherung in einem neuen Ordner wieder her. Verwende ausschließlich Deine eigene Sicherung und Deinen Schlüssel. Nicht über den produktiven Ordner entpacken.
Auf dem VPS, als root:
read -r -p 'Absoluter Pfad zu Deiner eigenen .tar.gz.enc-Sicherung: ' BACKUP_FILE
test -f "$BACKUP_FILE"
RESTORE_DIR=$(mktemp -d /opt/nextcloud-kalender-restore-XXXXXXXX)
openssl enc -d -aes-256-cbc -pbkdf2 -iter 200000 \
-pass file:/root/.nextcloud-kalender-backup.key -in "$BACKUP_FILE" \
| tar -xzf - -C "$RESTORE_DIR"
cd "$RESTORE_DIR"
Die wiederhergestellte normale Compose-Datei nicht starten. Erstelle stattdessen compose.restore.yml:
services:
db:
image: postgres:17-bookworm@sha256:639ab7ceb90e13123085b741fb31ef493fba25463002f6da665352e7b534b652
env_file: .env
mem_limit: 512m
volumes: [./restore-postgres:/var/lib/postgresql/data]
networks: [isoliert]
healthcheck:
test: [CMD-SHELL, 'pg_isready -U "$$POSTGRES_USER" -d "$$POSTGRES_DB"']
interval: 5s
timeout: 5s
retries: 20
redis:
image: redis:7-alpine@sha256:858f009f9709ce576febc734aa78b8f6d624b82571f9ddb6bda4377c833b3499
mem_limit: 128m
networks: [isoliert]
web:
image: nextcloud:35.0.1-apache@sha256:b1ae671e9815401b0e837b19b9c778e89887721d67f0c8f9d34aa1d27a9a208f
env_file: .env
mem_limit: 1g
environment:
OVERWRITEHOST: localhost:8780
OVERWRITEPROTOCOL: http
OVERWRITECLIURL: http://localhost:8780
NEXTCLOUD_TRUSTED_DOMAINS: localhost
volumes: [./html:/var/www/html]
networks: [isoliert]
networks:
isoliert:
internal: true
Dieses Testnetz hat keinen externen Zugang. Es gibt keinen Cron, keinen öffentlichen Port und keine Verbindung zu NPM. Gleiche Servicenamen bedeuten hier eigene Dienste im getrennten Compose-Projekt.
RESTORE_PROJECT=$(basename "$RESTORE_DIR" | tr '[:upper:]' '[:lower:]')
docker compose -p "$RESTORE_PROJECT" -f compose.restore.yml up -d --wait db redis
docker compose -p "$RESTORE_PROJECT" -f compose.restore.yml exec -T db \
pg_restore -U nextcloud -d nextcloud --no-owner --no-privileges --exit-on-error < database.dump
cat > html/config/zzz-restore.config.php <<'PHPRESTORE'
<?php
$CONFIG = [
'dbuser' => getenv('POSTGRES_USER'),
'dbpassword' => getenv('POSTGRES_PASSWORD'),
'trusted_domains' => ['localhost', '127.0.0.1'],
'overwritehost' => 'localhost:8780',
'overwriteprotocol' => 'http',
'overwrite.cli.url' => 'http://localhost:8780',
'mail_smtphost' => '127.0.0.1',
'mail_smtpport' => 9,
];
PHPRESTORE
chmod 644 html/config/zzz-restore.config.php
docker compose -p "$RESTORE_PROJECT" -f compose.restore.yml up -d web
Nextcloud kann bei der Installation einen eigenen Datenbankbenutzer wie oc_admin anlegen. Dieser gehört zum alten Datenbankcluster. Der Test verwendet deshalb die Zugangsdaten seiner neu angelegten Datenbank und importiert keine alten Rollen oder Berechtigungen. zzz-restore.config.php ist ausschließlich für diesen Teststack. Nach dem Start dieselbe Test-Compose-Datei bei jedem Aufruf verwenden:
docker compose -p "$RESTORE_PROJECT" -f compose.restore.yml exec -T -u www-data web \
php -d apc.enable_cli=1 occ status --output=json
docker compose -p "$RESTORE_PROJECT" -f compose.restore.yml exec -T -u www-data web \
php -d apc.enable_cli=1 occ user:list
RESTORE_IP=$(docker compose -p "$RESTORE_PROJECT" -f compose.restore.yml ps -q web \
| xargs docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}')
printf 'Nur für Deinen SSH-Tunnel: %s\n' "$RESTORE_IP"
Öffne lokal einen SSH-Tunnel, ersetze TEST-CONTAINER-IP durch die soeben ermittelte Adresse und meinserver durch Deinen SSH-Alias:
ssh -N -L 127.0.0.1:8780:TEST-CONTAINER-IP:80 meinserver
Im Browser http://localhost:8780 öffnen. Dieses HTTP bleibt innerhalb des SSH-Tunnels. Prüfe den wiederhergestellten Testtermin, die Aufgabe und die Freigaben mit den bekannten Testkonten. Eine bloße Auflistung der Benutzer beweist noch keine vollständige Wiederherstellung. Wiederherstellungsgrundlagen.
Stoppe anschließend nur den Teststack, in dessen Verzeichnis:
docker compose -p "$RESTORE_PROJECT" -f compose.restore.yml down
Der Testordner enthält geschützte wiederhergestellte Daten. Seine spätere Entfernung erfordert die Kontrolle des konkreten Pfads. Der Produktivstack und seine Daten bleiben erhalten.
Regelmäßiger Betrieb und Updates
Ergänze erst nach erfolgreicher Sicherung und Wiederherstellungsprobe mit crontab -e eine Zeile. Bestehende Zeilen erhalten:
13 6 * * * /opt/nextcloud-kalender/backup.sh >> /var/log/nextcloud-kalender-backup.log 2>&1
Die Zeit gilt in der Zeitzone des Servers. Kontrolliere die nächste tatsächliche Ausführung und hole die Sicherung außerhalb des VPS ab. Die Schlüsselkopie gehört nicht in dasselbe ungeschützte Verzeichnis wie die Archive.
Vor einem Update: Kompatibilität von Server, Calendar und Tasks prüfen, frisch sichern und einen Rückweg bereithalten. Dann die Image-Version samt Digest gezielt aktualisieren, Web und Cron auf derselben Nextcloud-Version halten und docker compose pull / up -d ausführen. Danach occ status, Cron, Login, gemeinsame Bearbeitung und CalDAV prüfen. Datenbank-Major-Upgrades sind ein eigener Schritt. Ein älteres Image über eine bereits aktualisierte Datenbank zu starten ist kein verlässliches Rollback.
Deine Einrichtung selbst prüfen
Bestätige nur Ergebnisse, die Du selbst geprüft hast. Deine Häkchen werden ausschließlich in diesem Browser gespeichert. Sie sind Deine Selbstauskunft, keine automatische Serverprüfung.
Beispieldateien und Betriebscheckliste · Unser Prüfprotokoll
Entscheidungen und Fehlerfälle
Sechs Fragen; ab fünf richtigen Antworten ist die Lernkontrolle bestanden. Jede Auswertung erklärt Dir die richtige Entscheidung. Für den Teilnahmenachweis bestätigst Du zusätzlich die sieben Ergebnisse der Abschlussaufgabe.
Dein Teilnahmenachweis
Für den Nachweis brauchst Du eine bestandene Lernkontrolle und Deine sieben bestätigten Übungsergebnisse.
FL Pro Consulting · Selbstlern-Kurs
Nextcloud: eigene Kalender gemeinsam organisieren
Dein Name
Die praktischen Übungen wurden von der teilnehmenden Person selbst bestätigt. Dieser Nachweis ist keine externe Zertifizierung und keine automatische Prüfung ihrer Servereinrichtung.
Florian Ludwig · FL Pro Consulting