Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Docker 23.10.2026 · 11 min Lesezeit

Yuvomi Familienplaner mit Docker Compose selbst hosten

Diese Anleitung zeigt, wie Sie den Familienplaner Yuvomi 2.79.0 mit Docker Compose betreiben: Geheimnisse und Datenbankschlüssel setzen, ersten Administrator anlegen, Aufgaben und Einkaufslisten per API erfassen, eingebaute Backups nutzen, nach Totalverlust wiederherstellen und von 2.78.0 aktualisieren.

Geprüft am 23.10.2026 · für Yuvomi 2.79.0

WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Titelbild: Yuvomi Familienplaner selbst hosten, mit Karten für Aufgaben, Einkauf und Backup neben einem Laptop mit Planer-Dashboard

Yuvomi ist ein selbst gehosteter Familienplaner: Aufgaben, Kalender, Einkaufslisten, Rezepte, Budget, Dokumente und rund zwanzig weitere Module laufen in einem einzigen Container mit einer SQLite-Datenbank. Das MIT-lizenzierte Projekt hieß bis vor Kurzem Oikos und wird sehr aktiv gepflegt, Version 2.79.0 erschien am 21. Oktober 2026. Diese Anleitung führt durch Installation, Erstkonfiguration, API, Backup, Restore nach Totalverlust und das Update von 2.78.0 auf 2.79.0. Alle Ausgaben stammen aus einem eigenen Testlauf.

Voraussetzungen

  • Linux-Server mit Docker Engine und dem Docker Compose Plugin (Grundlage: Docker Compose unter Linux einrichten), amd64 oder arm64, also auch ein Raspberry Pi 4 oder 5.
  • 1 CPU-Kern und laut Projekt 256 MB RAM für die App; mit Reserve für das System sind 1 bis 2 Kerne und 1 GB RAM angenehm.
  • Rund 1 GB freier Speicher für das Image (etwa 500 MB) plus Platz für Datenbank, Backups und hochgeladene Dokumente.
  • Ein freier TCP-Port, standardmäßig 3000. Für den Zugriff aus dem Internet zusätzlich ein Reverse Proxy mit HTTPS.
  • openssl zum Erzeugen der Geheimnisse und curl für Tests.
EckdatenWert
Imageghcr.io/ulsklyc/yuvomi:2.79.0 (Tags ohne führendes v)
Port3000/TCP im Container, Host-Port über OIKOS_HTTP_PORT
Volumes/data (Datenbank), /backups, /app/modules, /documents
Pflicht-EnvSESSION_SECRET, DB_ENCRYPTION_KEY (echter Wert oder bewusst leer)
Wichtige EnvSESSION_SECURE, TRUST_PROXY, TZ, BACKUP_SCHEDULE, BACKUP_KEEP
LizenzMIT

Schritt 1: Projektordner, Compose-Datei und .env anlegen

Die offizielle docker-compose.yml nutzt :latest. Für den Betrieb ist ein fester Versions-Tag sicherer, damit kein pull unbemerkt Datenbankmigrationen einspielt. Die Tags in der GitHub Container Registry tragen kein v: 2.79.0 existiert, v2.79.0 nicht.

mkdir -p /opt/yuvomi && cd /opt/yuvomi
curl -o .env https://raw.githubusercontent.com/ulsklyc/yuvomi/main/.env.example
openssl rand -hex 32   # Wert für SESSION_SECRET
openssl rand -hex 32   # Wert für DB_ENCRYPTION_KEY

Legen Sie daneben die compose.yaml an. Der Healthcheck stammt aus der offiziellen Datei.

services:
  yuvomi:
    image: ghcr.io/ulsklyc/yuvomi:${YUVOMI_TAG:-2.79.0}
    container_name: yuvomi
    restart: unless-stopped
    ports:
      - "${OIKOS_HTTP_PORT:-3000}:3000"
    volumes:
      - ./data:/data
      - ./backups:/backups
      - ./modules:/app/modules
      - ./documents:/documents
    env_file:
      - .env
    environment:
      - NODE_ENV=production
      - DB_PATH=/data/yuvomi.db
      - BACKUP_DIR=/backups
      - MODULES_DIR=/app/modules
      - SESSION_SECURE=${SESSION_SECURE:-false}
    healthcheck:
      test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/health', r => process.exit(r.statusCode === 200 ? 0 : 1))"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s

Tragen Sie in der .env die beiden erzeugten Werte ein und ergänzen Sie Tag und Zeitzone. Die Zeitzone bestimmt unter anderem, wann das nächtliche Backup läuft.

SESSION_SECRET=<erster Wert aus openssl>
DB_ENCRYPTION_KEY=<zweiter Wert aus openssl>
OIKOS_HTTP_PORT=3000
YUVOMI_TAG=2.79.0
TZ=Europe/Berlin

Der Container setzt beim Start die Besitzrechte der Volumes auf den Benutzer node (UID 1000) und läuft danach ohne Root-Rechte. Allgemeine Härtungstipps für Compose-Stacks finden Sie unter Docker Compose absichern: Secrets, Healthchecks, Non-Root.

Verifizieren: docker compose config --quiet gibt nichts aus, und grep -c REPLACE_WITH .env liefert 0. Steht dort noch eine 1 oder 2, ist ein Platzhalter übrig geblieben.

Schritt 2: Container starten und Version prüfen

docker compose up -d --pull always
docker compose ps
docker compose logs --no-log-prefix | grep -E "Version|Backup scheduler"

Im Test meldete docker compose ps den Container nach rund 15 Sekunden als healthy. Das Log nennt Version und Backup-Zeitplan:

"msg":"Server running on port 3000 | Version 2.79.0"
"msg":"Backup scheduler started: 0 2 * * * (keeping last 7 backups)"

Beim ersten Start mit gesetztem Schlüssel legt Yuvomi die Datenbank direkt verschlüsselt an. Eine normale SQLite-Datei beginnt mit SQLite format 3, die Datei im Test mit zufälligen Bytes.

Verifizieren: curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/health liefert 200, und docker inspect yuvomi --format '{{index .Config.Labels "org.opencontainers.image.version"}}' zeigt 2.79.0.

Schritt 3: Ersten Administrator anlegen

Beim ersten Aufruf von http://SERVER:3000 führt Yuvomi durch das Anlegen des Admin-Kontos (Benutzername, Anzeigename, Passwort mit mindestens 8 Zeichen). Bis dahin kann jeder mit Zugriff auf den Port die Einrichtung übernehmen, legen Sie den Admin also sofort an. Ohne Browser geht es über die API:

read -rs PW   # Passwort eingeben, erscheint nicht in der History
curl -s -c jar -X POST http://localhost:3000/api/v1/auth/setup \
  -H 'Content-Type: application/json' \
  -d "{\"username\":\"admin\",\"display_name\":\"Familie Muster\",\"password\":\"$PW\",\"language\":\"de\",\"timezone\":\"Europe/Berlin\"}"

Die Antwort war 201 mit dem neuen Benutzer ("role":"admin"). Ein zweiter Setup-Versuch wird danach im Produktionsmodus mit 404 Not found. abgewiesen, die Einrichtung lässt sich also nicht kapern. Alternativ legt docker compose exec yuvomi node setup.js den Admin auf der Konsole an.

Yuvomi-Übersicht mit Navigation für Planen, Haushalt und Menschen, Hinweis auf die nächste Aufgabe und sechs offene Einkaufsposten
Die Übersicht nach dem ersten Login: links die Module, rechts die Hinweise für heute.

Verifizieren: Nach dem Login zeigt die Übersicht Ihren Anzeigenamen. Ein erneuter POST auf /api/v1/auth/setup liefert 404.

Schritt 4: Aufgaben und Einkaufslisten über die API anlegen

Für Skripte, Home Assistant oder Kurzbefehle erstellen Sie unter Einstellungen, API-Zugriff ein Token. Tokens lassen sich auf einzelne Module und Lese- oder Schreibrechte beschränken. Mit dem Token arbeiten Sie per Authorization: Bearer, ein CSRF-Header ist dann nicht nötig:

T='yuvomi_...'   # Token aus den Einstellungen
B=http://localhost:3000/api/v1
curl -s -X POST $B/tasks -H "Authorization: Bearer $T" -H 'Content-Type: application/json' \
  -d '{"title":"Müll rausbringen","priority":"high","due_date":"2026-10-25"}'
curl -s -X POST $B/shopping -H "Authorization: Bearer $T" -H 'Content-Type: application/json' \
  -d '{"name":"Wocheneinkauf"}'
curl -s -X POST $B/shopping/1/items -H "Authorization: Bearer $T" -H 'Content-Type: application/json' \
  -d '{"name":"Milch"}'

Alle drei Aufrufe antworteten im Test mit 201. Die Einträge erscheinen sofort in der Oberfläche.

Aufgabenliste in Yuvomi mit vier offenen Aufgaben und geöffneter Detailansicht mit Status, Priorität und Kommentaren
Per API angelegte Aufgaben in der Listenansicht, rechts die Details der gewählten Aufgabe.
Einkaufsliste Wocheneinkauf in Yuvomi mit sechs Artikeln wie Milch, Brot, Äpfel und Käse
Die Einkaufsliste im Modul Küche, daneben Mahlzeiten, Rezepte und Vorrat.

Verifizieren: curl -s $B/shopping -H "Authorization: Bearer $T" zeigt die Liste mit "item_total" größer 0. Ohne Token antworten die API-Endpunkte mit 401 Not authenticated.

Schritt 5: Backups einrichten und erstellen

Yuvomi sichert die Datenbank selbst: standardmäßig täglich um 2 Uhr, die letzten sieben Sicherungen bleiben in /backups (Host: ./backups). Anpassbar sind beide Werte über BACKUP_SCHEDULE und BACKUP_KEEP. Unter Einstellungen, Backup und Wiederherstellung stoßen Sie eine Sicherung sofort an, laden eine herunter oder richten ein WebDAV-Ziel ein. Per API geht beides ebenso:

curl -s -X POST $B/backup/trigger -H "Authorization: Bearer $T"
curl -s -o yuvomi-$(date +%F).db -H "Authorization: Bearer $T" $B/backup/database
{"data":{"timestamp":"2026-10-23T00:19:22.775Z","file":"yuvomi-backup-2026-10-23T00-19-22-723Z.db","success":true}}
Einstellungsseite Backup und Wiederherstellung mit Upload-Feld für den Restore und aktivem Zeitplan täglich um 02:00 mit sieben Backups
Automatische Backups sind ab Werk aktiv; das letzte manuelle Backup wird mit Zeitpunkt angezeigt.

Wichtig: Die Backups sind mit demselben DB_ENCRYPTION_KEY verschlüsselt wie die Datenbank, ohne Schlüssel ist jede Sicherung wertlos. Sichern Sie .env getrennt und offline. Außerdem liegen Dokumente nur dann in der Datenbank, wenn Sie keinen lokalen Ordner, kein WebDAV und kein Google Drive als Dokumentenspeicher gewählt haben; andernfalls müssen Sie diese Ziele separat sichern. Kopieren Sie ./backups regelmäßig auf ein anderes System.

Verifizieren: ls -l backups/ zeigt eine Datei yuvomi-backup-…db, und in der Weboberfläche steht bei Letztes Backup ein Zeitpunkt mit dem Zusatz erfolgreich.

Schritt 6: Restore nach Totalverlust

Im Test wurde der Ernstfall nachgestellt: Container gestoppt, Daten- und Backup-Ordner gelöscht, nur die heruntergeladene Sicherung und die .env blieben übrig. Wiederhergestellt wird mit dem dokumentierten Befehl, der die Sicherung zuerst prüft und erst dann ersetzt. Der Befehl stammt unverändert aus der offiziellen Installationsdoku:

SERVICE=yuvomi
BACKUP="$PWD/yuvomi-2026-10-23.db"
docker compose stop "$SERVICE"
docker compose run --rm -v "$BACKUP:/tmp/yuvomi-restore.db:ro" --entrypoint sh "$SERVICE" -c 'set -eu; node server/check-backup.js /tmp/yuvomi-restore.db; target="${DB_PATH:-/data/yuvomi.db}"; case "$target" in */oikos.db) target="${target%/oikos.db}/yuvomi.db";; esac; stamp=$(date -u +%Y%m%dT%H%M%SZ); if [ -f "$target" ]; then cp "$target" "$target.pre-restore-$stamp.0.partial"; sync; mv "$target.pre-restore-$stamp.0.partial" "$target.pre-restore-$stamp"; fi; staging="$target.restore-tmp-0-$stamp"; cp /tmp/yuvomi-restore.db "$staging"; chmod 600 "$staging" 2>/dev/null || true; chown node:node "$staging" 2>/dev/null || true; sync; if [ -f "$target-wal" ]; then if [ -s "$target" ]; then mv "$target-wal" "$target.pre-restore-$stamp-wal"; else mv "$target-wal" "$target.pre-restore-$stamp.wal-kept"; fi; fi; rm -f "$target-shm"; sync; mv "$staging" "$target"; sync'
docker compose up -d "$SERVICE"
Backup check passed: /tmp/yuvomi-restore.db (schema v250).

Nach dem Start war die Marker-Aufgabe Müll rausbringen wieder da, die Einkaufsliste hatte ihre drei Artikel. Bei laufender Instanz geht es bequemer über die Weboberfläche oder die API. Im Test wurde nach einer Sicherung eine weitere Aufgabe angelegt und danach die Sicherung zurückgespielt:

curl -s -X POST $B/backup/restore -H "Authorization: Bearer $T" \
  -H 'Content-Type: application/octet-stream' --data-binary @backups/yuvomi-backup-2026-10-23T00-21-11-912Z.db
{"ok":true,"data":{"schema_version":257}}

Die nachträglich angelegte Aufgabe war danach verschwunden, der Marker blieb. Eine Kopie yuvomi.db.pre-restore-… neben der Datenbank erlaubt den Weg zurück. Eine Sicherung aus einer älteren Version wird beim Einspielen automatisch auf den aktuellen Stand migriert (hier von Schema 250 auf 257). Stammt das Backup von einer anderen Installation, geben Sie deren Schlüssel laut Doku als Backup-Schlüssel im Dialog an, statt den DB_ENCRYPTION_KEY der neuen Instanz zu tauschen.

Verifizieren: docker compose ps meldet healthy, und curl -s $B/tasks -H "Authorization: Bearer $T" enthält die erwarteten Einträge.

Schritt 7: Update auf eine neue Version

Der Testaufbau lief zunächst mit 2.78.0 und wurde anschließend auf 2.79.0 gehoben. Legen Sie vor jedem Update ein Backup an und lesen Sie das Changelog. Danach genügt es, den Tag zu ändern:

curl -s -X POST $B/backup/trigger -H "Authorization: Bearer $T"
sed -i 's/^YUVOMI_TAG=.*/YUVOMI_TAG=2.79.0/' .env
docker compose pull
docker compose up -d
docker compose logs --no-log-prefix | grep -E "Migration|Version"
"msg":"Migration 251 applied: users: avatar_key, a random key per profile picture for its address"
"msg":"Migration 255 applied: recipe providers: an account remembers the case of its last failed sync"
"msg":"Server running on port 3000 | Version 2.79.0"

Das Update brachte sieben Migrationen (251 bis 257) und war nach wenigen Sekunden durch, alle Daten blieben erhalten. Wichtig: Migrationen laufen nur vorwärts. Der Versuch, danach wieder 2.78.0 zu starten, endete in einer Neustartschleife:

Error: [DB] This database was written by a newer Yuvomi: it carries migration 251, 252, 253, 254, 255, 256, 257 and this build knows up to v250.

Der Weg zurück ist daher immer das Backup von vor dem Update, nicht ein älteres Image.

Verifizieren: curl -s $B/version -H "Authorization: Bearer $T" liefert "version":"2.79.0".

Troubleshooting

SymptomUrsache und Lösung
Container in Restarting (1), Log: DB_ENCRYPTION_KEY is still the placeholder from .env.examplePlatzhalter aus der Beispieldatei. Echten Wert mit openssl rand -hex 32 eintragen oder die Zeile leeren, wenn Sie bewusst ohne Verschlüsselung arbeiten.
Log: SESSION_SECRET is still the placeholder from .env.exampleGleiches Prinzip. Dieser Abbruch greift auch bei bestehenden Installationen; ein neues Geheimnis kostet nur einen erneuten Login.
Log: Wrong encryption key - /data/yuvomi.db could not be decrypted with DB_ENCRYPTION_KEY, /health nicht erreichbarDer Schlüssel in der .env passt nicht zur Datenbank. Im Test genügte es, den alten Wert zurückzuschreiben und docker compose up -d auszuführen. Ohne den alten Wert sind die Daten verloren.
Nach einem Update auf eine ältere Version: This database was written by a newer YuvomiWieder die neuere Version starten oder das Backup von vor dem Update zurückspielen.
Alle Benutzer abgemeldetSESSION_SECRET wurde geändert. Im Test lieferte die alte Sitzung danach 401, API-Tokens funktionierten weiter.
Alter Container oikos blockiert nach der Umbenennung Port 3000Einmal docker compose up -d --remove-orphans ausführen.

Häufige Fragen

Muss ich die Datenbank verschlüsseln?

Nein, ein leerer DB_ENCRYPTION_KEY startet Yuvomi unverschlüsselt. Weil Familienplaner aber Gesundheitsdaten, Dokumente und Budgets enthalten können, rät das Projekt zur Verschlüsselung. Laut Projekt wird eine unverschlüsselte Datenbank beim ersten Start mit Schlüssel einmalig verschlüsselt.

Was passiert, wenn ich das SESSION_SECRET verliere?

Nichts Schlimmes: Sie erzeugen ein neues, alle Benutzer melden sich einmal neu an. API-Tokens bleiben gültig, weil sie in der Datenbank liegen.

Wie betreibe ich Yuvomi hinter einem Reverse Proxy?

Für den Zugriff von unterwegs gehört Yuvomi hinter einen Proxy mit HTTPS, etwa Caddy, Nginx oder Zoraxy. Die Projektdoku nennt dafür SESSION_SECURE=true, damit das Session-Cookie nur über HTTPS läuft, und TRUST_PROXY=1, damit Yuvomi die echte Client-Adresse übernimmt. Binden Sie den Port dann nur an localhost ("127.0.0.1:3000:3000"). Für Einladungs- und Erinnerungsmails setzen Sie zusätzlich BASE_URL auf die öffentliche Adresse.

Fazit

Yuvomi ist schnell installiert, und typische Fehler wie Platzhalter-Geheimnisse, falscher Schlüssel und Downgrades enden in einem sauberen Abbruch mit klarer Meldung statt in stillem Datenverlust. Backup, Prüfung und Restore sind eingebaut und haben im Test einen Totalverlust vollständig rückgängig gemacht. Die eigentliche Verantwortung liegt bei Ihnen: Der DB_ENCRYPTION_KEY muss getrennt von den Backups sicher verwahrt werden, und vor jedem Update gehört eine frische Sicherung auf ein zweites System. Gegenüber Grocy, KitchenOwl oder Tandoor ist Yuvomi breiter aufgestellt und verbindet Einkauf und Rezepte mit Kalender, Aufgaben und Budget.

Weiterführende Anleitungen und Quellen

YuvomiDocker ComposeFamilienplanerSelfhostingBackupSQLiteHaushalt