| | 1 | = Backups der Web-Dienste = |
| | 2 | |
| | 3 | [[PageOutline(2-3)]] |
| | 4 | |
| | 5 | Diese Seite beschreibt, '''was''' bei den Web-Diensten gesichert wird, '''wo die Grenzen''' der LV-weisen Sicherung liegen und '''wie eine Ad-hoc-Sicherung von Hand''' läuft, bevor an einem Dienst geschraubt wird. |
| | 6 | |
| | 7 | Die Mechanik von Dirvish selbst — Bank, Vaults, Branches, Expire, Recovery — steht in [wiki:BackupSystem]. Hier steht nur, was dienstspezifisch ist. Siehe auch [wiki:WebDienste]. |
| | 8 | |
| | 9 | == Hosts == |
| | 10 | |
| | 11 | ||= Host =||= Rolle =|| |
| | 12 | || `backer` || Dirvish-Server. Alle `dirvish`-Aufrufe werden hier abgesetzt, als root. || |
| | 13 | || `laubfrosch` || Web-Host. NGINX, Docker-Container der Web-Dienste, Webroots unter `/var/www/`. || |
| | 14 | || `janus` || Datenbank-Server. MariaDB nativ, nicht im Container. || |
| | 15 | |
| | 16 | == Vaults und ihre Grenzen == |
| | 17 | |
| | 18 | Die Web-Dienste sind so aufgebaut, dass App-Code und Datenmasse in getrennten LVs liegen. Der Rsync bleibt mit `xdev` innerhalb eines Dateisystems; damit ist der Umfang eines Vaults durch die LV-Grenze definiert und nicht durch eine Exclude-Liste, die mit jedem Update erodiert. |
| | 19 | |
| | 20 | ||= Vault =||= Dienst =||= Zustand außerhalb des LV =|| |
| | 21 | || `www-cloudservice` || Nextcloud (inkl. Passman) || Datenbank `cloudservice` auf `janus` || |
| | 22 | || `www-usvn` || USVN / Subversion || || |
| | 23 | || `www-trac` || Trac || || |
| | 24 | || `www-octoprint` || !OctoPrint || || |
| | 25 | || `www-iobroker` || ioBroker || || |
| | 26 | || `janus-local` || lokale Daten auf `janus`, u.a. die SQL-Dumps || || |
| | 27 | |
| | 28 | '''Die rechte Spalte ist die eigentliche Fallgrube.''' Ein Vault ist genau so viel wert, wie die Antwort auf die Frage „welcher Zustand dieses Dienstes liegt ''nicht'' in diesem LV?" vollständig ist. Das betrifft Datenbanken auf anderen Hosts, Redis- oder !SQLite-Stände, und — weil `xdev` ja gerade nicht über Dateisystemgrenzen geht — jeden weiteren Mount ''innerhalb'' des Baums, etwa ein Docker-Volume unterhalb des Webroots. |
| | 29 | |
| | 30 | Prüfung pro Dienst, einmalig und nach jedem Umbau: |
| | 31 | |
| | 32 | {{{#!sh |
| | 33 | # auf laubfrosch: hängt innerhalb des Webroots noch etwas eigenes? |
| | 34 | findmnt -R /var/www/<dienst> |
| | 35 | }}} |
| | 36 | |
| | 37 | Taucht dort ein Mount auf, der in keinem Vault steht, ist er unsichtbar für das Backup. |
| | 38 | |
| | 39 | == Nextcloud und Passman im Detail == |
| | 40 | |
| | 41 | === Warum Dump und config.php nur als Paar taugen === |
| | 42 | |
| | 43 | Passman verschlüsselt die ohnehin schon clientseitig verschlüsselten Credentials auf dem Server ein zweites Mal. Der dafür verwendete Schlüssel wird aus `passwordsalt` und `secret` aus der `config.php` abgeleitet. Daraus folgt: |
| | 44 | |
| | 45 | * Ein Datenbank-Dump ohne die zugehörige `config.php` ist für die Passman-Daten '''wertlos''' — auch dann, wenn alle Benutzer ihr Vault-Passwort noch wissen. |
| | 46 | * `passwordsalt`, `secret` und `instanceid` sind aus keinem Backup rekonstruierbar. Gehen sie verloren, sind sie weg. |
| | 47 | * Beim Rollback eines fehlgeschlagenen Versionsupgrades müssen Dump und `config.php` '''vom selben Zeitpunkt''' stammen. In der `config.php` steht die `version`, die zum Schemastand der Datenbank passen muss; eine neue `config.php` auf einer alten Datenbank führt beim Start direkt in den Upgrade- oder Fehlerzustand. |
| | 48 | |
| | 49 | Die `config.php` liegt auf `laubfrosch` unter: |
| | 50 | |
| | 51 | {{{ |
| | 52 | /var/www/cloudservice.vpn21.net/htdocs/virgin/config/config.php |
| | 53 | }}} |
| | 54 | |
| | 55 | Sie liegt damit innerhalb des Webroots und wird vom Vault `www-cloudservice` erfasst — ''sofern'' `config/` nicht als eigenes Docker-Volume gemountet ist. Das ist mit dem `findmnt` oben zu verifizieren und ist der wichtigste Einzelpunkt dieser Seite. |
| | 56 | |
| | 57 | === Was aus dem Backup grundsätzlich nicht wiederkommt === |
| | 58 | |
| | 59 | Der Vault-Key eines Passman-Vaults verlässt den Client nie. Es gibt keine Admin-Funktion, fremde Vaults zu sichern oder zu exportieren; die aktuelle Passman-Version registriert genau ein `occ`-Kommando, und das ist ein Wartungs-Check für Sharing-ACLs. Die Sicherung erfasst also die Daten aller Benutzer, aber lesbar macht sie nur der jeweilige Benutzer mit seinem Vault-Passwort. |
| | 60 | |
| | 61 | Konsequenz für den Betrieb: Jeder Benutzer muss sein Vault-Passwort außerhalb von Nextcloud hinterlegt haben. Wer eine Nextcloud-unabhängig lesbare Kopie will, muss sie selbst ziehen — im Vault unter den Einstellungen als JSON-Export (vollständiger als CSV, da Custom Fields erhalten bleiben) und anschließend verschlüsselt ablegen. Zentral anstoßen lässt sich das nicht. |
| | 62 | |
| | 63 | === Sicherheitliche Kehrseite === |
| | 64 | |
| | 65 | Sobald SQL-Dump und `passwordsalt`/`secret` beide unverschlüsselt im Dirvish-Baum liegen, ist dieses Dateisystem der direkte Weg zur serverseitigen Entschlüsselungsschicht aller Passman-Daten. Dirvish verschlüsselt nichts, und die Hardlink-Historie bedeutet, dass das für alle Images gilt. Das ist eine bewusste Entscheidung wert, keine Nebenwirkung. |
| | 66 | |
| | 67 | == Ad-hoc-Sicherung vor einem Eingriff == |
| | 68 | |
| | 69 | Anzuwenden vor jedem Versionsupgrade und vor jedem Eingriff an einem Dienst. Die Images laufen in der normalen Rotation des Vaults mit; wer einen Pre-Upgrade-Stand länger halten will, muss ihn vor dem Verfallen auslagern. |
| | 70 | |
| | 71 | === Nextcloud (`www-cloudservice`) === |
| | 72 | |
| | 73 | Drei Hosts, der Reihe nach. Die Reihenfolge ist nicht beliebig: Erst stillstellen, dann dumpen, dann einsammeln. |
| | 74 | |
| | 75 | 1. '''Auf `laubfrosch`''' — Instanz stillstellen, damit Dump und Dateistand zueinander passen. Der `trap` sorgt dafür, dass ein Abbruch die Cloud nicht im Wartungsmodus stehen lässt: |
| | 76 | {{{#!sh |
| | 77 | cd /var/www/cloudservice.vpn21.net |
| | 78 | ./enter-nextcloud-fpm-docker-container.sh |
| | 79 | ./occ maintenance:mode --on |
| | 80 | }}} |
| | 81 | 1. '''Auf `janus`''' — Dump ziehen, in dasselbe Verzeichnis, das der `pre-client` des Vaults `janus-local` benutzt: |
| | 82 | {{{#!sh |
| | 83 | # als root, sonst keine Schreibrechte in /var/lib |
| | 84 | mysqldump --single-transaction --quick --default-character-set=utf8mb4 \ |
| | 85 | -u root -p cloudservice | gzip > /var/lib/cloudservice-$(date +%F-%H%M).sql.gz |
| | 86 | }}} |
| | 87 | `--single-transaction` liefert bei reinem InnoDB einen konsistenten Snapshot ohne Sperren. `--default-character-set=utf8mb4` ist zwingend, sonst schreddert der Dump die 4-Byte-Zeichen — die Instanz läuft mit `utf8mb4` / `utf8mb4_bin`. |
| | 88 | 1. '''Auf `laubfrosch`''' — Wartungsmodus wieder aus: |
| | 89 | {{{#!sh |
| | 90 | cd /var/www/cloudservice.vpn21.net |
| | 91 | ./enter-nextcloud-fpm-docker-container.sh |
| | 92 | ./occ maintenance:mode --off |
| | 93 | }}} |
| | 94 | 1. '''Auf `backer`''' — beide Hälften einsammeln, als root. Der Code-/Config-Stand und der Dump liegen in verschiedenen Vaults und müssen deshalb beide gezogen werden: |
| | 95 | {{{#!sh |
| | 96 | dirvish --vault www-cloudservice |
| | 97 | dirvish --vault janus-local |
| | 98 | }}} |
| | 99 | 1. '''Gegenprobe''' auf `backer`, bevor der Eingriff beginnt: |
| | 100 | {{{#!sh |
| | 101 | dirvish-locate www-cloudservice config/config.php | tail |
| | 102 | }}} |
| | 103 | Zu sehen sein muss das soeben erzeugte Image. Erst dann ist der Rollback-Stand vollständig: Dump, `config.php` und App-Code vom selben Zeitpunkt. |
| | 104 | |
| | 105 | === Übrige Dienste === |
| | 106 | |
| | 107 | Gleiches Muster, verkürzt. Für Dienste ohne Zustand außerhalb des LV bleibt nur der letzte Schritt: |
| | 108 | |
| | 109 | {{{#!sh |
| | 110 | # auf backer, als root |
| | 111 | dirvish --vault www-usvn # bzw. www-trac, www-octoprint, www-iobroker |
| | 112 | }}} |
| | 113 | |
| | 114 | Hat der Dienst Zustand außerhalb seines LV (Spalte in der Vault-Tabelle oben), gehören davor dieselben Schritte wie bei Nextcloud: Dienst stillstellen oder in einen konsistenten Zustand bringen, Zustand in eine Datei schreiben, die in einem Vault liegt, dann erst `dirvish`. Beim Ausfüllen der Tabelle ist je Dienst zu klären: |
| | 115 | |
| | 116 | * Läuft eine Datenbank außerhalb des LV, und wohin wird sie gedumpt? |
| | 117 | * Hält der Dienst Zustand im RAM, der beim harten Stop verloren geht (ioBroker, !OctoPrint)? |
| | 118 | * Liegt eine SQLite-Datei im LV, die während des Rsync beschrieben werden kann? |
| | 119 | |
| | 120 | == Safe-Auszug der unersetzlichen Schlüssel == |
| | 121 | |
| | 122 | Weil `passwordsalt`, `secret` und `instanceid` unersetzlich sind, existieren sie zusätzlich auf Papier. Das Script `[attachment:nc-secrets-sheet.sh]` erzeugt den Auszug als Klartext-Blatt und als QR-Code. |
| | 123 | |
| | 124 | Ablage des Scripts: als Anhang an dieser Seite sowie auf `laubfrosch` unter `/var/www/cloudservice.vpn21.net`. |
| | 125 | |
| | 126 | Aufruf auf `laubfrosch`: |
| | 127 | |
| | 128 | {{{#!sh |
| | 129 | cd /var/www/cloudservice.vpn21.net |
| | 130 | ./nc-secrets-sheet.sh htdocs/virgin/config/config.php cloudservice.vpn21.net |
| | 131 | }}} |
| | 132 | |
| | 133 | Erzeugt werden `nc-secrets-<datum>.txt` und `nc-secrets-<datum>.png`. Der QR-Code enthält exakt dieselben `key=value`-Zeilen wie das Blatt, nicht die Prosa drumherum, mit Fehlerkorrektur auf Stufe `H`. |
| | 134 | |
| | 135 | Eigenschaften, auf die beim Umgang zu achten ist: |
| | 136 | |
| | 137 | * Fehlt einer der drei Einträge in der `config.php` oder ändert sich deren Schreibweise, bricht das Script ab, statt ein unvollständiges Blatt zu erzeugen. |
| | 138 | * `umask 077` steht im Script, die Dateien entstehen also nicht kurzzeitig mit offenen Rechten. Trotzdem gehören sie '''nicht''' in das Dirvish-Revier und sind nach dem Druck zu löschen — der vorgesehene Weg ist Papier und Safe. |
| | 139 | * Das Blatt gehört '''nicht''' ins Passman-Vault und nicht ins Wiki: Ohne diese Werte lässt sich das Vault nicht öffnen, in dem sie dann lägen. Ins Wiki gehört das Script, nicht seine Ausgabe. |
| | 140 | * Die Werte ändern sich im Normalbetrieb nicht, auch nicht über Versionsupgrades hinweg. Der Ausdruck altert also nicht und muss nur bei einem Neuaufsetzen der Instanz erneuert werden. Datum und Instanzname stehen auf dem Blatt, damit er in Jahren noch zuzuordnen ist. |