duffyduckandClaude Opus 5 2d7418ca69 flatten laeuft im laufenden Betrieb - belegt, nicht behauptet
Am ganzen Durchlauf gemessen: VM 9802 aus einem 802-Snapshot mit geladenem
Arbeitsspeicher gestartet, dann geflattet, waehrend sie lief.

  32-GiB-Platte, 13 GiB kopiert, rund 70s
  bei jeder Messung qmpstatus=running, QEMU-Monitor antwortete
  Uhr auf der Konsole lief weiter (10:38 -> 10:39, mit Bildschirmanimation)
  danach kein PARENT mehr, Quell-Snapshots entschuetzt
  Kostenschaetzung sagte 14.1G vorher - kopiert wurden 13 GiB

Anders als beim Live-Restore des Proxmox Backup Servers wird nichts
nachgeladen: der Klon liegt im selben Pool und ist von Anfang an vollstaendig.
flatten loest nur die Abhaengigkeit, nicht die Verfuegbarkeit.

Nebenbei: ein Datentraeger, den es gar nicht mehr gibt - etwa der kopierte
Arbeitsspeicher, den Proxmox nach dem Fortsetzen selbst freigibt - wurde als
"war schon eigenstaendig" gemeldet. Er wird jetzt uebergangen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 19:11:00 +02:00
2026-07-31 01:33:36 +02:00

pvesnap — automatische Snapshots für Proxmox VE

Ein systemd-Dienst, der nach frei definierbaren Zeitplänen Snapshots von VMs und Containern anlegt und alte Snapshots nach einer einstellbaren Vorhaltezeit wieder löscht. Alles wird über eine INI-Datei gesteuert, die sich auch bequem in einem ncurses-Editor bearbeiten lässt.

  • Beliebig viele Gruppen — z. B. „diese VMs stündlich, jene täglich, der Rest monatlich“
  • VM-Auswahl nach VMID, Name (mit *-Mustern), Tag, Pool oder einfach „alle“
  • Vorhaltezeit je Gruppe nach Anzahl und/oder Alter
  • Jeder Snapshot bekommt eine Beschreibung, an der er sich wiedererkennen lässt
  • Läuft cluster-weit (alle Nodes) über pvesh
  • Nur Python-Standardbibliothek — keine zusätzlichen Pakete nötig

Dazu drei Werkzeuge, um wieder an die Daten im Snapshot zu kommen:

  • pvesnap-explorer — zwei Fenster im Terminal wie im Midnight Commander
  • pvesnap-web — im Browser durchsehen und herunterladen, auch vom anderen Rechner
  • pvesnap-recovery — den Snapshot als laufende Maschine starten, abgeschottet ohne Netzwerk oder als vollwertige Wiederherstellung mit gleicher Identität

Installation

Auf dem Proxmox-Host als root:

git clone <dieses-repo> pvesnap && cd pvesnap
./install.sh                                    # nur der Snapshot-Dienst
./install.sh --with-webexplorer --port 8823     # zusätzlich die Web-Oberfläche
./install.sh --help                             # alle Optionen
Option
--with-webexplorer Web-Oberfläche als Dienst einrichten (erfordert --port)
--port <nummer> Port der Web-Oberfläche
--bind <adresse> Adresse, auf der sie lauscht (Vorgabe 0.0.0.0)
--no-start installieren, aber Dienste nicht starten
--force auch ohne erkanntes Proxmox VE installieren

Das Skript legt an:

Pfad Inhalt
/usr/lib/pvesnap/ Programmcode
/usr/local/bin/pvesnap Dienst und Konfiguration
/usr/local/bin/pvesnap-explorer Zwei-Fenster-Explorer
/usr/local/bin/pvesnap-web Web-Oberfläche
/usr/local/bin/pvesnap-recovery Snapshot als Maschine starten
/etc/pvesnap/pvesnap.conf Konfiguration (wird bei Updates nicht überschrieben)
/var/lib/pvesnap/state.json merkt sich die letzten Läufe
/etc/systemd/system/pvesnap.service systemd-Unit des Snapshot-Dienstes
/etc/systemd/system/pvesnap-web.service Unit der Web-Oberfläche (nur mit --with-webexplorer)
/etc/pvesnap/web.conf Port und Anmeldeart der Web-Oberfläche

In der mitgelieferten Beispielkonfiguration sind alle Gruppen auf enabled = no gesetzt — es passiert also erst etwas, wenn du eine Gruppe aktivierst.

Deinstallation:

./uninstall.sh            # Programm und Dienst entfernen, Konfiguration bleibt
./uninstall.sh --purge    # zusätzlich /etc/pvesnap und /var/lib/pvesnap löschen

Bereits angelegte Snapshots werden dabei nie angerührt.


Konfiguration im ncurses-Editor

pvesnap config
  • GruppenlisteEnter bearbeiten, n neu, c kopieren, d löschen, Leertaste an/aus, g globale Einstellungen, v Übersicht welche VM in welcher Gruppe landet, s speichern, r Dienst neu laden, q Ende
  • r — Dienst neu laden, ohne den Editor zu verlassen: entspricht systemctl reload pvesnap. Ungespeicherte Änderungen werden vorher zum Speichern angeboten, ein gestoppter Dienst zum Starten, und wenn das Neuladen scheitert, wird ein Neustart angeboten. Nach s fragt der Editor ohnehin gleich, ob neu geladen werden soll. Oben in der Kopfzeile steht jederzeit, ob der Dienst läuft. (Braucht root — also sudo pvesnap config.)
  • Gruppe bearbeiten — Feld auswählen, Enter ändern, Leertaste umschalten. Ganz unten steht live, auf wie viele Gäste die Auswahl gerade zutrifft.
  • VM-Auswahl (v) — Liste aller VMs und Container mit Node, Status und Tags; Leertaste auswählen, a alle, n keine, i umkehren, / filtern, Enter übernehmen.

Beim Speichern wird die INI-Datei neu geschrieben. Eigene Kommentare und ein [defaults]-Abschnitt gehen dabei verloren (die Werte bleiben inhaltlich erhalten, sie stehen danach in jeder Gruppe einzeln). Eine Sicherung wird als pvesnap.conf.bak abgelegt.


Konfiguration von Hand

[global]
prefix = auto                      # Namenspräfix aller pvesnap-Snapshots
check_interval = 60s               # wie oft der Dienst nach Fälligem schaut
state_file = /var/lib/pvesnap/state.json
log_level = INFO
task_timeout = 15m
retries = 2                        # Wiederholungen, wenn eine Sperre belegt ist
retry_delay = 60s
pause_between = 0s                 # Pause zwischen zwei Gästen
run_on_start = no                  # beim Start sofort einen Durchlauf machen?
dry_run = no                       # yes = nichts wirklich tun, nur protokollieren
description = pvesnap | Gruppe: {group} | erstellt: {datetime} | Vorhaltezeit: {keep_time}

[defaults]                         # Vorgaben für alle Gruppen (optional)
skip_stopped = no

[group:stündlich]
interval = 1h
align = yes                        # an der Uhr ausrichten: 00:00, 01:00, ...
keep_count = 24                    # höchstens 24 Snapshots je VM
keep_time = 2d                     # nichts älter als 2 Tage
tags = stuendlich                  # alle VMs mit diesem Tag
skip_stopped = yes

[group:täglich]
schedule = daily
at = 02:30
keep_count = 14
keep_time = 21d
names = web-*, db-*

[group:monatlich]
schedule = monthly
day_of_month = 1
at = 04:00
keep_count = 6
all = yes
exclude_tags = nosnap

Nach jeder Änderung:

pvesnap check                # Konfiguration prüfen
systemctl reload pvesnap     # Dienst übernimmt die Änderung ohne Neustart

Zeitplan

Entweder ein Intervall …

interval = 30m      # 30m, 1h, 6h, 2d12h, 1w ...
align = yes         # yes: an der Uhr ausgerichtet (00:00, 00:30, 01:00, ...)
                    # no:  30 Minuten nach dem letzten Lauf

… oder ein fester Termin:

schedule zusätzliche Angaben Beispiel
hourly minute = 15 jede Stunde um :15
daily at = 02:30 täglich um 02:30
weekly at, day_of_week = so sonntags um 03:00
monthly at, day_of_month = 1 am 1. jedes Monats
yearly at, day_of_month, month einmal jährlich

day_of_month = 31 wird in kürzeren Monaten automatisch auf den letzten Tag gezogen. Läuft der Host zum Termin nicht, wird der Lauf beim nächsten Start nachgeholt.

Vorhaltezeit

keep_count = 24     # höchstens 24 Snapshots je VM und Gruppe (0 = unbegrenzt)
keep_time  = 7d     # nichts älter als 7 Tage           (0 = unbegrenzt)
keep_min   = 1      # so viele bleiben in jedem Fall stehen

Beides ist kombinierbar — gelöscht wird, was eine der beiden Grenzen reißt. Mindestens eine der beiden Angaben muss gesetzt sein, sonst würde die Zahl der Snapshots unbegrenzt wachsen (pvesnap check weist darauf hin).

Welche VMs?

Alle Angaben wirken als ODER, Ausschlüsse gewinnen immer:

all = yes                     # alle VMs und Container
vmids = 100,101,105-110       # nach ID, auch Bereiche
names = web-*, db-0?          # nach Name, mit Platzhaltern
tags = prod, wichtig          # nach Proxmox-Tag
pools = Kunden                # nach Proxmox-Pool
types = qemu                  # nur VMs (bzw. lxc = nur Container; leer = beides)

exclude_vmids = 999
exclude_names = *-test
exclude_tags = nosnap

Snapshot-Optionen

vmstate = yes         # RAM mitsichern (nur QEMU und nur bei laufender VM)
skip_stopped = yes    # gestoppte Gäste überspringen
description = Sicherung von {name} ({vmid}) vom {date}

Platzhalter der Beschreibung: {group} {group_slug} {vmid} {name} {node} {type} {pool} {tags} {date} {time} {datetime} {timestamp} {keep_time} {keep_count} {schedule}


Namensschema und Sicherheit

auto-taeglich-20260730-023000
 │      │         │       └── Uhrzeit
 │      │         └────────── Datum
 │      └──────────────────── Kurzname der Gruppe
 └─────────────────────────── prefix aus [global]

pvesnap löscht ausschließlich Snapshots, deren Name exakt auf dieses Muster passt und deren Gruppen-Kurzname zur jeweiligen Gruppe gehört. Von Hand oder von anderen Werkzeugen angelegte Snapshots bleiben garantiert unangetastet.

Umlaute und Sonderzeichen im Gruppennamen werden für den Kurznamen umgeschrieben (täglichtaeglich). Wenn zwei Gruppen denselben Kurznamen ergäben, meldet das pvesnap check.


Befehle

pvesnap status                    # Übersicht: Gruppen, letzte und nächste Läufe
pvesnap vms                       # alle VMs und die Gruppen, in denen sie stecken
pvesnap list                      # vorhandene pvesnap-Snapshots  (-a = auch fremde)
pvesnap check                     # Konfiguration prüfen
pvesnap config                    # ncurses-Editor

pvesnap run                       # jetzt fällige Gruppen ausführen
pvesnap run --force -g täglich    # eine Gruppe sofort ausführen
pvesnap run --force --dry-run     # Probelauf, ändert nichts
pvesnap prune -g stündlich        # nur aufräumen, keine neuen Snapshots

systemctl status pvesnap
systemctl reload pvesnap          # Konfiguration neu einlesen (SIGHUP)
journalctl -u pvesnap -f          # Protokoll mitlesen

Ein manueller pvesnap run ist auch möglich, während der Dienst läuft — beide teilen sich eine Sperre und kommen sich nicht in die Quere.

Mit -c /pfad/zur.conf lässt sich jederzeit eine andere Konfiguration verwenden, z. B. zum Ausprobieren.


Hinweise aus der Praxis

  • Snapshot ist kein Backup. Snapshots liegen auf demselben Storage wie die VM. Für echte Sicherungen zusätzlich vzdump / Proxmox Backup Server verwenden.
  • Speicherplatz: Jeder Snapshot hält alte Blöcke fest. Bei schreibfreudigen VMs lieber kurze Vorhaltezeiten wählen und den Storage im Auge behalten.
  • Nicht jedes Storage kann Snapshots — LVM-thick und Verzeichnis-Storage mit raw-Images können es nicht. Solche VMs melden einen Fehler im Protokoll; die übrigen laufen normal weiter.
  • vmstate = yes friert die VM kurz ein und braucht Platz in Höhe des zugewiesenen RAM. Für regelmäßige Läufe meist unnötig.
  • Gruppe umbenennen: Der neue Name bekommt einen eigenen Kurznamen. Snapshots unter dem alten Namen werden dann nicht mehr automatisch aufgeräumt — vorher aufräumen lassen oder die alten Snapshots von Hand entfernen.
  • Zeitumstellung: Es wird mit lokaler Zeit gerechnet. Ein täglicher Termin um 02:30 kann in der Umstellungsnacht ausfallen oder doppelt anstehen.

Wenn Snapshots am Storage-Lock scheitern

trying to acquire cfs lock 'storage-data' ...
TASK ERROR: cfs-lock 'storage-data' error: got lock request timeout

storage-data ist dabei kein falsch gelesener Name — in pmxcfs heißen Storage-Sperren immer storage-<name>, gemeint ist also das Storage data. Proxmox nimmt diese Sperre beim Anlegen eines Snapshots und gibt nach 60 s auf, wenn sie jemand anderes hält.

pvesnap geht damit so um:

  • Der Aufruf wartet, bis der Snapshot-Task in Proxmox wirklich fertig ist, bevor die nächste VM drankommt — sonst würden sich die Läufe gegenseitig aussperren.
  • Sperr-Fehler gelten als vorübergehend und werden retries-mal mit retry_delay Abstand wiederholt. Echte Fehler (etwa „storage does not support snapshots") werden nicht wiederholt.
  • Mit pause_between = 10s lässt sich zusätzlich Druck vom Storage nehmen, wenn viele VMs auf demselben Storage liegen.

Der Dienst scheitert, von Hand geht es

Scheitert jeder Lauf des Dienstes am Storage-Lock, während derselbe Befehl in der Shell funktioniert, liegt es an der Umgebung des Dienstes — nicht am Storage. pvesh führt die Proxmox-API im eigenen Prozess aus, der Snapshot-Task ist also ein Kindprozess von pvesnap und erbt alles, was in der systemd-Unit eingeschränkt wurde.

Der Klassiker ist ProtectSystem= in der Unit: das hängt /etc schreibgeschützt ein, und pmxcfs legt seine Sperren als Verzeichnisse unter /etc/pve/priv/lock/ an. Das mkdir scheitert, Proxmox wiederholt es erfolglos — und meldet am Ende einen Lock-Timeout statt eines Rechtefehlers. Prüfen:

systemctl show pvesnap -p ProtectSystem -p ProtectHome -p PrivateTmp -p ReadOnlyPaths
pvesnap check          # meldet so etwas von sich aus

Alle drei müssen leer bzw. no sein. Die mitgelieferte Unit enthält deshalb bewusst keine Sandbox-Optionen.

Wenn die Sperre wirklich belegt ist

Diese Kommandos helfen beim Eingrenzen:

pvesm status                      # ist das Storage online und erreichbar?
grep -A6 "^[a-z]*: data" /etc/pve/storage.cfg
pvesh get /cluster/tasks --output-format json | head    # hängt noch ein Task?
systemctl status pvestatd pve-cluster
journalctl -u pvestatd -n 50

Häufigste Ursachen: ein hängender Backup- oder Replikationsjob auf demselben Storage, ein nicht erreichbares NFS/CIFS-Storage (dann blockiert pvestatd), oder ein abgebrochener Task, der die Sperre nicht freigegeben hat.


Dateien aus einem Snapshot holen

Ein Snapshot ist kein Verzeichnis. Damit man hineinschauen kann, wird er schreibgeschützt als Blockgerät eingebunden und gemountet — je nach Storage unterschiedlich:

Storage Weg hinein
rbd (Ceph) rbd map pool/image@snap, bei nicht unterstützten Image-Features rbd-nbd
zfspool Container direkt über .zfs/snapshot/…, VMs über einen temporären Klon
lvmthin, lvm die Snapshot-LV snap_<volume>_<snapname> aktivieren
dir, nfs, cifs qemu-nbd --load-snapshot (nur qcow2)

Danach werden Partitionen erkannt und mit ro,noload bzw. ro,norecovery,nouuid gemountet — Snapshots laufender Gäste haben fast immer ein unsauberes Journal, ohne diese Optionen würde der Kernel hineinschreiben wollen.

Aufgeräumt wird beim Beenden automatisch. Bleibt nach einem Absturz etwas hängen:

pvesnap-explorer --cleanup

pvesnap-explorer — zwei Fenster im Terminal

pvesnap-explorer                  # Gast und Snapshot auswählen
pvesnap-explorer 802              # Snapshot von VM 802 auswählen
pvesnap-explorer 802 <snapname>   # direkt öffnen
pvesnap-explorer --local /srv/restore     # rechtes Fenster startet dort
pvesnap-explorer --path /mnt/x    # beliebiges Verzeichnis (zum Ausprobieren)
pvesnap-explorer --cleanup        # hängengebliebene Einbindungen lösen
Parameter Vorgabe Bedeutung
vmid Gast direkt vorwählen
snapshot Snapshot direkt vorwählen
-l, --local <pfad> aktuelles Verzeichnis Startverzeichnis im rechten Fenster
-p, --path <pfad> beliebiges Verzeichnis öffnen, ohne Proxmox zu fragen
--cleanup hängengebliebene Einbindungen lösen und beenden
-v, --verbose ausführliches Protokoll

Links der Snapshot, rechts der lokale Rechner:

Taste
Tab Fenster wechseln
Pfeiltasten, Enter bewegen, Verzeichnis öffnen oder Datei ansehen
Backspace ein Verzeichnis hoch
Leertaste markieren; * umkehren, a alle, u keine
F5 / c Markiertes ins andere Fenster kopieren
F3 / v Datei ansehen (Text oder Hex)
F7 / n neues Verzeichnis (nur lokal)
F6 / g Verzeichnis direkt eingeben
F2 / m anderes Dateisystem des Snapshots wählen
F10 / q eine Ebene zurück (Snapshot wird ausgehängt)

Der Explorer hat drei Ebenen: Gastauswahl → Snapshot-Auswahl → Dateien. Mit q geht es jeweils eine Ebene zurück; beim Verlassen des Dateibrowsers wird der Snapshot wieder ausgehängt, sodass man gleich den nächsten öffnen kann. Das rechte Fenster behält dabei sein Verzeichnis — praktisch, wenn man aus mehreren Snapshots ins selbe Zielverzeichnis sammelt.

Kopiert wird immer vom aktiven ins andere Fenster — in den Snapshot hinein geht nichts, er ist schreibgeschützt. Beim Kopieren gibt es einen Fortschrittsbalken, ESC bricht ab; vorhandene Dateien werden abgefragt (ja / nein / alle / keine). Gerätedateien und Sockets werden übersprungen, symbolische Verweise bleiben Verweise.

pvesnap-web — im Browser herunterladen

Als Dienst einrichten

./install.sh --with-webexplorer --port 8823

Danach läuft die Oberfläche dauerhaft auf http://<host>:8823/ und startet mit dem System. Ohne --port bricht das Skript ab — der Port hat keine sinnvolle Vorgabe, die zu jedem Host passt.

./install.sh --with-webexplorer --port 8443 --bind 10.0.0.5   # nur auf einer IP
./install.sh --with-webexplorer --port 8823 --no-start        # erst später starten

Alle Aufrufparameter des Dienstes stehen in /etc/pvesnap/web.conf:

PVESNAP_WEB_ARGS=--bind 0.0.0.0 --port 8823 --auth pve

Dort lässt sich alles nachträglich ändern — Port, Adresse, Anmeldeart, Rechte:

nano /etc/pvesnap/web.conf
systemctl restart pvesnap-web

Dienst verwalten:

systemctl status pvesnap-web        # läuft er?
systemctl restart pvesnap-web       # nach Änderungen in web.conf
systemctl stop pvesnap-web          # anhalten (hängt offene Snapshots aus)
systemctl disable pvesnap-web       # nicht mehr automatisch starten
journalctl -u pvesnap-web -f        # Protokoll, auch fehlgeschlagene Anmeldungen

Von Hand starten

Für einen einmaligen Einsatz, ohne etwas zu installieren:

pvesnap-web                                  # Gast und Snapshot im Browser wählen
pvesnap-web 802                              # nur diesen Gast anbieten
pvesnap-web 802 autosnap-taeglich-20260731-023000    # Snapshot gleich öffnen
Parameter Vorgabe Bedeutung
-P, --port <nummer> 8823 Port, auf dem gelauscht wird
-b, --bind <adresse> 0.0.0.0 Netzwerkadresse; 127.0.0.1 = nur lokal
-a, --auth pve|token|none pve Anmeldeart, siehe unten
--require-privilege <recht> VM.Snapshot nötiges Recht auf dem Gast
--allow-user <user@realm> dieser Benutzer darf alles (mehrfach möglich)
-t, --token <schlüssel> zufällig Zugangsschlüssel selbst vorgeben
--no-token Kurzform für --auth none
-p, --path <verzeichnis> beliebiges Verzeichnis statt eines Snapshots
--cleanup hängengebliebene Einbindungen lösen und beenden
-v, --verbose ausführliches Protokoll
-V, --version Version anzeigen

Beispiele:

# Nur lokal lauschen, dazu vom Arbeitsplatz einen SSH-Tunnel legen
pvesnap-web --bind 127.0.0.1 --port 8823
#   am eigenen Rechner:  ssh -L 8823:localhost:8823 root@pve
#   dann im Browser:     http://localhost:8823/

# Ein Backup-Team soll ran, ohne Snapshot-Rechte zu haben
pvesnap-web --port 8823 --require-privilege VM.Backup

# Ein einzelner Dienstleister, unabhängig von den Proxmox-Rechten
pvesnap-web --port 8823 --allow-user dienstleister@pve

# Schnell etwas herausgeben, ohne Proxmox-Benutzer (Schlüssel in der Adresse)
pvesnap-web --port 8823 --auth token

# Ein beliebiges Verzeichnis freigeben, z. B. ein bereits gemountetes Backup
pvesnap-web --path /mnt/restore --port 8823

# Nach einem Absturz aufräumen
pvesnap-web --cleanup

Mit pvesnap-web --help gibt es dieselbe Übersicht im Terminal.

Anmeldung mit den Proxmox-Benutzern. Die Oberfläche zeigt dieselbe Anmeldemaske wie Proxmox — Benutzername, Passwort, Realm-Auswahl. Geprüft wird über POST /access/ticket auf der lokalen Proxmox-API, also genau den Weg, den auch das Proxmox-Webinterface geht. Alle Realms (pam, pve, LDAP, AD …) funktionieren damit automatisch. Zwei-Faktor-Anmeldungen werden abgewiesen statt halb durchgewinkt.

Wer darf was sehen? Ein gültiges Passwort allein reicht nicht — sonst könnte jeder Proxmox-Benutzer sämtliche Dateien aller Gäste lesen. Zusätzlich muss der Benutzer auf dem jeweiligen Gast das Recht VM.Snapshot besitzen (geprüft auf /, /vms, /vms/<id> und dem Pool des Gastes). In der Gastliste tauchen nur Gäste auf, für die das zutrifft; root@pam sieht wie in Proxmox alles. Anpassen mit:

--require-privilege VM.Backup        # anderes Recht verlangen
--allow-user backup@pve              # einzelne Benutzer generell zulassen
--auth token                         # stattdessen Schlüssel in der Adresse
--auth none                          # ohne Anmeldung (nur im vertrauten Netz)

Ohne Proxmox (--path) gibt es keine Benutzer — dort wird automatisch ein Zugangsschlüssel erzeugt und beim Start als Adresse ausgegeben.

Bedienung: Snapshot anklicken, durchklicken; einzelne Dateien werden direkt heruntergeladen, Verzeichnisse und Mehrfachauswahl als ZIP (im Strom erzeugt, es wird nichts zwischengespeichert).

Zur Sicherheit:

  • Es wird ausschließlich gelesen. Die Oberfläche kann nichts ändern oder löschen.
  • Pfade außerhalb des eingebundenen Snapshots werden abgewiesen — über die Adresszeile kommt man nicht an den Rest des Hosts.
  • Fehlgeschlagene Anmeldungen landen mit Absender-IP im Journal (journalctl -u pvesnap-web).
  • Die Verbindung ist unverschlüsseltes HTTP — Passwörter gehen im Klartext über das Netz. Über unsichere Netze deshalb besser einen SSH-Tunnel legen: ssh -L 8823:localhost:8823 root@pve, dazu in web.conf --bind 127.0.0.1 setzen.

Beim Beenden (Strg-C oder systemctl stop pvesnap-web) wird ein offener Snapshot wieder ausgehängt.


Einen Snapshot als Maschine starten — pvesnap-recovery

Manchmal reicht es nicht, einzelne Dateien herauszukopieren. Eine Datenbank zum Beispiel liegt im Snapshot als Haufen halbfertiger Dateien — brauchbar wird sie erst, wenn der Datenbankserver läuft und selbst einen Dump schreibt. Genau dafür ist pvesnap-recovery da: Es startet den Snapshot als eigenständige Maschine, ohne das Original anzufassen.

Zwei Betriebsarten:

live recovery
Netzwerk keins volles Netz
Identität bleibt (UUID, MACs, Hostname) bleibt (UUID, MACs, Hostname)
Wofür hineinschauen, Dump ziehen, Daten holen die Maschine wirklich wieder in Betrieb nehmen
Risiko keins — sie kann nichts erreichen hoch, solange das Original läuft

Bedient wird das Ganze mit pvesnap-recovery (ncurses-Oberfläche mit Übersicht und Assistent) oder direkt über Parameter.

Warum das schnell geht

Die Datenträger werden nicht kopiert, sondern geklont. Auf Ceph/RBD, ZFS und LVM-thin ist das ein Copy-on-Write-Klon: Er ist in Sekunden fertig, egal wie groß die Platte ist, und belegt anfangs keinen zusätzlichen Platz. Eine 32-GB-Platte war im Test nach 0,8 Sekunden geklont.

Dafür wird PVE::Storage::vdisk_clone benutzt — dieselbe Funktion, die auch Proxmox selbst für Klone verwendet, samt Cluster-Sperre auf dem Storage. Es wird also nichts nachgebaut, was Proxmox schon kann.

Auf Datei-Storages (dir, nfs, cifs) geht das nicht — dort lässt sich aus einem qcow2-internen Snapshot kein Klon ziehen. Für diese Storages bleibt der Weg über pvesnap-explorer.

Beide Betriebsarten klonen gleich. live und recovery unterscheiden sich ausschließlich im Netzwerk und in den Sicherheitsabfragen — an den Datenträgern ändert der Modus nichts. Es gibt keinen Vollkopie-Pfad.

Nachsehen lässt sich das jederzeit auf dem Host:

rbd -p <pool> ls -l | grep -E 'NAME|vm-<neue-id>'   # Spalte PARENT
rbd -p <pool> du    | grep -E 'NAME|vm-<neue-id>'   # PROVISIONED gegen USED

Eine frisch geklonte 32-GB-Platte steht dort mit PROVISIONED 32 GiB und USED 80 MiB — die 80 MiB sind alles, was der laufende Gast seither geschrieben hat.

Eigenständig machen — flatten

Ein Linked Clone hängt für immer am Quell-Snapshot. Für „mal reinschauen" ist das ideal, für eine dauerhaft übernommene Maschine nicht:

  • der Quell-Snapshot lässt sich nicht mehr löschen (die Vorhaltezeit scheitert mit snapshot is protected)
  • die Original-VM muss mitsamt ihrer Platte bestehen bleiben
  • der Klon wächst mit jedem Schreibvorgang

Soll die Wiederherstellung bleiben, wird sie gelöst:

pvesnap-recovery flatten 9802

Dahinter steckt rbd flatten — die Daten aus dem Elternteil werden jetzt wirklich in den Klon kopiert. Das dauert und belegt Platz, läuft aber im laufenden Betrieb. Danach hängt die Maschine an nichts mehr, und der Schutz der Quell-Snapshots wird automatisch aufgehoben, sodass die Vorhaltezeit wieder durchkommt. In der Oberfläche liegt das auf der Taste f; die Detailansicht zeigt an, ob eine Maschine noch am Snapshot hängt.

Nicht von rbd du täuschen lassen. Die Zeile eines Snapshots zeigt nur dessen Zuwachs, nicht seinen Inhalt. Im Test stand @handtest01 mit USED 56 MiB da — kopiert werden beim Flatten trotzdem über 8 GB, denn sichtbar ist an dieser Stelle der gesamte Inhalt der Kette (<TOTAL> 14 GiB). pvesnap-recovery flatten misst das deshalb vorher und nennt die Größe, bevor es losgeht.

Vorher wird geprüft, ob der Platz reicht. Läuft ein Ceph-Pool während des Kopierens voll, blockiert er alle Schreibvorgänge — dann steht nicht nur das Flatten, sondern jede VM auf diesem Storage, und selbst das Aufräumen wird schwierig, weil Löschen ebenfalls ein Schreibvorgang ist. flatten bricht deshalb ab, wenn weniger als das 1,15-fache des Bedarfs frei ist; --force setzt sich darüber hinweg.

Schnell ist es, solange Platz da ist: 13 GB waren im Test in rund 70 Sekunden kopiert.

Die Maschine läuft dabei weiter. rbd flatten ist eine Online-Operation — anders als beim Live-Restore des Proxmox Backup Servers wird hier nichts nachgeladen: Der Linked Clone liegt im selben Pool und ist aus Sicht des Gastes von Sekunde eins an vollständig. flatten löst nur die Abhängigkeit, nicht die Verfügbarkeit. Im Test blieb die VM über den gesamten Vorgang auf qmpstatus: running, der QEMU-Monitor antwortete durchgehend, und die Uhr auf der Konsole lief weiter (10:38 → 10:39, mit sichtbarer Bildschirmanimation) — inklusive geladenem RAM-Zustand.

Wenn außerhalb von pvesnap gelöscht wurde — cleanup

Wird eine Wiederherstellung in der Proxmox-Oberfläche entfernt statt mit destroy, bleibt etwas liegen: der Klon selbst kann übrigbleiben, und der Quell-Snapshot bleibt geschützt — die Vorhaltezeit scheitert dann dauerhaft mit snapshot is protected.

pvesnap-recovery cleanup          # zeigt Gefundenes, fragt, räumt auf
pvesnap-recovery cleanup --all    # auch Datenträger ohne Elternteil

Gesucht wird nach Datenträgern der Form vm-<id>-disk-N, zu deren VMID es keine Konfigurationsdatei unter /etc/pve/nodes/*/ mehr gibt. Bewusst nicht über /cluster/resources: Ein Gast auf einem abgemeldeten Node taucht dort unter Umständen nicht auf — und dann würden die Platten einer lebenden Maschine als verwaist gelten. Ohne Elternteil wird nichts von selbst entfernt, und der Schutz eines Snapshots wird nur gelöst, wenn wirklich kein Klon mehr daran hängt.

Bei anderen Storages sieht es anders aus: LVM-thin-Klone sind ohnehin unabhängig (der Thin-Pool zählt die Blöcke, das Original darf weg), bei ZFS hängt der Klon am Snapshot und ließe sich nur per zfs send | zfs recv lösen — das macht flatten nicht und meldet die Datenträger als nicht behandelt.

Der Arbeitsspeicher kommt mit

Enthält der Snapshot den Arbeitsspeicher (vmstate, in der Konfiguration snapshot_vmstate = yes), wird der mitgenommen. Die Maschine bootet dann nicht, sondern läuft genau dort weiter, wo sie beim Snapshot stand:

  • kein Crash-Recovery, kein fsck, kein Journal-Rollback
  • Datenbanken sind bereits offen und konsistent
  • die Uhr im Gast steht auf dem Snapshot-Zeitpunkt

Im Test war das nachweisbar: Die Konsole zeigte 10:38 — die Uhrzeit des Snapshots — während auf dem Host längst 11:24 war.

Damit das klappt, muss die Geräteausstattung exakt zum gespeicherten Zustand passen. pvesnap-recovery sorgt selbst dafür:

  • vmgenid und smbios1 bleiben erhalten (fehlen sie, bricht das Laden mit Unknown savevm section or instance 'vmgenid' ab)
  • runningmachine und runningcpu aus dem Snapshot werden übernommen
  • die Netzwerkkarte bleibt vorhanden, wird aber abgeklemmt (link_down=1) statt entfernt — herausnehmen würde den Zustand unbrauchbar machen
  • das Austauschlaufwerk wird erst nach dem Fortsetzen angesteckt (Hotplug), weil der Gast in einem Zustand aufwacht, in dem es die Platte noch nicht gab

Ein Detail, das Proxmox nicht selbst meldet: Schlägt das Laden des Arbeitsspeichers fehl, quittiert Proxmox den Start trotzdem mit TASK OK und lässt die Maschine angehalten stehen. pvesnap-recovery liest das Task-Protokoll mit, setzt die Maschine fort und sagt deutlich, wenn statt des RAM-Standes kalt gebootet wurde.

Mit --no-resume lässt sich der Arbeitsspeicher bewusst weglassen.

Daten aus einer Maschine ohne Netzwerk holen

Ohne Netz kommt nichts heraus — dafür gibt es das Austauschlaufwerk.

Bei virtuellen Maschinen wird eine leere, formatierte Zusatzplatte angelegt (Bezeichnung PVESNAP, mit einer kurzen LIESMICH.txt darauf):

# Snapshot abgeschottet starten, mit 20 GB Austauschplatte
pvesnap-recovery live 802 --exchange 20G

# im Gast (über die noVNC-Konsole):
mount /dev/disk/by-label/PVESNAP /mnt
mysqldump --all-databases > /mnt/dump.sql
umount /mnt && poweroff

# auf dem Host:
pvesnap-recovery pull 9802        # gibt den Pfad aus, z. B. /run/pvesnap/exchange/9802
pvesnap-recovery release 9802     # wieder lösen
pvesnap-recovery destroy 9802     # alles verwerfen

Bei Containern ist es einfacher: Ein Host-Verzeichnis wird direkt durchgereicht und erscheint im Container unter /mnt/pvesnap. Was der Container hineinschreibt, liegt sofort auf dem Host — kein Ein- und Aushängen nötig.

pvesnap-recovery live 100 --exchange ja
pct exec 9100 -- sh -c 'pg_dumpall > /mnt/pvesnap/dump.sql'
ls /var/lib/pvesnap/exchange/9100/

Und hier passt auch die Idee mit dem Netzlaufwerk: Ist auf dem Host ohnehin schon eine NFS- oder CIFS-Freigabe eingehängt, lässt sie sich direkt durchreichen — der Container schreibt dann quasi aufs Netzlaufwerk, obwohl er selbst kein Netzwerk hat:

pvesnap-recovery live 100 --exchange-dir /mnt/nfs/dumps

Bei virtuellen Maschinen geht das nicht: Ein Host-Verzeichnis lässt sich nicht in eine VM hineinreichen. Dort bleibt es bei der Austauschplatte.

An die Konsole kommen

https://<node>:8006/?console=kvm&novnc=1&vmid=9802&node=<node>&resize=off&cmd=

Diese Adresse gibt pvesnap-recovery nach dem Anlegen aus, ebenso pvesnap-recovery console <VMID>. Es ist die ganz normale noVNC-Konsole von Proxmox — die Maschine taucht auch in der Weboberfläche auf, markiert mit dem Tag pvesnap-recovery. Bei Containern geht zusätzlich pct enter <VMID>.

Wiederherstellung mit Netzwerk

pvesnap-recovery recover 802 autosnap-g5min-20260731-103800 --newid 9802

Hier bleibt alles erhalten, was die Maschine ausmacht: SMBIOS-UUID, vmgenid, MAC-Adressen, bei Containern der Hostname. Für alles im Netz ist sie dieselbe Maschine — inklusive Lizenzbindungen, AD-Mitgliedschaft und DHCP-Reservierungen.

Genau deshalb ist sie gefährlich. Zwei Maschinen mit derselben MAC und derselben IP im selben Netz geben Chaos. pvesnap-recovery prüft deshalb vorher, ob das Original läuft, und lässt sich in dem Fall nicht beiläufig durchwinken:

Situation Verhalten
ncurses-Oberfläche Zusammenfassung nur mit j, danach eine zweite Rückfrage, die den Grund beim Namen nennt
recover … im Terminal das Wort ja muss ausgeschrieben werden — j reicht nicht
recover … -y wird abgewiesen (Exit-Code 2). -y überspringt Routinefragen, nicht diese
recover … --force läuft durch — die bewusste Entscheidung

Das Original also vorher stoppen — oder mit --net down starten und die Karte erst zuschalten, wenn klar ist, dass die Luft rein ist.

Parameter

Parameter Bedeutung
live <VMID> [snapshot] abgeschottet starten (ohne Snapshot: der neueste)
recover <VMID> [snapshot] mit Netzwerk und gleicher Identität starten
--newid <ID> VMID der neuen Maschine (Vorgabe: nächste freie)
--node <name> auf welchem Node sie laufen soll
--net none|down|on keine Karte / Karte ohne Leitung / voll am Netz
--resume / --no-resume Arbeitsspeicher laden bzw. bewusst kalt starten
--exchange <größe> Austauschplatte, z. B. 20G (Container: ja genügt)
--exchange-storage <name> Storage dafür (Vorgabe: wie die erste Platte)
--exchange-fs <fs> ext4 (Vorgabe), ext3, xfs, vfat, ntfs
--exchange-dir <pfad> nur Container: dieses Host-Verzeichnis durchreichen
--memory <MB>, --cores <n> abweichende Ausstattung (nicht mit --resume)
--name <name> Name der neuen Maschine
--keep-binds durchgereichte Host-Verzeichnisse des Originals übernehmen
--no-start nur einrichten, nicht starten
-y, --yes Routinefragen überspringen (deckt --force nicht ab)
--force auch anlegen, wenn das Original noch läuft
Befehl Bedeutung
pvesnap-recovery ncurses-Oberfläche mit Übersicht und Assistent
list vorhandene Wiederherstellungen anzeigen
start / stop hoch- bzw. herunterfahren
console <VMID> noVNC-Adresse ausgeben
pull <VMID> Austauschlaufwerk auf den Host holen
release <VMID> es wieder lösen
flatten <VMID> vom Quell-Snapshot lösen (für den Dauerbetrieb)
cleanup Klone entfernen, zu denen es keinen Gast mehr gibt
destroy <VMID> restlos verwerfen

Was beim Verwerfen passiert

destroy räumt vollständig auf: Maschine stoppen, Gast samt aller Klone entfernen, Austauschverzeichnis löschen — und den Schutz der Quell-Snapshots wieder aufheben.

Dieser letzte Punkt ist wichtig: Ceph verlangt für einen Klon, dass der Quell-Snapshot geschützt ist (rbd snap protect), und Proxmox setzt das beim Klonen selbst. Bliebe der Schutz stehen, könnte die Vorhaltezeit diesen Snapshot später nicht mehr löschen — im Protokoll stünde dann immer wieder snapshot is protected. Solange eine Wiederherstellung existiert, ist ihr Quell-Snapshot also bewusst unlöschbar; danach nicht mehr.

Zur Sicherheit fasst destroy nur Maschinen an, die den Tag pvesnap-recovery tragen. Eine von Hand angelegte VM lässt sich damit nicht versehentlich löschen. uninstall.sh warnt ebenfalls, wenn noch Wiederherstellungen offen sind.


Aufbau

pvesnap/
  config.py       INI lesen und schreiben, Gruppen- und Globaleinstellungen
  schedule.py     Berechnung des nächsten Termins
  naming.py       Namensschema und Beschreibungs-Vorlagen
  proxmox.py      pvesh-Anbindung (Inventar, Snapshots anlegen/löschen)
  engine.py       Auswahl der Gäste, Anlegen, Aufräumen
  daemon.py       Hauptschleife, Signale, Sperren
  state.py        merkt sich die letzten Läufe
  preflight.py    prüft die Umgebung (root, /etc/pve beschreibbar, /root)
  cli.py          Kommandozeile
  curses_util.py  gemeinsame curses-Bausteine
  tui.py          ncurses-Konfigurationseditor
  snapfs.py       Snapshots einbinden und mounten (rbd/zfs/lvm/qcow2)
  explorer.py     Zwei-Fenster-Explorer im Terminal
  recovery.py     Snapshot als Maschine starten (Klone, Konfiguration, Aufräumen)
  recovery_ui.py  ncurses-Oberfläche und Kommandozeile dazu
  web/            Web-Oberfläche zum Herunterladen
    server.py     HTTP-Server, ZIP im Strom, Zugangsschlüssel
    assets.py     Stylesheet und HTML-Gerüst
config/pvesnap.conf.example
systemd/pvesnap.service
install.sh  uninstall.sh

Der Dienst (pvesnap) und die beiden Explorer teilen sich proxmox.py; snapfs.py liefert beiden Oberflächen einen ganz gewöhnlichen Pfad, sodass Explorer und Web-Oberfläche nichts über Ceph, ZFS oder LVM wissen müssen.

S
Description
No description provided
Readme
383 KiB
Languages
Python 94.8%
Shell 5%
CSS 0.2%