Eine private Cloud
Einleitung
Ich habe mir in den letzten Monaten viele Gedanken zum Thema Datensouveränität, Datenhoheit bzw. Data Sovereignty gemacht. Der Grund hierfür waren einige Veränderungen in meinem privaten Umfeld, woraus sich der Wunsch ergeben hat, in Zukunft (noch) sorgfältiger mit den eigenen Daten umzugehen und besser kontrollieren zu können, wo diese gehostet sind und wer (potentiell) darauf Zugriff hat. Aufgrund dessen bin ich zum Entschluss gekommen, mein über viele Jahre bestehendes iCloud Abo bei Apple (vorher habe ich Google Drive genutzt) zu kündigen und meine Daten (und die meiner Familie) künftig selbst zu hosten.
Bestandsaufnahme
Um zu verstehen was ich alles umsetzen muss, um dem Ideal einer eigenen Cloud am nächsten zu kommen, habe ich mir zunächst iCloud nochmal angeschaut. Ziel war es zu sehen, was es alles bietet (und was davon ich überhaupt nutze). Sozusagen eine erste Bestandsaufnahme.
iCloud beinhaltet folgende Applikationen:
- Contacts
- Calendar
- Photos
- Drive
- Notes
- Reminders
- Pages
- Numbers
- Keynote
- Find my
Einen eigenen Mailserver zu hosten halte ich für unsinnig und nutze stattdessen seit einigen Jahren Proton Mail aus der Schweiz, einen Anbieter mit sehr starkem Fokus auf der Privatsphäre der Nutzer. Der Dienst beinhaltet auch eine Kontaktverwaltung und einen Kalender (im Paket Mail Plus). Es gäbe bei Proton zwar auch das Unlimited Paket welches zusätzlich noch Drive (ein Cloud Speicher), VPN (selbsterklärend) sowie Pass (eine Passwortverwaltung) enthält, aber da ich die Cloud ja selber hosten möchte, beim VPN auf Mullvad vertraue und auch meine Passwortverwaltung selbst hosten möchte benötige ich diese zusätzlichen Dienste nicht. Mail, Contacts und Calendar habe ich somit bereits abgedeckt.
Als nächstes schauen wir uns die beiden (aus meiner Sicht) Kerndienste von iCloud an, Photos und Drive. Diese möchte ich auf jeden Fall durch selbstgehostete services ersetzen. Als Alternativen habe ich mir immich (für Photos) und Nextcloud (für Drive) ausgesucht, die ich auch bereits im kleinen Rahmen auf einem meiner Testserver erprobt habe. Nextcloud würde sogar “ab Werk” eine Fotoverwaltung, eine Kontaktverwaltung, einen Kalender, Notizen etc. mitbringen (und ist durch plug-ins erweiterbar), mir gefällt immich von den Funktionen und dem UI (user interface) allerdings besser.
Die weiteren Dienste die ich noch ersetzen möchte sind Notes (mit einer Kombination aus Joplin und Vikunja, welches gleichzeitig Microsoft To Do als Nachfolger von Wunderlist abgelöst hat) und Reminders (ist durch Proton Calendar bereits abgedeckt). Pages, Numbers und Keynote habe ich nie genutzt, da ich sowohl noch eine Microsoft Office Lizenz besitze als auch (immer öfter) LibreOffice verwende. Auf Find my muss (oder kann) ich verzichten.
Zu guter Letzt brauche ich im Gegensatz zu einer kommerziellen Cloud bei einem Anbieter noch ein paar Verwaltungs- und Synchronisationsdienste sowie einige Anwendungen zum Aufsetzen des Systems und für eine sichere Verbindung. Diese sollten möglichst leicht zu bedienen und für meine Nutzer unsichtbar sein.
Der Plan
Ich plane die Umsetzung mithilfe eines Verbundes von drei Raspberry Pi’s und externen SSDs anzugehen. Einer der Raspis steht bei mir zuhause, die anderen beiden jeweils an zwei weiteren, sicheren Orten außerhalb meiner Wohnung. Alle drei Geräte sind mittels eines WireGuard VPN verbunden und somit nicht direkt im Internet exposed.
Vorteil ist, dass ich mir um die Sicherheit meines Netzwerks, meiner Daten und meiner Dienste keine allzu großen Sorgen machen muss. Nachteil ist, dass sowohl ich als auch meine Familie (außerhalb meines privaten Heimnetzes) immer per VPN mit meinem Heimnetz verbunden sein müssen, um Zugriff zu haben. Dies ist grundsätzlich kein Problem und kann auch für technisch weniger versierte Nutzer beispielsweise über Automatismen (iOS) oder “always on” (Android) gelöst werden.
Alle von mir genutzten Projekte sind FOSS (free and open source software) und bieten sowohl Desktop Clients für Linux, MacOS und Windows (oder Webanwendungen) als auch Apps für iOS und Android an. Teilweise sind kleinere Einstellungen auf den Endgeräten vorzunehmen um die gleiche Nutzererfahrung wie beispielsweise Apple oder Google Photos zu haben (beispielsweise automatische Uploads aller gemachten Fotos in den eigenen immich account in der Cloud), grundsätzlich ist die Einrichtung aber überall sehr simpel.
Der finanzielle Aspekt
Auch unter finanziellen Gesichtspunkten kann (!) sich das selber hosten lohnen, allerdings sollte man es eher aus ideellen Gründen in Betracht ziehen.
Die benötigte Hardware für mein Projekt ist folgende:
- 3x Raspberry Pi 5 (4b RAM Version): ca. 70,00 Euro (210,00 Euro für alle drei)
- 3x Raspberry Pi Case (Raspberry Pi 5 Version): ca. 17,00 Euro (45,00 Euro für alle drei)
- 3x Samsung T9 Portable SSD 4TB: ca. 350,00 Euro (1.050,00 Euro für alle drei)
- 3x SanDisk Extreme 64 GB micro SD Karte: ca. 9,00 Euro (27,00 Euro für alle drei)
- 5er Pack Amazon Basics Ethernet Kabel 30 cm: ca. 15,00 Euro (also 9,00 Euro für drei, gibt es aber nur im fünfer Pack)
Insgesamt kostet die Hardware also ca. 1.340,00 Euro. Nicht gerade wenig, aber immerhin ist die komplette Software umsonst (die Ersteller freuen sich aber über Spenden!). Der Aufkleber ist übrigens von der Free Software Foundation Europe (fsfe) und verdeutlicht den Grundgedanken hinter meinem Projekt ganz gut.
Demgegenüber stehen meine bisherigen Kosten für den 2 TB im Monat Plan von iCloud+ (teilbar mit maximal fünf Personen) in Höhe von 10,00 Euro im Monat, also 120,00 Euro im Jahr. Wenn ich einen (fiktiven) 4 TB für 20,00 Euro im Monat Plan hochrechne müsste ich meine eigene Cloud also über 5 Jahre nutzen, um (ohne Inflation) rein von den Hardwarekosten (ohne Strom) günstiger zu sein. Naja. Das ist wohl der Preis der Datensouveränität.
Mögliche Schwachpunkte und Verbesserungspotential
Wenn man sich meinen Plan so durchliest könnte man argumentieren, dass “das ja gar keine richtige Cloud ist”, weil es keine high availability gibt (d.h. wenn der cloud-master ausfällt, übernimmt keiner der cloud-backups automatisch und die services sind nicht mehr erreichbar). Im Grunde handelt es sich nur um ein etwas komplexeres Setup aus einem kleinen homelab und einer externen backup Lösung. Das ist richtig.
Ich habe bereits weitere Überlegungen angestellt, die in Richtung Proxmox Cluster (ebenfalls aus drei Rechnern) aus thin clients oder anderen Minicomputern bestehen. Diese sollen nicht mehr über ein WireGuard VPN Netzwerk verbunden, sondern regulär exposed werden. Bei diesem high availability cluster wäre es dann tatsächlich so, dass die Dienste zum einen “einfach so” aus dem Internet erreichbar sind und zum anderen redundant ausgeführt, falls einer der drei Rechner ausfällt. Hierzu muss ich mir allerdings vor allem im Bereich (Zugriffs-) Sicherheit noch ein paar Gedanken machen bevor ich den Plan umsetzen kann. Bis dahin ist die aktuelle Cloud “good enough”.
Die Umsetzung der eigenen Cloud
Nachdem ich nun das warum erklärt habe geht es ab sofort um das wie. Ich werde Schritt für Schritt im Detail auflisten wie ich mein Setup aufgesetzt habe. Basis des Ganzen ist Docker. Um zu zeigen wie man Container aufsetzt werde ich verschiedene Wege aufzeigen. Wer bereits weiß wie das geht und seinen präferierten Weg gefunden hat (meiner sind docker compose files) kann diese Abschnitte natürlich überspringen. Ich habe versucht die einzelnen Kommandos so gut wie möglich zu erklären und zu trennen. Einfache oder sich häufig wiederholende Kommandos werde ich versuchen nicht erneut zu erklären.
Hardware zusammenbauen
Im ersten Schritt wird die Hardware zusammen gebaut. Das ist relativ einfach und selbsterklärend, nur beim Kabel für den beim Raspberry 5 neuen und im offiziellen Gehäuse bereits integrierten Lüfter muss man ein bisschen aufpassen. Die Micro SD Karte wird noch nicht eingesteckt, da wir sie erst beschreiben müssen. Die folgenden Bilder illustrieren den Zusammenbau.
Micro SD Karte vorbereiten
Um die zukünftigen Cloud Rechner in Betrieb nehmen zu können, brauchen wir zunächst ein funktionierendes Betriebssystem (Operating System /OS). Hier habe ich mich für den vermeintlich leichtesten Weg entschieden und einfach Raspberry Pi OS (vormals Raspbian) entschieden. Andere aus meiner Sicht für das Projekt auch gut geeignete OS wären Ubuntu Server 24.04 LTS für den Raspberry Pi oder Debian für Raspberry Pi. Die Kommandos sollten sich übertragen lassen.
Zum flashen von .iso Dateien nehme ich entweder den Raspberry Pi Imager oder Balena Etcher(beides gibt es für Linux, MacOS und Windows). Auf Windows gibt es noch das beliebte Rufus, habe ich persönlich aber noch nie verwendet. Jetzt stecken wir die erste der drei Micro SD Karten in unseren Rechner.
Im Raspberry Pi Imager gehen wir auf Raspberry Pi Device und wählen den Raspberry Pi 5 aus. Bei Operating System wählen wir Raspberry Pi OS (other) und dann Raspberry Pi OS Lite (64-bit). Lite habe ich gewählt weil alle drei Rechner sowieso headless (also ohne angeschlossenen Bildschirm und somit auch ohne benötigte Desktop Umgebung laufen werden) laufen werden und der Zugriff rein über SSH (Secure Shell Protocol) laufen wird. Unter Storage wählen wir die Micro SD Karte aus und klicken auf “Next”.
Unter OS customization gehen wir auf “Edit settings” und ändern unter General den hostname, den username und das password und wählen unter locale etwas passendes aus, in meinem Fall Europe/Berlin. Auch das eigene keyboard sollte man bereits auswählen (vermutlich de, ich selbst nutzte us aufgrund der Lage der Sonderzeichen). Unter Services ist es wichtig den Haken bei “enable SSH” zu setzen und eine Authentifizierungsmethode zu wählen. Für mein Projekt wähle ich “use password”, sicherer (vor allem wenn es public exposed wird wäre aber ein key). Unter Options wählen wir eject media when finished, klicken “yes” bei OS customization und bestätigen nochmal mit “yes” das der gesamte Inhalt der ausgewählten Micro SD Karte gelöscht werden wird (sie ist in meinem Fall allerdings sowieso noch leer) und bestätigen den Vorgang mit unserem Passwort. Nach einer kurzen Wartezeit ist die Karte fertig beschrieben und wird automatisch ausgeworfen. Jetzt entfernen wir sie und wiederholen das Ganze noch zwei Mal für die beiden backup Server (wichtig: andere Passwörter wählen!).
SSD vorbereiten
Im nächsten Schritt werden die drei SSD vorbereitet, die später im Betrieb alle Inhalte unserer Cloud aufnehmen werden. Ich habe mich aufgrund der Größe, der Geschwindigkeit und der Lautstärke für SSD und gehen HDD entschieden, da ich die beiden backup Server ja “offsite” bei Familienmitgliedern lagern werde und sie dort möglichst wenig Platz wegnehmen und auf keinen Fall “Schreibgeräusche” von sich geben sollen. Das Einzige was man vor Ort (und auch nur selten) hören wird ist der neue Lüfter beim Pi 5. Zur Vorbereitung schließen wir die erste SSD an unseren Rechner an.
Unter Linux gehen wir wie folgt vor (bei anderen OS kann ich hier leider nichts sagen):
- Mit
df
zeigen wir alle Laufwerke an um den Dateipfad zu finden (für uns relevant (kann abweichen!): /dev/sda) sudo mkfs.ext4 /dev/sda
formatiert die SSD mit dem Linux (de facto) Standarddateisystem EXT4. Da der Befehl als super user ausgeführt wird bestätigen wir mit einem Klick auf “y”.- Nach dem formatieren mounten wir die SSD erneut und kopieren den Dateipfad zur gemounteten Platte (in meinem Fall /run/media/username).
ls -l /run/media/username
(Pfad zur eigenen Festplatte selbst einfügen) zeigt die aktuellen Rechte ansudo chmod -R -v 777 /run/media/username
ändert die Rechte so, dass jeder Nutzer lesen und schreiben darf (wird später wichtig)- Jetzt die Platte auswerfen und neu mounten, um zu sehen ob es geklappt hat
- Am Ende legen wir auf der Platte mit
mkdir cloud
(wahlweise auch ein anderer Name) noch einen Ordner an, der später alle Inhalte enthalten wird. Sieht finde ich einfach aufgeräumter aus, - Das Ganze wiederholen wir jetzt noch zwei Mal für die restlichen beiden SSDs.
Achtung: es findet keine Verschlüsselung der Festplatten statt, d.h. diese können später einfach abgezogen und ausgelesen werden. Wer möchte kann dies natürlich trotzdem tun, das ist aber außerhalb des Umfangs dieses Artikels.
Raspis einrichten
Jetzt richten wir die drei Raspberry Pi Rechner ein und bereiten sie für die Installation von Docker vor. Die Schritte Raspis einrichten, Docker installieren und Portainer installieren müssen auf allen Geräten durchgeführt werden, Portainer Agent installieren nur auf den cloud-backups. Später ist es dann teils, teils. Ich werde es bei allen Schritten aber auch nochmals dazu schreiben.
Hierzu benötigen wir die jeweiligen IP Adressen. Diese kann man einfach aus den DHCP Leases des eigenen Routers auslesen, unter OPNsense etwa bei Services -> ISC DHCPv4 -> Leases. In der Tabelle werden sie als jüngste Geräte meistens ganz unten stehen oder am Beginn des Teils der IP Adressraums, der dynamisch vergeben wird.
Zur Einrichtung der Raspis gehen wir wie folgt vor:
- Wir verbinden uns mit
ssh username@192.168.1.41
per SSH mit dem Rechner und nutzen hierbei den Benutzernamen, den wir beim Beschreiben der Micro SD Karten festgelegt haben und die IP des jeweiligen Gerätes. - Da wir uns zum allerersten Mal mit diesem Server verbinden bestätigen wir dessen Identität durch die Eingabe von
yes
- Jetzt geben wir das zuvor vergebene Passwort ein, klicken auf “Enter” und schon sind wir auf dem System aufgeschaltet
- Zuallererst aktualisieren wir die Repositories mit
sudo apt update
und bringen danach mitsudo apt upgrade
das komplette System auf den neusten Stand - Jetzt verbinden wir eine der SSDs mit dem Raspi und lesen deren UUID (Universally Unique Identifier) mit
blkid
aus. Diese UUID brauchen wir um sicherstellen zu können, dass diese verbundene externe Festplatte immer automatisch gemountet wird, also auch bei einem Systemneustart etwa nach einem Crash oder Update. Da zwei Geräte ja offsite platziert werden ist ein einfacher Zugriff später nicht mehr so leicht möglich. - Mit
sudo nano /etc/fstab
bearbeiten wir die fstab Datei des Systems und fügen die ZeileUUID=xxx-xxx-xxx-xxx-xxx /mnt/usb ext4 defaults 0 0
ein, wobei wir hier bei UUID die vorher ausgelesene Nummer eintragen. - Jetzt sollte die SSD bei einem Neustart automatisch gemounted werde. Im Notfall kann dies aber auch mit dem Befehl
mount -a
manuell erfolgen (es ist ja eh nur ein Gerät eingesteckt). - Den Pfad zur SSD finden wir wieder mit
df
und merken ihn uns für später. - Jetzt wechseln wir mit
cd
ins eigene home Verzeichnis und legen mitmkdir docker
einen Ordner für Docker und die diversen weiteren Container an.
Docker installieren (alle Geräte)
Docker ist eine open source Software, die zum deployment und zur Steuerung von containerisierten Applikationen eingesetzt wird. Im Prinzip starten und steuern wir hiermit (über die Kommandozeile) viele kleine mini Linux Einheiten (meist mit Alpine Linux), die jeweils nur eine Applikation bereit stellen.
Wir richten Docker wie folgt ein:
- Mit
cd docker
wechseln wir in den soeben erstellten Ordner curl -fsSL https://get.Docker.com -o get-Docker.sh
besorgt uns das offizielle Docker Installationsskriptsudo sh get-Docker.sh
führt es aus (Achtung: grundsätzlich sollte man nicht einfach irgendwelche Skripte irgendwo aus dem Internet mit super Rechten ausführen, daher findet sich hier nochmal der offizielle Link um das Skript zu verifizieren)- Als Nächstes fügen wir mit
sudo usermod -aG docker $USER
den Benutzer zur docker Gruppe hinzu - Mit
newgrp docker
loggen wir uns in diese docker Gruppe ein - Als letztes deployen wir mit
docker run hello-world
unseren ersten Testcontainer um die Docker Installation abzuschließen.
Portainer installieren (alle Geräte)
Das von uns soeben installierte Docker läuft rein über die Kommandozeile. Es gibt zwar eine Docker Desktop Applikation, aber wir nutzen zur grafischen Verwaltung unserer Container einen weiteren Container, nämlich die Docker Verwaltungssoftware Portainer. Diese ist nach der Einrichtung bequem über den Browser erreichbar und ermöglicht uns eine einfache und schnelle Übersicht über unsere diversen container. Am Ende dieser Anleitung werden es übrigens mindestens 21 Container sein, verteilt auf drei Server.
Die Schritte im Detail:
- Ein volume für Portainer erstellen mit
docker volume create portainer_data
- Portainer deployen mit
docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest
- Portainer startet jetzt automatisch und kann im Browser unter https://192.168.1.41:9443 (IP anpassen) aufgerufen werden
- Beim ersten Aufrufen der Seite müssen wir das Sicherheitsrisiko akzeptieren (gilt für alle neuen Dienste und kann zum Beispiel durch die Einrichtung eines reverse proxy wie beispielsweise NPM mit let’s encrypt Zertifikaten “umgangen” werden. Hierzu schreibe ich vielleicht nochmal einen extra Artikel.)
- Passwort vergeben
- “Get started” anklicken
- Lokale Umgebung (Environments -> local) auswählen und umbenennen (cloud-master und cloud-backup-1 bzw. cloud-backup-2)
- “Containers” auswählen
- Den im letzten Abschnitt frisch erstellten “Hallo Welt” Container löschen (es ist der “nicht-Portainer” Container mit dem zufällig vergebenen Namen)
Portainer Agent installieren (nur auf den cloud-backups)
Um nicht jedes Mal für jeden der drei Server Portainer aufrufen zu müssen um die Container zu überprüfen setzen wir auf den beiden backup Servern noch Portainer Agent auf. Nach dem Installieren erlaubt uns Portainer Agent die beiden backup Server mit dem Hauptserver zu verbinden und deren Container in der Portainer Instanz des Hauptservers zu verwalten.
Zur Einrichtung brauchen wir die folgenden Schritte:
- Zur Installation auf den beiden cloud-backups
docker run -d -p 9001:9001 --name portainer_agent --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/docker/volumes:/var/lib/docker/volumes portainer/agent:latest
ausführen - Jetzt auf cloud-master auf “Environments” in der Liste links gehen und “Connect to existing environments” oder links in der Leiste “Environments” -> “+ Add environment” -> “Docker Standalone” auswählen
- “Start Wizard” anklicken
- Name (cloud-backup-1) und IP (inklusive Port, also z.B.: 192.168.1.42:9001) eingeben
- “Connect” klicken
- Zurück auf die Home Seite gehen und die Browsertabs von cloud-backup-1 und cloud-backup-2 schließen, da diese nicht länger benötigt werden. Alle drei Environments sollten nun auf der Weboberfläche von cloud-master zu sehen sein.
Achtung: sobald WireGuard eingerichtet wurde (s.u.) müssen die IPs von den derzeitigen lokalen Adressen auf die in WireGuard ausgewählten IPs geändert werden (kleines Stiftsymbol rechts), damit auch noch auf die beiden Portainer Instanzen zugegriffen werden kann wenn sich diese an ihren (remote) Bestimmungsorten befinden.
MariaDB (nur auf cloud-master)
Als Nächstes geht es um die Einrichtung einer Datenbank, die die Informationen für unsere Cloud Applikation Nextcloud beinhalten wird. Die Installation erfolgt beispielhaft grafisch über Portainer (einfach aber relativ aufwendig).
Hier die Anleitung:
- In Portainer “cloud-master” environment auswählen
- Add container anklicken, als Name
MariaDB
und als Imagelinuxserver/mariadb:latest
angeben - Unter Manual network port publishing -> “+ publish a new network port” anklicken und
host publish 3306 container 3306
ausfüllen - Unter “Advanced container settings” unten unter Volumes -> Volume mapping -> + map additional volume anklicken und den Kippschalter auf “Bind’ setzen. Unter
container /config
und unterhost /home/pflavio/docker/mariadb/config
(den Pfad in den Docker Ordner) angeben - Unter Env -> “+ Add an environment variable” (7x anklicken) und wie folgt befüllen
1 2 3 4 5 6 7
- PUID 1000 - PGID 1000 - TZ Europe/Berlin (passende auswählen) - MYSQL_ROOT_PASSWORD passwort1234 (ändern) - MYSQL_DATABASE nextclouddb - MYSQL_USER dbuser - MYSQL_PASSWORD passwort1234 (ändern)
- Als Restart Policy “unless stopped” auswählen und “Deploy the container” anklicken
Nextcloud (nur auf cloud-master)
Jetzt setzen wir Nextcloud auf. Nextcloud ist eine open source cloud sofware die man selber hosten kann. Dadurch dass alle Daten nur auf unserem eigen Server liegen haben wir die Kontrolle darüber, wer wann wie Zugriff erhält.
Wir machen das nochmal über die Portainer Web Oberfläche:
- “Add container” anklicken und als Namen
Nextcloud
vergeben und bei Imagelinuxserver/nextcloud:latest
angebenn - Unter “Manual network port publishing” “+ publish a new network port” anklicken und
host publish 443 container 443
angeben - Unter “Advanced container settings” unten unter “Volumes” und “Volume mapping” 2x den Punkt “+ map additional volume” anklicken und den Kippschalter wieder jeweils auf “Bind” setzen. Die beiden Volumes wie folgt befüllen:
container /config -> host /home/pflavio/docker/nextcloud/config
(der Pfad in den Docker Ordner)
undcontainer /data -> host /mnt/usb/cloud-master/nextcloud
(der Pfad auf die externe USB SSD) - Unter “Env” 3x “+ Add an environment variable” anklicken und folgendes eintragen
1 2 3
- PUID 1000 - PGID 1000 - TZ Europe/Berlin (passende auswählen)
- Als “Restart Policy” wieder “unless stopped” wählen und “Deploy the container” anklicken
Nextcloud ist ab sofort unter https://192.168.1.41:443 erreichbar (bzw. unter der eigenen IP Adresse). Beim ersten Start muss man einen Nutzernamen und ein Passwort für den Admin Nutzer vergeben. Best practice ist hier einen extra Admin Nutzer aufzusetzen und für sich selbt (im “Normalbetrieb”) nochmal einen separaten Nutzer ohne Adminprivilegien.
Als Nächstes wird die Datenbank konfiguriert:
- MySQL/MariaDB auswählen
- Den Nutzernamen, das Passwort und die Datenbank vom mariadb container wählen (aus Schritt 5)
localhost
in die IP von cloud-master ändern- “Weiter” klicken und die “Recommended apps” überspringen (Apps können wenn gewünscht nachträglich noch hinzugefügt werden)
- Im letzten Schritt werden alle weiteren, “normalen” (nicht Admin) Nutzer angelegt
Bestehende Dateien hochladen
Bestehende Dateien werden bei Nextcloud am besten direkt über das Web Interface hochgeladen. Dies geht relativ schnell und problemlos. Den upload über das Terminal würde ich nur fortgeschrittenen Nutzern empfehlen, da danach die Datenbank neu indexiert werden muss.
Update 22.05.2024
Wer trotzdem Dateien manuell auf die eigene Nextcloud Instanz schieben möchte geht wie folgt vor:
- Verzeichnis auf lokalem Rechner inklusive aller enthaltenen Dateien und Verzeichnisse auf den Cloud Raspi in den Nextcloud Ordner des gewünschten Nutzers auf der externen SSD kopieren
scp -r /Pfad/auf/das/gewünschte/lokale/Verzeichnis nextclouduser@192.168.1.41:/mnt/usb/cloud-master/nextcloud/nextclouduser/files
- Auf dem Cloud Raspi (nicht auf dem lokalen Rechner von dem die Dateien kamen, also vorher per SSH aufschalten) eine Docker shell für den Nextcloud container öffnen
docker exec -it Nextcloud bash
- Innerhalb der Nextcloud shell zum Zielordner navigieren
cd /data/nextclouduser/files
- Frisch kopierte Daten neu indexieren
occ files:scan --path=nextclouduser/files
- Die neu hochgeladenen Dateien sind nun auch im Webinterface von Nextcloud ganz normal verfügbar
immich (nur auf cloud-master)
immich ist eine selbst gehostete Foto- und Videomanagementsoftware, ähnlich Apple Photos. Dieser Container ist einfacher ohne Portainer mit Docker Compose zu erstellen, was auch die vom Projekt (und von mir persönlich) bevorzugte Variante ist.
Wir gehen wie folgt vor:
- Im Terminal wechseln wir mit
cd ~/docker
in den Docker Ordner - Mit
mkdir immich-app
erstellen wir einen Ordner für immich - Wir wechseln in den neuen Ordner mit
cd immich-app
- Das offizielle Docker compose file laden wir mit
wget -O docker-compose.yml https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
- Zusätlich brauchen wir die .env Beispieldatei. Diese laden wir mit
wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env
. Achtung: sie ist wahrscheinlich unsichtbar und daher perls
nicht anzeigbar. Um sicherzustellen dass sie heruntergeladen wurde am besten mitls -a
alle Dateien anzeigen lassen. - Die .env Beispieldatei müssen wir noch an unsere Bedürfnisse anpassen und ändern sie mit
nano .env
. Dann ändern wir dieUPLOAD_LOCATION
auf/mnt/usb/cloud-master/immich
(der Pfad auf die externe USB SSD) und dasDB_PASSWORD
ändern wir auf ein sicheres Passwort. - Den Container starten wir mit dem Befehl
docker compose up -d
immich ist jetzt unter https://192.168.1.41:2283 erreichbar (bzw. unter der eigenen IP Adresse). In der Portainer Web GUI sollten jetzt auch fünf neue Container sichtbar sein. Wir klicken unter der immich IP “Getting started” an und nehmen die Ersteinrichtung vor. Zuerst legen wir wieder einen separaten Admin user an und dann die weiteren Benutzer (analog zur Einrichtung von Nextcloud).
Bestehende Fotos hochladen
Da der web upload in immich bei großen Mengen an Fotos nicht ganz so gut funktioniert wie Dateien in Nextcloud, würde ich hier zum “kleinen Helfer” immich-go greifen.
Die folgenden Schritte werden auf dem eigenen Rechner (mit Zugriff auf die hochzuladenden Fotos) ausgeführt, nicht auf den neuen Cloud Pis.
- immich-go herunterladen.
- Mit
cd ~/Downloads
zum downloads Ordner wechseln - immich-go entpacken, ausführbar machen und in den gleichen Ordner kopieren in dem sich die bestehende Foto-Bibliothek befindet.
- In diesen Ordner wechseln und folgendes Kommando ausführen:
./immich-go -server=http://192.168.1.41:2283 -key=eigenerapikey upload /run/media/pflavio/T9/cloud/immich/library/philip
. Der Befehlt sagt immich-go welchen Ordner mit Fotos er wohin kopieren soll und authentifiziert sich dabei mit einem API-key. Im Befehlt angepasst werden müssen die IP des eigenen Server, der eigene API key sowie der gewünschte Zielpfad. Der Vorgang kann für jeden Nutzer erneut durchgeführt werden (mit entsprechenden individuellen Anpassungen) um alle bestehenden Fotos zum Beispiel aus iCloud umzuziehen. Den eigenen API-key findet man übrigens unter dem eigenen Benutzer und dann “API Keys” und ein Klick auf “New API Key”.
Joplin (nur auf cloud-master)
Joplin ist eine Notizbuchapp ähnlich OneNote oder Evernote. Wir nutzen diesmal ein docker compose file. Joplin bräuchte für die reine Syncronisierung gar keine eigene App, man könnte auch einfach unsere schon bestehende Nextcloud Instanz einbinden. Joplin Server hat allerdings den Vorteil, dass dann auch Inhalte und Notizbücher geteilt werden können.
Die Einrichtung läuft wie folgt ab:
- Wir wechseln in den Docker Ordner, legen einen neuen Ordner für Joplin an und wechseln in diesen Ordner mit
cd ~/docker && mkdir joplin && cd joplin
- Wir erstellen eine docker-compose.yml Datei mit
nano docker-compose.yml
mit folgendem Inhalt:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
joplin-server:
image: etechonomy/joplin-server:latest
container_name: joplin-server
environment:
- APP_BASE_URL=http://192.168.1.41:22300
- APP_PORT=22300
- DB_CLIENT=pg
- POSTGRES_PASSWORD=bitteaendern
- POSTGRES_DATABASE=joplin
- POSTGRES_USER=joplin
- POSTGRES_PORT=5432
- POSTGRES_HOST=joplin-db
restart: unless-stopped
ports:
- 22300:22300
joplin-db:
image: postgres:16
container_name: joplin-db
restart: unless-stopped
ports:
- 5432:5432
volumes:
- /mnt/usb/cloud-master/joplin/joplin-data:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=bitteaendern
- POSTGRES_USER=joplin
- POSTGRES_DB=joplin
Alle Werte bei denen bitteaendern
steht bitte anpassen. Achtung: bei - APP_BASE_URL
muss die IP des Servers inkl. Port 22300 und voranstehendem http:// stehen, sonst ist ein login isn web interface später nicht möglich!
- Den Container starten wir mit dem Befehl
docker compose up -d
- Das interface ist jetzt unter http://192.168.1.41:22300 erreichbar. Die Standardemail ist admin@localhost und das Standardpasswort admin. Beides bitte ändern.
- Zur Nutzung von Joplin braucht man nun noch einen (oder mehrere, wird ja synchronisiert) Client Apps
Zwischenfazit
Die Einrichtung der Apps, die man normalerweise als Nutzer bei Apple oder Google verwendet ist nun abgeschlossen. Da wir uns aber auch um die Verwaltung und die Vernetzung des Servers kümmern müssen, brauchen wir zusätzlich zu Docker und Portainer noch einige weitere Tools. Diese richten wir im Folgenden ein.
Syncthing
Um Redundanzen zu schaffen und ein ständiges, automatisiertes Backup aller unser Daten zu erhalten verwenden wir Syncthing. In Syncthing wählt man vereinfacht gesagt einen Ordner aus, der auf allen Instanzen vorhanden ist und konstant überall auf dem gleichen Stand gehalten wird. Das machen wir uns zunutze für den Ordner /mnt/usb/cloud-master
, also der Ort an dem wir alle unsere Inhalte abgelegt haben.
Zur Einrichtung nutzen wir wieder die Portainer GUI (da wir mittlerweile so ziemlich alle Wege durch haben um Docker Container einzurichten kann natürlich auch ein anderer Weg gewählt werden) und führen folgende Schritte aus:
- “Add container” anklicken, als Name
syncthing
und als Imagelinuxserver/syncthing:latest
wählen - Unter “Manual network port publishing” 4x “+ publish a new network port” anklicken und folgendes eintragen:
host publish 8384 container 8384 host publish 22000 container 22000/tcp host publish 22000 container 22000/udp host publish 21027 container 21027/udp
- Unter “Advanced container settings” unten unter “Volumes”, “Volume mapping” 2x “+ map additional volume anklicken und die Kippschalter auf “Bind” setzen. Befüllen werden wir die volumes wie folgt:
container /config -> host /home/pflavio/docker/syncthing/config
(der Pfad in den Docker Ordner) undcontainer /data -> host /mnt/usb/cloud-master
(der Pfad auf die externe USB SSD) - Unter “Env” klicken wir 3x auf “+ Add an environment variable” und tragen ein:
PUID 1000 PGID 1000 TZ Europe/Berlin (passende auswählen)
- Die Restart Policy ist wie immer “unless stopped” und mit einem Klick auf “Deploy the container” starten wir Syncthing.
Syncthing ist jetzt unter https://192.168.1.41:8384 (bzw. der gewählten IP Adresse) erreichbar. Wichtig ist jetzt, unbedingt einen Nutzernamen und ein Passwort zu vergeben und den Standard Ordner Pfad zu ändern, damit Syncthing für unseren use case in der Einleitung funktioniert.
Hierzu entfernen wir zuerst den default folder. Dazu klicken wir auf “Folders”, dann “Default Folder”, dann “edit” und dann “remove”. Wir brauchen ihn nicht, da dieser Ordner auf unseren Raspis jeweils bei den Syncthing config Dateien im Docker Ordner auf dem home Verzeichnis liegt. Synchronisieren wollen wir aber die Daten auf der externen Festplatte, also die in Schritt 3. unter dem container volume /data abgelegt sind.
Um diesen Pfad korrekt zu hinterlegen klicken wir oben rechts auf “actions”, “settings”, “Default Configuration” und dann “Edit Folder Defaults” und geben jetzt als Folder Path /data
an. Dann hinterlegen wir den Ordner durch klicken auf “Folders” und “Add Folder”. Die Felder befüllen wir wie folgt:
1
2
3
Folder Label cloud-master
Folder ID cloud-master
Folder path /data
Um später Fehler mit dem filesystem watcher zu vermeiden führen wir jetzt auf der Kommandozeile folgenden Befehl aus: echo "fs.inotify.max_user_watches=204800" | sudo tee -a /etc/sysctl.conf
Dieser erhöht die maximale Anzahl der auf 204.800 und verhindert, dass Syncthing einen entsprechenden Fehler ausgibt. Danach starten wir den Rechner mit sudo reboot
neu. Alternativ ist auch der Befehl echo 204800 | sudo tee /proc/sys/fs/inotify/max_user_watches
möglich, hier ist kein direkter Neustart notwendig.
Syncthing überwacht nun permanent das Verzeichnis /cloud-master
auf Änderungen und synchronisiert diese mit… aktuell noch niemandem, da wir die beiden anderen Raspis noch nicht eingebunden haben. Das erledigen wir jetzt:
- Klick auf “add remote device”
- Gib jeweils die volle ID der beiden anderen Raspis an
- Nur auf cloud-master: wähle den Ordner aus
- Klicke auf “sharing”
- Wähle beide backup Raspis aus
Das automatisierte backup auf der eigenen Cloud funktioniert jetzt. Durch die Internetmagie von Syncthing (und die IDs) finden sich die drei Rechner jetzt und synchronisieren sich. Hierzu ist nicht mal ein VPN nötig!
WireGuard (nur auf den cloud-backups)
Obowhl nur für Syncthing der nächste Schritt nicht notwendig wäre, werden wir im nächsten Schritt trotzem einen privaten VPN über das sehr leichtgewichtige WireGuard Protokoll einrichten. Das VPN dient zum einen der Fernwartung unserer beiden externen Raspis (die wir ja an einem sicheren, externen Ort aufstellen werden), zum anderen erlaubt es uns in Zukunft auf Wunsch etwa weitere tools oder container zu installieren ohne vor Ort sein zu müssen. Ich habe bereits einen WireGuard Server auf meinem OPNsense Router laufen, daher muss ich nur die beiden cloud-backup Geräte als clients einrichten (das Hauptgerät cloud-master bleibt ja bei mir im Heimnetz und benötigt somit keine WireGuard Anwendung). Falls noch kein WireGuard Server besteht und dieser unbedingt auf dem cloud-master Gerät laufen soll, ist die Einrichtung eines Servers zum Beispiel über den WireGuard Docker Container von linuxserver.io möglich.
Nur für das einrichten der beiden clients gehen wir folgt vor:
- Im home Ordner (nicht in /home/pflavio/docker) einen Ordner für WireGuard anlegen mit
mkdir wireguard
- WireGuard installieren mit
sudo apt install wireguard
- private key erstellen mit
wg genkey > cloud-backup-1_private.key
und notieren - public key erstellen mit
wg pubkey < cloud-backup-1_private.key > cloud-backup-1_public.key
und notieren - config file erstellen mit
sudo nano /etc/wireguard/wg0.conf
und mit folgendem Inhalt befüllen:
1
2
3
4
5
6
7
8
9
[Interface]
PrivateKey = EintragausSchritt3.
Address = 192.168.66.10/32
DNS = 192.168.1.1
[Peer]
PublicKey = EintragvomServer
AllowedIPs = 0.0.0.0/0
Endpoint = öffentlicheIPoderDynDNS:51820
Die IP Adresse muss einmalig sein und aus dem im Server definierten Addressraum stammen. DNS ist optional, allerdings habe ich mein eigenes Pi-hole und nutze dies dank WireGuard auch für meine diversen externen und mobilen Geräte.
- Die beiden public keys der clients müssen jetzt noch im Server als Peers hinterlegt werden (analog zum Server als Peer in Schritt 5.)
- WireGuard starten mit
wg-quick up wg0
- WireGuard ist jetzt aktiv (überprüfen kann man dies zum Beispiel anhand des letzten handshakes oder des Durchsatzes im Server)
- Um WireGuard bei jedem booten zu starten führen wir noch
sudo systemctl enable wg-quick@wg0
aus
Jetzt könnten die beiden backup Geräte bereits “ausgewildert” und an ihren späteren Bestimmgsort verbracht werden.
homepage (nur auf cloud-master)
Nachdem die Pflicht nun erfüllt ist, folgt die Kür. Als kleinen Bonus und um eine ähnliche UI/UX wie etwa iCloud Web zu erhalten richten wir noch ein kleines Dashboard ein, über dessen GUI wir mit einem Klick in die diversen Apps abspringen können.
Die Einrichtung ist simpel:
- Wir wechseln wieder per
cd ~/Docker
in den Docker Ordner - Im Docker Ordner legen wir mit
mkdir homepage
einen Ordner für homepage an - Wir erstellen eine docker-compose.yml Datei mit
nano docker-compose.yml
mit folgendem Inhalt:
1
2
3
4
5
6
7
8
services:
homepage:
image: ghcr.io/gethomepage/homepage:latest
container_name: homepage
ports:
- 3000:3000
volumes:
- /home/pflavio/docker/homepage/config:/app/config
- Den Container starten wir mit dem Befehl
docker compose up -d
- Das interface ist jetzt unter http://192.168.1.41:3000 erreichbar. Noch ist es aber komplett leer.
- Zur Nutzung müssen nun die config files von homepage befüllt werden. Als “Starthilfe” habe ich die Datein für das hier gezeigte Dashboard zum Download verlinkt. Sie müssen auf den eigenen Server angepasst (inkl. URL und API keys) in den Ordner
/home/pflavio/docker/homepage/config
kopiert werden (die existierenden Dateien werden ersetzt). Die icons müssen unter/home/pflavio/docker/homepage/icons
abgelegt werden. Danach muss der homepage Container neu gestartet werden (zum Beispiel über Portainer). Das Ergebnis wird in etwa so aussehen:
Paperless-ngx (eine Anwendung zur Digitalisierung von Dokumenten auf Papier) ist in diesem Tutorial nicht enthalten. Eventuell schreibe ich dazu einen weiteren Artikel.
Um es (aus meiner Sicht) perfekt zu machen fehlt nun noch ein reverse proxy, wie etwa Nginx Proxy Manager. Die Services sind zwar nicht exposed, aber wir können diesen trotzdem verwenden um mit Let’s Encrypt SSL Zertifikate zu bekommen und “schöne” domain names. Das ist allerdings außerhalb des Umfangs dieses Artikels.
Finaler Test
Jetzt ist die Stunde der Wahrheit gekommen. Um zu testen ob alles funktioniert, verteilen wir zunächst die beiden externen Raspis. Dann checken wir in Syncthing, ob diese verbunden sind. Alternativ können wir auch schauen, ob die Ping Anzeige auf unserem Dashboard grün ist (=Server ist erreichbar). Zum Testen der Synchronisieerung schieben wir einfach ein paar Dateien auf unsere Nextcloud und schauen, ob Syncthing anfängt zu arbeiten.
Updates
Man sollte seine Systeme und Applikationen stets aktuell halten, um die Sicherheit und korrekte Funktion zu gewährleisten.
Betriebssysteme
Zum updaten der OS gehen wir wie folgt vor:
- Wir verbinden uns mit
ssh username@192.168.1.41
und dem Passwort per SSH mit dem jeweiligen Rechner (Achtung: bei den beiden externen Raspis brauchen wir nun die jeweils in WireGuard spezifizierte IP, nicht die lokale ). - Wir aktualisieren die Repositories mit
sudo apt update
und bringen mitsudo apt upgrade
das komplette System auf den neusten Stand.
Container
Zum updaten der container können wir entweder Portainer nutzen oder Docker compose.
Über Portainer:
- Wir wählen den zu aktualisierenden Container in der Portainer GUI unter “Containers” einzeln aus und stoppen ihn über den Button “stop”
- Wir wählen den zu aktualisierenden Container erneut aus, klicken auf den Namen um in die Ansicht “Container details’ zu kommen und klicken dort oben rechts auf den button “recreate”. Im pop-up Fenster wählen setzen wir den Schalter auf ‘re-pill image” und bestätigen mit “Recreate”.
- Nach einer kurzen Wartezeit (je nach Container Größe) klicken wir auf “Start”.
- Zum Schluss müssen wir den alten Container (erkennbar am Zusatz “-old” am Namen) noch löschen (über den button “remove”)
Über Docker compose:
- Wir ziehen uns die neuesten Versionen der Docker images mit
docker-compose pull
- Nach dem erfolgreichen download starten wir alle Container auf Basis der neuen Images mit
docker-compose up -d
neu und haben so den kompletten Stack auf den neusten Stand gebracht.
Fazit
In diesem blog post habe ich aufgezeigt, warum ich mir Gedanken um eine eigene Cloud gemacht habe und wie diese umgesetzt wurde. Ich habe versucht es möglichst einfach zu halten und im Detail zu erklären. Ich nutze dieses Setup nun seit einigen Wochen und bin bisher sehr zufrieden.
Falls Fragen bestehen schreibt mir gerne eine Email oder schreibt mich bei Mastodon an. Vielen Dank fürs Lesen!