diff --git a/ROADMAP.md b/ROADMAP.md index 32bdf9f..2988ccb 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1066,6 +1066,45 @@ Kreuzchen, das sich setzen lässt und beim nächsten Laden weg ist. Diesmal beide Stellen angefasst und nachgemessen: **vier geschickt, vier gespeichert.** In beiden steht jetzt ein Verweis auf die andere. +### ✅ Fertig — die Sicherung liegt an drei Orten statt an zweien + +Der letzte offene Punkt aus `docs/ideen.md`. Ein **zweites Laufwerk**, +einstellbar im Panel unter Einstellungen → Sicherung; `tools/sichern.ps1` legt +das Archiv dort ab, vergleicht die Prüfsumme und dünnt auch dort aus. + +**Warum das nicht dasselbe ist wie die Nextcloud.** Die hilft, wenn der ganze +Rechner weg ist — aber wer 335 MB, später 100 GB, zurückholen muss, lädt sie +über die Leitung. Das zweite Laufwerk ist in Minuten zurückgespielt. Zwei +Fragen, zwei Antworten. + +**Und es warnt, wenn es dieselbe Platte ist.** Das ist der eigentliche Inhalt: +ein zweiter Ordner auf `C:` sieht im Panel genauso grün aus wie eine echte +zweite Platte und hilft gegen gar nichts. Verglichen wird die *physische* +Platte und nicht der Laufwerksbuchstabe — zwei Partitionen derselben NVMe +sterben zusammen. Nachgemessen, dieser Rechner: + +``` +Platte 0 SAMSUNG MZVL21T0HDLU-00B07 954 GB -> C: (Daten + C:\backup) +Platte 1 SAMSUNG MZVL21T0HDLU-00B07 954 GB -> D: (das zweite Ziel) + +C:\backup gegen D:\backup -> Nr. 0 gegen Nr. 1 -> "andere Platte" +C:\backup gegen C:\Users -> Nr. 0 gegen Nr. 0 -> Warnung +``` + +Ein echter Lauf, kein Trockentest: 4630 Einträge, 335,9 MB, auf beiden lokalen +Zielen und in der Nextcloud dieselbe Prüfsumme `FFCE4D0A7310…`. Der Bericht in +`sicherung.letzte` trägt jetzt `zweit: true`; fehlt das Feld, ist **kein** +zweites Ziel eingerichtet — es steht absichtlich nicht als `false` da, denn das +läse sich wie „hat nicht geklappt". + +Die **Statusseite** zählt die Orte mit: `sicherung ok an 3 Orten` statt nur +`ok`. Eine Sicherung, die es nur einmal gibt, ist grün und trotzdem eine, die +ein Plattenausfall mitnimmt — das gehört dorthin, wo jemand hinsieht. + +Und `tools/zurueckspielen.ps1` sagt im Kopf, was zu tippen ist, wenn genau +diese Platte das Problem ist. Das ist der Fall, für den das Ganze da ist, und +niemand soll ihn um vier Uhr nachts erst herleiten müssen. + ### ⬜ Als Nächstes **Der Vergleichsmaßstab ist weg.** Am 11.08.2026 sind die Lite-Container diff --git a/docs/API.md b/docs/API.md index 5e81a05..a0ec80d 100644 --- a/docs/API.md +++ b/docs/API.md @@ -177,6 +177,10 @@ dieses Dienstes — fällt eines aus, ist er `gestoert` und die Antwort ist Wer auch das rot haben will, hängt `?streng=1` an — dann gibt alles außer `gesund` eine 503. +Die Prüfung `sicherung` sagt zusätzlich, an **wie vielen Orten** das letzte +Archiv liegt (`an 3 Orten`, oder `nur an einem Ort`). Eine Sicherung, die es +nur einmal gibt, ist grün und trotzdem eine, die ein Plattenausfall mitnimmt. + ### In Uptime Kuma ``` diff --git a/docs/ideen.md b/docs/ideen.md index f115386..5735a64 100644 --- a/docs/ideen.md +++ b/docs/ideen.md @@ -138,10 +138,26 @@ die Oberfläche sie nicht ein zweites Mal hinschreibt. Bei 910 GB frei ist das heute keine Grenze, sondern eine Zusicherung: der Papierkorb kann nicht mehr unbemerkt zur zweiten Ablage werden. -### Mehrere Sicherungsziele — offen +### ~~Mehrere Sicherungsziele~~ — gebaut am 12.08.2026 -Die Archive liegen auf derselben Platte wie die Daten, die Kopie in der -Nextcloud ist die einzige Trennung. +Ein **zweites Laufwerk**, einstellbar im Panel unter Einstellungen → Sicherung. +Damit liegt jedes Archiv an drei Orten: `C:ackup`, das zweite Laufwerk und +die Nextcloud. + +Die drei sind nicht dreimal dasselbe. Die Nextcloud hilft, wenn der ganze +Rechner weg ist — aber wer 335 MB (oder später 100 GB) zurückholen muss, lädt +sie über die Leitung. Das zweite Laufwerk ist in Minuten zurückgespielt. + +**Und es warnt, wenn es dieselbe Platte ist.** Das ist der eigentliche Inhalt: +ein zweiter Ordner auf C: sieht im Panel genauso grün aus wie eine echte zweite +Platte und hilft gegen gar nichts. Verglichen wird die *physische* Platte, nicht +der Laufwerksbuchstabe — zwei Partitionen derselben NVMe sterben zusammen. +Nachgemessen in beide Richtungen: `C:` gegen `D:` ergibt Nr. 0 gegen Nr. 1 und +ein „andere Platte"; `C:` gegen `C:` ergibt zweimal Nr. 0 und die Warnung. + +Ein echter Lauf: 4630 Einträge, 335,9 MB, auf beiden Zielen die Prüfsumme +`FFCE4D0A7310…` — identisch. Die Statusseite sagt seitdem +`sicherung ok an 3 Orten` statt nur `ok`. --- diff --git a/server/src/routes/dash.ts b/server/src/routes/dash.ts index e406f71..fb38f4d 100644 --- a/server/src/routes/dash.ts +++ b/server/src/routes/dash.ts @@ -1311,6 +1311,7 @@ dashRoutes.post('/settings', async (c) => { passwort?: string ordner?: string behalten?: number | string + zweitziel?: string } }>(c) if (!body) return c.json(KEIN_JSON, 400) @@ -1418,6 +1419,31 @@ dashRoutes.post('/settings', async (c) => { } setSetting(SICHERUNG_KEYS.behalten, String(Math.round(n))) } + if (sic.zweitziel !== undefined) { + // Der Pfad gilt auf dem HOST. Der Dienst sieht ihn nie und kann + // ihn deshalb nicht nachschlagen -- er nimmt ihn entgegen und + // tools/sichern.ps1 stolpert notfalls darueber. Was hier trotzdem + // geht, ist die Form: ein Pfad ohne Laufwerk oder Freigabe ist mit + // Sicherheit ein Tippfehler, und ein Tippfehler in einem + // Sicherungsziel faellt sonst erst auf, wenn man die Sicherung + // braucht. + const v = sic.zweitziel.trim().replace(/[\\/]+$/, '') + // Entweder ein Laufwerksbuchstabe (D:\...) oder eine UNC-Freigabe + // (\\nas\sicherungen). Alles andere ist ein relativer Pfad, und + // relativ WOZU waere hier gar nicht beantwortbar. + if (v && !/^([A-Za-z]:[\\/]|\\\\[^\\]+\\)/.test(v)) { + return c.json( + { + error: + 'Das zweite Ziel braucht ein Laufwerk oder eine Freigabe, ' + + 'z. B. D:\\backup\\d4rk_media oder \\\\nas\\sicherungen.', + }, + 400, + ) + } + setSetting(SICHERUNG_KEYS.zweitziel, v) + } + // Wie beim Discord-Geheimnis: leer heisst unveraendert, "-" entfernt. if (sic.passwort !== undefined) { const v = sic.passwort.trim() diff --git a/server/src/routes/status.ts b/server/src/routes/status.ts index ecf33fc..b55fde4 100644 --- a/server/src/routes/status.ts +++ b/server/src/routes/status.ts @@ -189,7 +189,12 @@ async function pruefen(): Promise { pruefungen.push({ was: 'sicherung', ok: false, hinweis: 'noch keine gemeldet' }) } else { try { - const l = JSON.parse(roh) as { at: number; ok: boolean } + const l = JSON.parse(roh) as { + at: number + ok: boolean + hoch?: boolean + zweit?: boolean + } const stunden = (now() - l.at) / 3_600_000 if (!l.ok) { pruefungen.push({ was: 'sicherung', ok: false, hinweis: 'letzte fehlgeschlagen' }) @@ -200,7 +205,16 @@ async function pruefen(): Promise { hinweis: `letzte vor ${Math.round(stunden)} Stunden`, }) } else { - pruefungen.push({ was: 'sicherung', ok: true }) + // WIEVIELE ORTE, nicht nur "gelaufen". Eine Sicherung, die es + // nur einmal gibt, ist gruen und trotzdem eine, die ein + // Plattenausfall mitnimmt -- das gehoert auf die Statusseite, + // wo jemand hinschaut, und nicht nur ins Panel. + const orte = 1 + (l.zweit ? 1 : 0) + (l.hoch ? 1 : 0) + pruefungen.push({ + was: 'sicherung', + ok: true, + hinweis: orte === 1 ? 'nur an einem Ort' : `an ${orte} Orten`, + }) } } catch { pruefungen.push({ was: 'sicherung', ok: false, hinweis: 'Eintrag unlesbar' }) diff --git a/server/src/settings.ts b/server/src/settings.ts index 5662221..6caabc2 100644 --- a/server/src/settings.ts +++ b/server/src/settings.ts @@ -109,6 +109,17 @@ export const SICHERUNG_KEYS = { passwort: 'sicherung.passwort', ordner: 'sicherung.ordner', behalten: 'sicherung.behalten', + /** Ein ZWEITER lokaler Ablageort, moeglichst auf einer anderen Platte. + * + * WOZU, wenn es doch schon die Nextcloud gibt: die ist weit weg. Wer + * 100 GB zurueckholen muss, laedt sie ueber die Leitung -- das ist die + * Sicherung fuer den Fall, dass das Haus abbrennt, nicht fuer den Fall, + * dass eine Platte stirbt. Fuer den zweiten will man die Kopie IM Rechner + * haben, nur eben nicht auf derselben Platte. + * + * Der Pfad gilt auf dem HOST, nicht im Container -- ihn prueft deshalb + * nicht der Dienst, sondern tools/sichern.ps1. */ + zweitziel: 'sicherung.zweitziel', /** Schreibt das Skript nach jedem Lauf. JSON, damit das Panel es anzeigen * kann, ohne dass hier eine weitere Tabelle noetig waere. */ letzte: 'sicherung.letzte', @@ -119,6 +130,7 @@ export type SicherungConfig = { benutzer: string ordner: string behalten: number + zweitziel: string hatPasswort: boolean bereit: boolean } @@ -135,6 +147,7 @@ export function sicherungConfig(): SicherungConfig { benutzer, ordner, behalten, + zweitziel: getSetting(SICHERUNG_KEYS.zweitziel), hatPasswort: Boolean(passwort), bereit: Boolean(basis && benutzer && passwort), } diff --git a/server/ui/src/api.ts b/server/ui/src/api.ts index d9547e1..33d83df 100644 --- a/server/ui/src/api.ts +++ b/server/ui/src/api.ts @@ -309,6 +309,10 @@ export type LetzteSicherung = { groesse?: number /** true = in der Nextcloud, false = nur lokal, undefined = unbekannt. */ hoch?: boolean + /** true = auch auf der zweiten Platte. undefined heisst „kein zweites Ziel + * eingerichtet" und nicht „hat nicht geklappt" -- schiefgegangen waere ein + * Grund fuer ok:false, nicht fuer ein stilles false. */ + zweit?: boolean fehler?: string } | null @@ -320,6 +324,7 @@ export type Einstellungen = { benutzer: string ordner: string behalten: number + zweitziel: string hatPasswort: boolean bereit: boolean letzte: LetzteSicherung diff --git a/server/ui/src/pages/Einstellungen.tsx b/server/ui/src/pages/Einstellungen.tsx index df3f7a0..be7e835 100644 --- a/server/ui/src/pages/Einstellungen.tsx +++ b/server/ui/src/pages/Einstellungen.tsx @@ -1,5 +1,13 @@ import { useEffect, useState } from 'react' -import { AlertTriangle, CheckCircle2, CloudUpload, Loader2, ShieldCheck, ShieldX } from 'lucide-react' +import { + AlertTriangle, + CheckCircle2, + CloudUpload, + HardDrive, + Loader2, + ShieldCheck, + ShieldX, +} from 'lucide-react' import { api, type Einstellungen as EinstellungenDaten } from '../api' import { run, useStore } from '../store' import { bytes, zeit } from '../format' @@ -55,6 +63,7 @@ function SicherungKarte() { const [passwort, setPasswort] = useState('') const [ordner, setOrdner] = useState('') const [behalten, setBehalten] = useState('14') + const [zweitziel, setZweitziel] = useState('') async function laden() { setLaedt(true) @@ -65,6 +74,7 @@ function SicherungKarte() { setBenutzer(e.sicherung.benutzer) setOrdner(e.sicherung.ordner) setBehalten(String(e.sicherung.behalten)) + setZweitziel(e.sicherung.zweitziel) } catch (err) { note('fehler', err instanceof Error ? err.message : 'Unbekannt') } finally { @@ -87,6 +97,7 @@ function SicherungKarte() { ...(passwort ? { passwort } : {}), ordner, behalten: Number(behalten), + zweitziel, }), (r) => r.bereit @@ -116,7 +127,7 @@ function SicherungKarte() { return ( @@ -158,6 +169,7 @@ function SicherungKarte() { {l.groesse != null && `, ${bytes(l.groesse)}`} {l.hoch === true && ', in der Nextcloud'} {l.hoch === false && ', nur lokal'} + {l.zweit === true && ', auf der zweiten Platte'} {l.fehler && ( {l.fehler} )} @@ -199,11 +211,34 @@ function SicherungKarte() { min={1} max={365} value={behalten} - hinweis="gilt hier wie in der Nextcloud" + hinweis="gilt überall gleich" onChange={(e) => setBehalten(e.target.value)} /> + setZweitziel(e.target.value)} + /> +

+ + + + Die zwei Ziele beantworten zwei verschiedene Fragen. + {' '} + Die Nextcloud hilft, wenn der ganze Rechner weg ist — aber wer 100 GB + zurückholen muss, lädt sie über die Leitung. Das zweite Ziel liegt im + Rechner und ist in Minuten zurückgespielt; es hilft nur, wenn es auf einer{' '} + anderen Platte liegt als die + Daten. Ein zweiter Ordner auf derselben Platte sieht aus wie eine + Sicherung und ist keine. + +

+

diff --git a/tools/sichern.ps1 b/tools/sichern.ps1 index 578ebb4..6623ba6 100644 --- a/tools/sichern.ps1 +++ b/tools/sichern.ps1 @@ -16,14 +16,26 @@ # 3. Das Archiv wird GEPRUEFT: ausgepackt, die Datenbank geoeffnet, die # Eintraege gezaehlt und mit dem laufenden Dienst verglichen. Eine # Sicherung, die niemand nachzaehlt, ist eine Vermutung. -# 4. Das Archiv geht in die NEXTCLOUD, wenn im Panel Zugangsdaten stehen +# 4. Das Archiv geht auf ein ZWEITES LAUFWERK, wenn im Panel eines steht +# (Einstellungen → Sicherung → "Zweites Ziel"). Auch hier wird die +# Pruefsumme verglichen — eine Kopie, die niemand nachzaehlt, ist eine +# Vermutung. +# +# WOZU, wo es doch die Nextcloud gibt: die beiden beantworten zwei +# verschiedene Fragen. Die Nextcloud hilft, wenn der ganze Rechner weg +# ist — aber wer 100 GB zurueckholen muss, laedt sie ueber die Leitung. +# Das zweite Laufwerk ist in Minuten zurueckgespielt. Es hilft nur, wenn +# es eine ANDERE PLATTE ist: ein zweiter Ordner auf derselben sieht aus +# wie eine Sicherung und ist keine. +# +# 4a. Das Archiv geht in die NEXTCLOUD, wenn im Panel Zugangsdaten stehen # (Einstellungen → Sicherung). Bis dahin lag die Sicherung auf derselben # Platte wie die Daten — gegen einen Plattenausfall half sie gar nicht. -# 4b. Und der Lauf MELDET SICH ZURUECK: das Ergebnis landet in der Datenbank +# 4c. Und der Lauf MELDET SICH ZURUECK: das Ergebnis landet in der Datenbank # und steht danach im Panel. Eine Sicherung, die still aufhoert zu laufen, # ist der eigentliche Schaden — nicht die eine Nacht, in der sie fehlt. -# 5. Alte Archive fliegen raus, hier wie dort, sobald mehr als -Behalten da -# sind. +# 5. Alte Archive fliegen raus, an ALLEN drei Orten, sobald mehr als +# -Behalten da sind. # # WARUM CURL UND NICHT RCLONE. Nextcloud spricht WebDAV, curl spricht WebDAV, # und curl ist ohnehin da. rclone waere ein weiteres Programm, das installiert, @@ -43,7 +55,10 @@ param( [string]$Container = 'd4rk-media', [string]$Volume = 'd4rk_media_media-data', [string]$Abbild = 'd4rk-media:latest', - [int]$Behalten = 14 + [int]$Behalten = 14, + # Leer heisst: aus den Einstellungen im Panel holen. Ein Wert hier hat + # Vorrang -- fuer den Fall, dass jemand einmalig woanders hinsichern will. + [string]$Zweitziel = '' ) $ErrorActionPreference = 'Stop' @@ -56,6 +71,7 @@ function Schlecht($text) { Write-Host " $text" -ForegroundColor Red } # steht. Schlaegt DAS fehl, ist es kein Grund, die Sicherung als gescheitert zu # behandeln — das Archiv liegt dann trotzdem richtig. $inDerWolke = $false +$aufZweiter = $null function Melde($ok, $dateien, $groesse, $hoch, $fehler) { $eintrag = @{ @@ -65,6 +81,10 @@ function Melde($ok, $dateien, $groesse, $hoch, $fehler) { groesse = $groesse hoch = [bool]$hoch } + # $null heisst "kein zweites Ziel eingerichtet" und steht dann GAR NICHT im + # Bericht -- ein Feld, das immer "false" sagt, liest sich wie "hat nicht + # geklappt", und das waere eine Falschmeldung. + if ($null -ne $script:aufZweiter) { $eintrag['zweit'] = [bool]$script:aufZweiter } if ($fehler) { $eintrag['fehler'] = "$fehler" } $json = ($eintrag | ConvertTo-Json -Compress) @@ -191,7 +211,12 @@ if ($dateien -ne $zahlen.media) { } Gut 'Datenbank in der Sicherung ist lesbar und vollstaendig.' -# -- 4. In die Nextcloud ------------------------------------------------------- +# -- Wohin ueberhaupt? Zugangsdaten und Ziele lesen ---------------------------- +# +# Beides kommt aus derselben Quelle und wird deshalb an EINER Stelle geholt: die +# Nextcloud-Zugangsdaten und der Pfad des zweiten Laufwerks. Was danach kommt, +# sind die drei Ziele in der Reihenfolge, in der sie im Ernstfall gebraucht +# werden -- erst die Platte nebenan, dann die Wolke. # # Die Zugangsdaten liegen NEBEN den Sicherungen und nicht im Repo: sie gehoeren # zu dieser Maschine, nicht zum Code. Fehlt die Datei, wird das einmal gesagt @@ -235,17 +260,102 @@ console.log(JSON.stringify({ passwort: hol('sicherung.passwort'), ordner: hol('sicherung.ordner'), behalten: hol('sicherung.behalten'), + zweitziel: hol('sicherung.zweitziel'), })); "@ if ($LASTEXITCODE -eq 0 -and $roh) { $j = $roh | ConvertFrom-Json - foreach ($k in 'basis', 'benutzer', 'passwort', 'ordner', 'behalten') { + foreach ($k in 'basis', 'benutzer', 'passwort', 'ordner', 'behalten', 'zweitziel') { if ($j.$k) { $z[$k] = $j.$k } } } } if ($z['behalten']) { $Behalten = [int]$z['behalten'] } +if (-not $Zweitziel -and $z['zweitziel']) { $Zweitziel = $z['zweitziel'] } + +# -- 4. Auf die zweite Platte -------------------------------------------------- +# +# Das billigste Ziel von allen -- ein Kopiervorgang im selben Rechner -- und das +# einzige, aus dem sich hundert Gigabyte in Minuten zurueckholen lassen. +# +# GEPRUEFT WIRD MIT DER PRUEFSUMME und nicht mit der Dateigroesse: eine +# abgebrochene Kopie auf eine volle Platte hat oft genau die richtige Laenge und +# trotzdem Nullen am Ende. +# +# UND ES WIRD GEWARNT, WENN ES DIESELBE PLATTE IST -- das ist der eigentliche +# Fehler, gegen den das hier gebaut ist. Ein zweiter Ordner auf C: sieht im +# Panel genauso gruen aus wie eine echte zweite Platte und hilft gegen gar +# nichts. Verglichen wird die PHYSISCHE Platte und nicht der Laufwerksbuchstabe: +# zwei Partitionen derselben NVMe sterben zusammen. + +function PlattenNummer($pfad) { + # $null heisst "kein Urteil moeglich" (Netzfreigabe, ungewoehnliche + # Einhaengung) und ist ausdruecklich nicht dasselbe wie "andere Platte". + try { + $wurzel = [System.IO.Path]::GetPathRoot((Resolve-Path $pfad).Path) + $buchstabe = $wurzel.TrimEnd('\', ':') + if ($buchstabe.Length -ne 1) { return $null } + return (Get-Partition -DriveLetter $buchstabe -ErrorAction Stop).DiskNumber + } catch { return $null } +} + +if (-not $Zweitziel) { + Write-Host ' Kein zweites Ziel eingerichtet (Panel -> Einstellungen -> Sicherung).' -ForegroundColor Yellow +} else { + Schritt "Auf die zweite Platte: $Zweitziel" + + try { + New-Item -ItemType Directory -Force -Path $Zweitziel -ErrorAction Stop | Out-Null + } catch { + Schlecht "Das zweite Ziel ist nicht erreichbar: $($_.Exception.Message)" + $aufZweiter = $false + Melde $false $zahlen.media $groesse $inDerWolke "Zweites Ziel: $($_.Exception.Message)" + exit 1 + } + + $hier = PlattenNummer $Ziel + $dort = PlattenNummer $Zweitziel + if ($null -ne $hier -and $hier -eq $dort) { + Write-Host " ACHTUNG: $Zweitziel liegt auf DERSELBEN Platte (Nr. $hier) wie $Ziel." -ForegroundColor Yellow + Write-Host ' Gegen einen Plattenausfall hilft das nicht -- ein anderes Laufwerk waehlen.' -ForegroundColor Yellow + } elseif ($null -ne $hier -and $null -ne $dort) { + Gut "andere Platte: Nr. $dort statt Nr. $hier" + } + + $zweitDatei = Join-Path $Zweitziel $name + try { + Copy-Item $archiv $zweitDatei -Force -ErrorAction Stop + } catch { + Schlecht "Kopieren fehlgeschlagen: $($_.Exception.Message)" + $aufZweiter = $false + Melde $false $zahlen.media $groesse $inDerWolke "Zweites Ziel: $($_.Exception.Message)" + exit 1 + } + + $hierHash = (Get-FileHash $archiv -Algorithm SHA256).Hash + $dortHash = (Get-FileHash $zweitDatei -Algorithm SHA256).Hash + if ($hierHash -ne $dortHash) { + Schlecht 'Die Kopie auf der zweiten Platte ist NICHT identisch.' + Remove-Item $zweitDatei -Force -ErrorAction SilentlyContinue + $aufZweiter = $false + Melde $false $zahlen.media $groesse $inDerWolke 'Pruefsumme der zweiten Kopie weicht ab' + exit 1 + } + Gut "kopiert und verglichen: identisch ($($hierHash.Substring(0,12))...)" + $aufZweiter = $true + + # Auch dort ausduennen, sonst laeuft die zweite Platte still voll. + $dortAlle = Get-ChildItem $Zweitziel -Filter 'd4rk_media-*.tar.gz' | Sort-Object Name -Descending + if ($dortAlle.Count -gt $Behalten) { + $dortAlle | Select-Object -Skip $Behalten | ForEach-Object { + Remove-Item $_.FullName -Force + Gut "auf der zweiten Platte entfernt: $($_.Name)" + } + } +} + +# -- 4a. In die Nextcloud ------------------------------------------------------ if (-not ($z['basis'] -and $z['benutzer'] -and $z['passwort'])) { Write-Host ' Keine Nextcloud eingerichtet (Panel → Einstellungen → Sicherung) — die Sicherung bleibt lokal.' -ForegroundColor Yellow diff --git a/tools/zurueckspielen.ps1 b/tools/zurueckspielen.ps1 index 1c15776..91ac195 100644 --- a/tools/zurueckspielen.ps1 +++ b/tools/zurueckspielen.ps1 @@ -21,10 +21,22 @@ # Bestand ausliefern und raeumt hinterher auf. Der echte Dienst wird dabei # nicht angefasst -- er laeuft die ganze Zeit weiter. +# WENN GENAU DIESE PLATTE DAS PROBLEM IST: die Sicherung liegt seit dem zweiten +# Ziel auch woanders. Das ist der Fall, fuer den sie da ist, und niemand soll +# ihn um vier Uhr nachts erst herleiten muessen -- +# +# pwsh -File tools\zurueckspielen.ps1 -Ordner D:\backup\d4rk_media -Echt +# +# und wenn auch die zweite Platte weg ist, holt man das Archiv aus der Nextcloud +# (Sicherungen/d4rk_media) und zeigt mit -Archiv direkt darauf. Welche Ziele +# eingerichtet sind, steht im Panel unter Einstellungen -> Sicherung. + [CmdletBinding()] param( # Ohne Angabe: das neueste Archiv im Sicherungsordner. [string]$Archiv = '', + # Die ZWEITE Platte steht in den Einstellungen; ohne Angabe wird hier + # gesucht, weil das der Ordner ist, in den sichern.ps1 zuerst schreibt. [string]$Ordner = 'C:\backup\d4rk_media', [string]$Container = 'd4rk-media', [string]$Volume = 'd4rk_media_media-data',