Der Anlass: ein Software-Schutzmodul am USB-Port. Normalerweise haengt so ein Dongle an einem USB-Server im Netz - eine abgeschottete Wiederherstellung hat aber keins. Ueber SPICE kommt das Geraet vom Rechner des Bedieners, nicht ueber das Gastnetz. Die Maschine bleibt also ohne Netzwerk und hat trotzdem ihren Dongle. --spice SPICE-Anzeige (vga: qxl), zusaetzlich zu noVNC --usb <n> so viele USB-Weiterleitungen --iso <volid> Abbild als CD einlegen spice <vmid> Verbindungsdatei fuer remote-viewer (.vv) Zwei Dinge zeigte erst der Test, beide haetten die Sache still unbrauchbar gemacht: vga: qxl zerstoert den geladenen Arbeitsspeicher. qxl hat 64 MB Grafikspeicher, die Vorgabe 16 - beim Laden kommt "Size mismatch: vga.vram", und die Maschine bleibt angehalten stehen. Wieder mit TASK OK. Wird jetzt abgelehnt, mit den drei Auswegen in der Meldung. Der dauerhafte ist, am Original 'vga: qxl' zu setzen - dann tragen alle kuenftigen Snapshots es mit und beides geht gleichzeitig. USB ohne SPICE ist wirkungslos. QEMU legt die usbredir-Geraete zwar an, aber ohne SPICE-Server gibt es keinen Kanal dafuer - spiceproxy sagt schlicht "no spice port". --usb schaltet die Anzeige deshalb mit ein. Ausserdem korrigiert: in der .vv-Datei darf das Zertifikat nicht in echte Zeilenumbrueche uebersetzt werden. virt-viewer erwartet die Zeichenfolge \n als zwei Zeichen in einer einzigen Zeile; sonst steht nur die erste hinter "ca=". tools/get-guest-tools.sh holt virtio-win auf einen ISO-Storage. Fuer den Dongle wird davon nichts gebraucht - die Tools sind nur fuer Zwischenablage, Aufloesung und Mauszeiger. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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 Commanderpvesnap-web— im Browser durchsehen und herunterladen, auch vom anderen Rechnerpvesnap-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
- Gruppenliste —
Enterbearbeiten,nneu,ckopieren,dlöschen,Leertastean/aus,gglobale Einstellungen,vÜbersicht welche VM in welcher Gruppe landet,sspeichern,rDienst neu laden,qEnde r— Dienst neu laden, ohne den Editor zu verlassen: entsprichtsystemctl reload pvesnap. Ungespeicherte Änderungen werden vorher zum Speichern angeboten, ein gestoppter Dienst zum Starten, und wenn das Neuladen scheitert, wird ein Neustart angeboten. Nachsfragt der Editor ohnehin gleich, ob neu geladen werden soll. Oben in der Kopfzeile steht jederzeit, ob der Dienst läuft. (Braucht root — alsosudo pvesnap config.)- Gruppe bearbeiten — Feld auswählen,
Enterändern,Leertasteumschalten. 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;Leertasteauswählen,aalle,nkeine,iumkehren,/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 alspvesnap.conf.bakabgelegt.
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äglich → taeglich). 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 = yesfriert 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 mitretry_delayAbstand wiederholt. Echte Fehler (etwa „storage does not support snapshots") werden nicht wiederholt. - Mit
pause_between = 10slä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 inweb.conf--bind 127.0.0.1setzen.
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 überpvesnap-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 dutäuschen lassen. Die Zeile eines Snapshots zeigt nur dessen Zuwachs, nicht seinen Inhalt. Im Test stand@handtest01mitUSED 56 MiBda — kopiert werden beim Flatten trotzdem über 8 GB, denn sichtbar ist an dieser Stelle der gesamte Inhalt der Kette (<TOTAL> 14 GiB).pvesnap-recovery flattenmisst 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 — und bleibt voll beschreibbar. rbd flatten
ist eine Online-Operation. 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.
Auch Daten, die während des Abkoppelns geschrieben werden, überleben es. Gemessen an einem Container, der durchgehend schrieb:
| vor dem Flatten geschrieben | 64 MB Zufallsdaten, SHA-256 danach OK |
| während des Flatten geschrieben | 192 MB Zufallsdaten, SHA-256 danach OK |
| Schreibvorgänge im Zeitfenster | 12, von 19:35:48 bis 19:36:10 (Flatten: 19:35:48–19:36:11) |
| Zustand des Gastes | durchgehend running |
Der Grund: rbd flatten füllt nur die Blöcke auf, die der Klon noch nicht
selbst besitzt. Was der Gast bereits geschrieben hat, gehört ihm — und wird
nicht überschrieben.
Warum das kein „Live-Restore" ist, sondern besser
Beim Live-Restore des Proxmox Backup Servers liegt das Backup auf einem anderen Medium: Die VM startet sofort, holt die Blöcke aber im Hintergrund übers Netz nach und läuft bis dahin gebremst.
Hier wird gar nichts nachgeladen. Der Klon liegt im selben Pool und ist aus Sicht des Gastes von Sekunde eins an vollständig — bei voller Geschwindigkeit. Und weil Copy-on-Write nichts kopiert, ist er unabhängig von der Größe in etwa einer Sekunde fertig:
Klon ~1 s egal ob 32 GB oder 2 TB
Start Sekunden mit RAM-Zustand sofort im laufenden Zustand
Arbeiten ab jetzt voll beschreibbar
flatten nebenher optional, im laufenden Betrieb
Bei einer 2-TB-VM wird also nicht stundenlang kopiert und dann gestartet —
gearbeitet wird ab der ersten Sekunde, das Abkoppeln läuft im Hintergrund mit.
flatten betrifft ausschließlich die Abhängigkeit vom Quell-Snapshot, nie
die Verfügbarkeit.
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.
Und wenn die Maschine nicht auf Ceph liegt?
Das ganze Thema „Abhängigkeit vom Quell-Snapshot" ist eine Ceph-Eigenheit. Andere Storages verhalten sich anders:
| Storage | Klon aus Snapshot | Hängt am Quell-Snapshot? | flatten |
|---|---|---|---|
rbd (Ceph) |
rbd clone, sofort |
ja — Snapshot wird geschützt und unlöschbar | nötig für den Dauerbetrieb |
lvmthin |
lvcreate -s, sofort |
nein | nicht nötig |
zfspool |
zfs clone, sofort |
ja | nicht möglich (nur zfs send | zfs recv) |
lvm (dick) |
— | — | PVE kann dort gar keine Snapshots |
dir, nfs, cifs |
— | — | kein Klon aus qcow2-Snapshots möglich |
LVM-thin ist in diesem Punkt sogar angenehmer als Ceph. Ein Thin-Snapshot ist ein eigenständiges Volume, das sich mit anderen nur die Blöcke im Pool teilt — nachgemessen:
Belegung im Thin-Pool nach dem Klonen (256 MB Nutzdaten):
data <19.84g 1.26 % ← Pool hält die Daten nur EINMAL
snap_..._wdhtest 1.00g
vm-9998-disk-0 1.00g 25.00 % Klon
vm-9999-disk-0 1.00g 25.00 % Original
Quell-Snapshot löschen, während der Klon existiert → erlaubt
Original löschen → erlaubt
Prüfsumme des Klons danach → unverändert
Also: platzsparend geteilt und trotzdem frei löschbar. Es gibt dort weder
das Problem mit geschützten Snapshots noch etwas zu flatten — flatten meldet
solche Datenträger entsprechend als „nicht nötig".
Der Preis ist ein anderer: lvmthin ist lokaler Speicher. Die
Wiederherstellung muss auf demselben Node laufen wie das Original;
pvesnap-recovery prüft das und lehnt einen anderen Node ab. Mit Ceph ist sie
dagegen auf jedem Node des Clusters startbar.
Und ein Warnhinweis, der für Thin-Pools genauso gilt wie für Ceph: Läuft der Thin-Pool voll, stehen alle Volumes darin. Überprovisionierung im Blick behalten.
Bei ZFS hängt der Klon wie bei Ceph am Snapshot, aber zfs promote würde
die Abhängigkeit nur umdrehen statt auflösen. Echte Unabhängigkeit ginge dort
nur über eine Vollkopie per zfs send | zfs recv — das macht flatten nicht
und sagt es auch so.
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:
vmgenidundsmbios1bleiben erhalten (fehlen sie, bricht das Laden mitUnknown savevm section or instance 'vmgenid'ab)runningmachineundrunningcpuaus dem Snapshot werden übernommen- die Netzwerkkarte bleibt vorhanden, wird aber abgeklemmt (
link_down=1) statt entfernt — herausnehmen würde den Zustand unbrauchbar machen - Transfer-Laufwerke werden 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 hinein und wieder heraus — Transfer-Laufwerke
Ein wiederhergestellter Snapshot hat kein Netzwerk. Dafür gibt es
Transfer-Laufwerke: benannte Abbilddateien unter
/var/lib/pvesnap/transfer/, die du in Ruhe vorher anlegst und befüllst
und im Notfall nur noch aus einer Liste auswählst.
pvesnap-recovery
v Übersicht der Laufwerke
n "dumps", 20G ← einmalig
Enter Commander: Werkzeuge hineinkopieren
q q
n Wiederherstellung, Snapshot wählen
Transfer-Laufwerke: [dumps] ← Leertaste
F10 läuft
...arbeiten... im Gast: Datenträger DUMPS
e auswerfen, am Host auslesen, wieder einklinken
h herunterfahren
v Enter Commander: Ergebnis abholen
Kein einziger Parameter. Auf der Kommandozeile ginge es auch:
--transfer dumps, mehrfach möglich.
| Eigenschaft | |
|---|---|
| Dateisystem | exFAT — Windows und Linux nativ, keine 4-GB-Grenze je Datei |
| Partition | GPT mit msftdata, damit Windows sofort einen Laufwerksbuchstaben vergibt |
| Bezeichnung | der Name in Großbuchstaben, z. B. DUMPS (max. 11 Zeichen) |
| Lebensdauer | überlebt jede Wiederherstellung — auch das Löschen der VM in der Weboberfläche |
Warum eine Datei und kein Proxmox-Volume? Ein Volume würde beim Entfernen
der Maschine mitgelöscht, auch aus der Weboberfläche heraus — die mühsam
vorbereitete Werkzeugsammlung wäre weg. Pfade überspringt PVE beim Zerstören
ausdrücklich (return if $volid =~ m|^/|). Angehängt wird über ein
Loop-Gerät, weil Proxmox als Pfad nur /dev/… akzeptiert.
Host oder Gast, nie beides. Zwei unabhängige Einhängungen desselben Blockgeräts zerlegen das Dateisystem. Die Verwaltung lässt das nicht zu: Anhängen wird abgelehnt, solange der Host es hält; Aushängen, solange ein Gast darauf arbeitet; Löschen, solange es überhaupt in Benutzung ist.
Bei Containern ist es kein Blockgerät, sondern ein durchgereichtes Verzeichnis. Host und Container sehen dieselben Dateien gleichzeitig — dort gibt es nichts auszuwerfen und nichts zu warten.
Im laufenden Betrieb wechseln
Taste e in der Detailansicht zieht das Laufwerk bei laufender Maschine ab
und gibt es wieder hinein — beliebig oft:
auswerfen → gehört wieder dem Host, einhängen und befüllen
einklinken → zurück in denselben Steckplatz, VM läuft durchgehend
Im Gast vorher aushängen. Unter Linux
umount, unter Windows „Auswerfen" im Explorer. Proxmox meldet das Gerät zwar ordentlich ab, aber ein Dateisystem, auf das gerade geschrieben wird, nimmt das übel. Hält der Gast es fest, schlägt das Auswerfen mit einer entsprechenden Meldung fehl.
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 |
--transfer <name> |
vorbereitetes Transfer-Laufwerk anhängen (mehrfach möglich) |
--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 |
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
transfer.py Transfer-Laufwerke: anlegen, ein-/aushängen, Verriegelung
transfer_ui.py deren Bildschirm, auch aus dem Explorer erreichbar
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.