Nextcloud ist ein wichtiger Teil meiner Datenhaltung. Daher habe ich mir überlegt, wie ich im absoluten Notfall das System möglichst schnell wieder ans Laufen bekomme. Dazu brauche ich ein Notfall Playbook, das mir den Raspberry Pi komplett einrichtet und die Dockercontainer baut.

Szenario
Das Szenario besteht aus der Annahme, dass nach einem Hardwareversagen die Nextcloud Installation komplett neu aufgesetzt werden muss. Dies lässt sich mit einem Ansible Playbook sehr gut automatisieren. Dazu zerlegen wir den Einrichtungsprozess in mehrere einzelne Schritte, für die wir einzelne Plays bauen.
Rolle anlegen
Zunächst benötigen wir ein Verzeichnis für unsere Rolle mit den Unterverzeichnissen.
mkdir -p roles/initnextcloud/tasks
mkdir -p roles/initnextcloud/files
mkdir -p roles/initnextcloud/vars
Parametrisierung
Zunächst müssen wir uns überlegen, welche Werte sich bei einer Neuinstallation von der alten Installation unterscheiden können. Diese lagern wir in Variablendeklarationen in einzelne Dateien aus und deklarieren Variablen darin.
Als erstes fällt mir da die PARTUUID der Daten NVME ein, die sich beim Austausch des Datenträgers ändern kann.
Diese deklarieren wir in roles/initnextcloud/vars/partuuid.yml
partuuid: "011ad286-01"
Die PARTUUID kannst du mit
ls -l /dev/disk/by-partuuid/
oder alternativ mit
blkid /dev/sda1
herausfinden. Du musst dazu die Partition deines Datenträgers nehmen.

Auf meinem Testsystem für diesen Post simuliert ein USB-Stick den NVME-Datenträger des produktiven Systems. Die Partition darauf ist unter /dev/sda1 gelistet.
Die Variablendatei roles/initnextcloud/vars/pckg.yml enthält alle Packages, die mit apt auf dem neu aufgesetzten System installiert werden sollen. Diese kannst du nach Belieben anpassen.
packages:
- python3-docker
- neofetch
- htop
- cowsay
- docker.io
- docker-compose
- git
- locate
- dnsutils
- nfs-kernel-server
- vim
- lsof
- ripgrep
Die Paketliste solltest du für dein System pflegen und aktualisieren.
Die Nextcloud Installation benötigt einige Verzeichnisse u.a. für die Volumes der Container. Auch die deklarieren wir in einer Liste in roles/initnextcloud/vars/dirs.yml
Zusätzlich deklarieren wir hier den URL für das Docker Repository und das Verzeichnis, in das das Repo hinein gecloned werden soll.
dockerrepo: "https://raspithekgit.srv64.de/raspithek/docker"
dockerdir: "/home/pi/git/dockercmd"
volumedirs:
- /mnt/nextcloud
- /opt/clamav
homedirs:
- bin
- git
ncdirs:
- /mnt/nextcloud/nextcloud/apps
- /mnt/nextcloud/nextcloud/html
- /mnt/nextcloud/nextcloud//data
- /mnt/nextcloud/nextcloud/config
Mit diesen drei .yml Dateien ist die Konfiguration unseres Playbooks bereits abgeschlossen.
Installationsschritte
Jetzt überlegen wir, was wir machen müssen, um Nextcloud im Notfall wieder ans Laufen zu bekommen.
Voraussetzung ist ein bootfähiges System, bei dem der ssh Zugang mit private Key für den User pi möglich ist.
Ich zerlege die Aufsetzprozedur in diese Teilschritte
- Einrichten des Betriebssystems
- Daten-NVME mounten und in fstab anlegen
- Anlegen der benötigten Verzeichnisse
- Docker Container einrichten
- zusätzliche optionale Schritte
Einrichten des Betriebssystems
Hier wird in erster Linie ein dist-upgrade von Raspberry Pi OS durchgeführt, im zweiten Schritt werden die Pakete aus der oben deklarierten Liste installiert.
- name: PI Update
become: true
apt:
update_cache: yes
upgrade: dist
- name: Pakete installieren
become: true
ansible.builtin.apt:
name: "{{ packages }}"
state: present
update_cache: yes
cache_valid_time: 86400
Datenpartition mounten
Zum Mounten der Datenpartition muss der notwendige Mountpoint angelegt werden. Danach wird ein Backup der /etc/fstab erzeugt. Das Mounten der der Partition fügt automatisch einen neuen Eintrag in der fstab hinzu. Danach ist die Partition verfügbar und wird auch nach einem Neustart wieder eingebunden. Da Ansible die Facts nicht von sich aus aktualisiert, müssen wir das explizit anstoßen.
- name: create mount dir
become: true
file:
path: "/mnt/nextcloud"
state: directory
- name: Backup der /etc/fstab anlegen
become: true
ansible.builtin.copy:
src: /etc/fstab
dest: /etc/fstab.backup.{{ ansible_date_time.iso8601 }}
remote_src: yes
mode: '0644'
- name: Ensure /mnt/nextcloud is mounted and in fstab
become: true
ansible.posix.mount:
path: /mnt/nextcloud
src: "PARTUUID={{ partuuid }}"
fstype: "ext4"
opts: "defaults,noatime"
state: mounted
- name: Facts aktualisieren
setup:
filter: ansible_mounts
Anlegen der benötigten Verzeichnisse
Dieses Play arbeitet die drei Listen aus vars/dirs.yml ab und legt die Verzeichnisse an. Als erstes wird geprüft, ob die Datenpartition korrekt eingebunden ist, sonst hat ein Weiterleiten des Playbooks keinen Zweck und es wird mit Fehlermeldung abgebrochen.
- name: Abbrechen, wenn /mnt/nextcloud nicht gemountet ist
fail:
msg: "/mnt/nextcloud ist nicht gemountet – Playbook wird abgebrochen."
when: "'/mnt/nextcloud' not in (ansible_mounts | map(attribute='mount') | list)"
- name: create home dirs
file:
path: "~/{{ item }}"
state: directory
loop: "{{ homedirs }}"
- name: create volume dir
become: true
file:
path: "{{ item }}"
state: directory
owner: pi
group: pi
mode: '0755'
loop: "{{ volumedirs }}"
- name: create nextcloud dirs
file:
path: ~/{{ item}}
state: directory
loop: "{{ ncdirs }}"
Dockercontainer einrichten
Dieser Schritt cloned das Docker Repository mit dem notwendigen docker-compose.yml und fügt den User pi
den benötigten Gruppen hinzu. Dann werden alle Container im docker-compose.yml erzeugt und gestartet. Dieser Schritt darf natürlich erst nach dem Anlegen der Verzeichnisse für die Volumes geschehen!
- name: Clone docker-compose repository
ansible.builtin.git:
repo: "{{ dockerrepo }}"
dest: "{{ dockerdir }}"
version: master
- name: Permission für Docker
become: true
file: path=/var/run/docker.sock mode=0660
# mode: 660
- name: adding user pi to docker group
become: true
user:
name: pi
groups: docker,video
- name: Run docker-compose up
community.docker.docker_compose:
project_src: '{{dockerdir }}/nextcloud'
state: present
become: true
Optionale Aufgaben
Dieser Schritt hat weniger mit Nextcloud zu tun sondern dient mehr, mir die Bedienung des Systems zu vereinfachen. zum einen kopiere ich hier meine Scripts auf den Pi, zum anderen benötigte Dateien für den User. Du kannst ihn gerne benutzen, aber auch völlig weglassen. Beide Tasks benutzen die fileglob Schleife, um alle Dateien unter roles/initnextcloud/files/scripts nach /home/pi/bin zu kopieren.Genauso wird alles unter roles/initnextcloud/files/resources ins Homeverzeichnis von pi kopiert.
- name: copy scripts
copy:
src: "{{ item }}"
dest: /home/pi/bin
mode: '0755'
loop: "{{ query('fileglob', 'files/scripts/*') }}"
- name: copy resources to ~
copy:
src: "{{ item }}"
dest: /home/pi
loop: "{{ query('fileglob', 'resources/*') }}"
main.yml
Alle diese einzelnen Plays können wir jetzt in der main.yml einbinden.
- include_vars: "roles/initnextcloud/vars/dirs.yml"
- include_vars: "roles/initnextcloud/vars/partuuid.yml"
- include_vars: "roles/initnextcloud/vars/pckg.yml"
- import_tasks: install.yml
- import_tasks: optional.yml
- import_tasks: mount.yml
- import_tasks: dirs.yml
- import_tasks: docker.yml
Zunächst müssen alle Variablendeklarationen inkludiert werden, danach die Task Files in der Reihenfolge, wie sie abgearbeitet werden sollen. In der Reihenfolge ist in erster Linie wichtig:
- Das Datenlaufwerk ist gemounted bevor die Volume Verzeichnisse angelegt werden, da sie zum Teil auf dem Laufwerk liegen
- Die Verzeichnisse müssen vor dem Start der Dockercontainer existieren.
Das Playbook
Das Playbook ist ziemlich kurz, da die gesamte Logik in der Rolle liegt. Beachte, dass hier gather_facts explizit eingeschaltet ist, da dirs.yml sonst den Zustand der Datenpartition nicht abfragen kann.
---
- hosts: "{{ target }}"
gather_facts: true
remote_user: pi
roles:
- initnextcloud
Test
Zum Test des Playbooks benutze ich einen Raspberry Pi 5 16GB mit angesteckten 64GB USB Stick. Dieser soll die Daten NVME des produktiven Systems simulieren.
Auf der MicroSD flashe ich eine frische Raspberry Pi OS (bookworm) Installation. Nachdem ich den ssh Zugang hergestellt habe, starte ich das Playbook
ansible-playbook -e="target=testsystem" initnextcloud.yml

Nach dem erfolgreichen Durchlauf logge ich mich ins System ein und prüfe, ob folgende Konfigurationen erfolgreich durchgeführt wurden:
- Für die Datenpartition wurde ein Eintrag in der fstab angelegt
- Für die Datenpartition wurde ein Eintrag in der /etc/fstab angelegt
- Die Dockercontainer wurden erfolgreich gestartet.

Auch nach einem Neustart ist das Setup korrekt.
Was das Playbook kann
Das Playbook stellt die komplette Nextcloud Installation auf einem fertig konfigurierten Raspberry Pi mit einem frischen Raspberry Pi OS her. Die Container von ClamAV und Nextcloud Cron werden dabei über das docker-compose.yml mit aufgebaut.
Was das Playbook nicht kann
Backupdaten einspielen und Nextcloud konfigurieren. Auch die Anbindung an ClamAV muss du manuell herstellen.
Fazit
Dieses Notfall Playbook stellt die Installation von Nextcloud innerhalb von wenigen Minuten wieder her. Was es allerdings nicht kann, ist die verwalteten Daten wiederherzustellen. Dafür braucht es einen separaten Mechanismus.
Das Playbook ist speziell für mein persönliches Setup angepasst. Ich habe mich aber bemüht, es so weit konfigurierbar zu machen, dass du es für deinen eigenen Nextcloud Server verwenden kann.
Das gesamte Playbook mit allen Dateien habe ich im git Repository abgelegt.