Die Proxmox Web-UI ist komfortabel, aber für wiederholbare Deployments ist die Kommandozeile unschlagbar. Mit qm (QEMU Manager) lassen sich VMs in Sekunden aus Templates erstellen, per Cloud-Init konfigurieren und auf beliebigen Storage deployen.
VM-Erstellung per CLI: Schnell, reproduzierbar und automatisierbar
Warum CLI statt Web-UI?
%%{init: {'theme': 'dark'}}%%
flowchart LR
subgraph GUI["Web-UI"]
A1[Klicken] --> A2[Warten]
A2 --> A3[Klicken]
A3 --> A4[Eingeben]
A4 --> A5[Klicken...]
end
subgraph CLI["Kommandozeile"]
B1[Ein Befehl] --> B2[Fertig]
end
style GUI fill:#f7768e,stroke:#f7768e
style CLI fill:#9ece6a,stroke:#9ece6a
| Aspekt |
Web-UI |
CLI |
| Geschwindigkeit |
Viele Klicks |
Ein Befehl |
| Reproduzierbarkeit |
Manuell |
Skriptbar |
| Automatisierung |
Nicht möglich |
Ideal |
| Dokumentation |
Screenshots |
Code |
| Fehleranfälligkeit |
Höher |
Geringer |
Voraussetzungen
Bevor es losgeht, benötigst du:
- Proxmox VE (getestet mit 8.x)
- SSH-Zugang zum Proxmox-Node (als root)
- Ein VM-Template (z.B. Debian 12 mit Cloud-Init)
- Storage für die neue VM (lokal, NFS, Ceph, etc.)
Tipp: Templates werden in Proxmox durch Rechtsklick → “Convert to Template” erstellt. Die Template-ID sollte leicht erkennbar sein (z.B. 9xxxxx für Templates).
Das qm-Kommando
qm ist das zentrale Tool für VM-Management in Proxmox:
1
2
3
4
5
6
7
8
9
10
11
| # Hilfe anzeigen
qm help
# Alle VMs auflisten
qm list
# Status einer VM
qm status <vmid>
# VM-Konfiguration anzeigen
qm config <vmid>
|
Wichtige qm-Befehle im Überblick
| Befehl |
Beschreibung |
qm list |
Alle VMs auflisten |
qm clone |
VM aus Template klonen |
qm set |
VM-Konfiguration ändern |
qm start |
VM starten |
qm stop |
VM stoppen |
qm destroy |
VM löschen |
qm resize |
Disk vergrößern |
VM aus Template erstellen
Grundlegender Clone-Befehl
1
| qm clone <template-id> <neue-vmid> --name <vm-name>
|
Beispiel:
1
| qm clone 940002 100 --name webserver-prod
|
Dies erstellt eine Linked Clone - schnell, aber abhängig vom Template.
Full Clone (unabhängige Kopie)
Für eine vollständig unabhängige VM mit --full:
1
| qm clone 940002 100 --name webserver-prod --full
|
%%{init: {'theme': 'dark'}}%%
flowchart TB
subgraph linked["Linked Clone"]
T1[Template Disk] --> L1[Clone 1]
T1 --> L2[Clone 2]
T1 --> L3[Clone 3]
end
subgraph full["Full Clone"]
T2[Template] -.->|Kopie| F1[Clone 1]
T2 -.->|Kopie| F2[Clone 2]
T2 -.->|Kopie| F3[Clone 3]
end
style linked fill:#7aa2f7,stroke:#7aa2f7
style full fill:#9ece6a,stroke:#9ece6a
| Typ |
Vorteile |
Nachteile |
| Linked Clone |
Schnell, platzsparend |
Abhängig vom Template |
| Full Clone |
Unabhängig, portabel |
Langsamer, mehr Speicher |
Storage auswählen
Standard-Storage verwenden
Ohne Angabe wird der Storage des Templates verwendet:
1
| qm clone 940002 100 --name myvm --full
|
Anderen Storage angeben
Mit --storage auf spezifischen Storage deployen:
1
| qm clone 940002 100 --name myvm --full --storage local-lvm
|
Verfügbare Storages anzeigen:
Ausgabe:
1
2
3
4
5
| Name Type Status Total Used Available %
local dir active 98041 7489 85510 7.64%
local-lvm lvmthin active 392908 39290 353617 10.00%
local-ssd lvmthin active 476928 95385 381542 20.00%
nas nfs active 3806528 286336 3520191 7.53%
|
Storage-Typen
| Typ |
Beschreibung |
Empfehlung |
local |
Lokales Verzeichnis |
Backups, ISOs |
local-lvm |
LVM Thin Pool |
Standard-VMs |
local-ssd |
LVM auf SSD/NVMe |
Performance-kritische VMs |
nfs / cifs |
Netzwerk-Share |
Shared Storage |
ceph |
Distributed Storage |
HA-Cluster |
zfs |
ZFS Pool |
Snapshots |
Cloud-Init Konfiguration
Cloud-Init ermöglicht die automatische Erstkonfiguration der VM beim Start.
IP-Adresse setzen
1
| qm set <vmid> --ipconfig0 ip=<ip>/<cidr>,gw=<gateway>
|
Beispiel mit statischer IP:
1
| qm set 100 --ipconfig0 ip=192.168.1.100/24,gw=192.168.1.1
|
DHCP verwenden:
1
| qm set 100 --ipconfig0 ip=dhcp
|
DNS-Server setzen
1
2
| qm set 100 --nameserver "8.8.8.8 8.8.4.4"
qm set 100 --searchdomain "example.com"
|
SSH-Keys hinzufügen
1
| qm set 100 --sshkeys ~/.ssh/id_ed25519.pub
|
Hinweis: Der SSH-Key muss URL-encoded sein bei Sonderzeichen. Alternativ aus Datei lesen.
User und Passwort
1
2
| qm set 100 --ciuser admin
qm set 100 --cipassword "geheimes-passwort"
|
Sicherheit: Passwörter im Klartext vermeiden! Besser: SSH-Keys verwenden.
Cloud-Init Snippets
Für komplexere Konfigurationen verwendet man Cloud-Init Snippets - YAML-Dateien mit erweiterten Einstellungen.
Snippet-Verzeichnis
Snippets werden auf einem Storage mit Content-Type snippets abgelegt:
1
2
3
4
5
6
7
| # Snippet-fähige Storages anzeigen
pvesm status | grep snippets
# Typischer Pfad
ls /var/lib/vz/snippets/
# oder bei NFS
ls /mnt/pve/<storage-name>/snippets/
|
User-Data Snippet erstellen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| #cloud-config
# Datei: /mnt/pve/nas/snippets/debian-config.yml
# Pakete installieren
packages:
- qemu-guest-agent
- git
- curl
- vim
# Dienste aktivieren
runcmd:
- systemctl enable qemu-guest-agent
- systemctl start qemu-guest-agent
# Timezone setzen
timezone: Europe/Berlin
# Locale setzen
locale: de_DE.UTF-8
|
Snippet der VM zuweisen
1
| qm set 100 --cicustom "user=<storage>:snippets/<datei>.yml"
|
Beispiel:
1
| qm set 100 --cicustom "user=nas:snippets/debian-config.yml"
|
Snippet-Typen
| Typ |
Beschreibung |
Parameter |
user |
User-Data (Pakete, Befehle) |
user=storage:snippets/file.yml |
network |
Netzwerk-Konfiguration |
network=storage:snippets/net.yml |
meta |
Meta-Daten |
meta=storage:snippets/meta.yml |
Mehrere Snippets kombinieren:
1
| qm set 100 --cicustom "user=nas:snippets/user.yml,network=nas:snippets/network.yml"
|
Disk-Größe anpassen
Disk vergrößern
1
| qm resize <vmid> <disk> <größe>
|
Beispiele:
1
2
3
4
5
| # Auf 50 GB setzen
qm resize 100 scsi0 50G
# Um 20 GB erweitern
qm resize 100 scsi0 +20G
|
Wichtig: Die Partition im Gast-System muss ebenfalls angepasst werden (z.B. mit growpart und resize2fs).
1
| qm config 100 | grep -E "^(scsi|virtio|ide|sata)"
|
Ausgabe:
1
| scsi0: nas:100/vm-100-disk-0.qcow2,size=32G
|
VM starten und verwalten
VM starten
Status prüfen
Ausgabe:
Auf Boot warten
Nach dem Start braucht die VM Zeit zum Booten. Ein einfacher Check:
1
2
3
4
5
6
| # Warten bis SSH erreichbar
while ! ssh -o ConnectTimeout=2 user@192.168.1.100 "echo OK" 2>/dev/null; do
echo "Warte auf VM..."
sleep 5
done
echo "VM ist bereit!"
|
VM stoppen
1
2
3
4
5
| # Graceful shutdown
qm shutdown 100
# Sofort stoppen (wie Stecker ziehen)
qm stop 100
|
VM löschen
1
2
3
| # VM muss gestoppt sein
qm stop 100
qm destroy 100
|
Mit Disks löschen:
Komplettes Beispiel
Ein vollständiger Workflow für eine neue Webserver-VM:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| #!/bin/bash
# deploy-webserver.sh
# Variablen
TEMPLATE=940002
VMID=100
NAME="webserver-prod"
IP="192.168.1.100"
GW="192.168.1.1"
STORAGE="local-lvm"
DISK_SIZE="50G"
SNIPPET="nas:snippets/debian-config.yml"
# 1. VM aus Template klonen
echo "Erstelle VM $NAME ($VMID)..."
qm clone $TEMPLATE $VMID --name $NAME --full --storage $STORAGE
# 2. Cloud-Init konfigurieren
echo "Konfiguriere Cloud-Init..."
qm set $VMID --ipconfig0 ip=$IP/24,gw=$GW
qm set $VMID --cicustom "user=$SNIPPET"
# 3. Disk vergrößern
echo "Vergrößere Disk auf $DISK_SIZE..."
qm resize $VMID scsi0 $DISK_SIZE
# 4. VM starten
echo "Starte VM..."
qm start $VMID
echo "VM $NAME erfolgreich erstellt!"
echo "IP-Adresse: $IP"
|
%%{init: {'theme': 'dark'}}%%
sequenceDiagram
participant Admin
participant Proxmox
participant Storage
participant VM
Admin->>Proxmox: qm clone (Template → VM)
Proxmox->>Storage: Disk kopieren
Storage-->>Proxmox: Disk erstellt
Admin->>Proxmox: qm set (Cloud-Init)
Proxmox->>Proxmox: Config speichern
Admin->>Proxmox: qm resize
Proxmox->>Storage: Disk vergrößern
Admin->>Proxmox: qm start
Proxmox->>VM: Boot
VM->>VM: Cloud-Init ausführen
VM-->>Admin: SSH bereit
Hardware anpassen
CPU und RAM
1
2
3
4
5
6
7
8
9
10
11
| # CPU-Kerne setzen
qm set 100 --cores 4
# Sockets setzen
qm set 100 --sockets 1
# RAM setzen (in MB)
qm set 100 --memory 4096
# Ballooning aktivieren
qm set 100 --balloon 2048
|
Netzwerk
1
2
3
4
5
6
7
8
| # Netzwerk-Interface hinzufügen
qm set 100 --net0 virtio,bridge=vmbr0
# VLAN setzen
qm set 100 --net0 virtio,bridge=vmbr0,tag=100
# MAC-Adresse festlegen
qm set 100 --net0 virtio,bridge=vmbr0,macaddr=BC:24:11:00:00:01
|
QEMU Guest Agent
Für bessere Integration mit Proxmox:
1
| qm set 100 --agent enabled=1
|
Tipp: Der Guest Agent muss im Gast-System installiert sein (qemu-guest-agent).
Cluster-Überlegungen
VM auf bestimmtem Node erstellen
Der Clone-Befehl wird auf dem Node ausgeführt, auf dem die VM erstellt wird:
1
2
| # Auf Node "gandalf" ausführen
ssh root@gandalf "qm clone 940002 100 --name myvm --full"
|
VM zwischen Nodes migrieren
1
| qm migrate 100 <ziel-node>
|
Online-Migration (ohne Downtime):
1
| qm migrate 100 gandalf --online
|
Best Practices
Namenskonventionen für VMIDs
| Bereich |
VMIDs |
Verwendung |
| 100-199 |
Produktiv-VMs |
|
| 200-299 |
Entwicklung |
|
| 900000+ |
Templates |
z.B. 940002 = Debian 12 |
Template-Notes nutzen
Hilfreiche Informationen in den Template-Notes speichern:
1
2
3
4
5
6
7
8
9
10
11
12
| qm set 940002 --description "# Debian 12 Template
## Quick Deploy
\`\`\`bash
qm clone 940002 <VMID> --name <NAME> --full
\`\`\`
## Cloud-Init Snippet
\`\`\`bash
qm set <VMID> --cicustom user=nas:snippets/debian-config.yml
\`\`\`
"
|
Automatisierung mit Ansible
Für komplexere Setups empfiehlt sich Ansible mit dem community.general.proxmox_kvm Modul:
1
2
3
4
5
6
7
8
9
10
11
| - name: VM aus Template erstellen
community.general.proxmox_kvm:
api_host: proxmox.example.com
api_user: root@pam
api_token_id: ansible
api_token_secret: ""
clone: debian-12-template
name: webserver
newid: 100
full: true
storage: local-lvm
|
Fehlerbehebung
Häufige Fehler
| Fehler |
Ursache |
Lösung |
VM is locked |
VM wird bearbeitet |
qm unlock <vmid> |
storage not found |
Falscher Storage-Name |
pvesm status prüfen |
VMID already exists |
ID vergeben |
Andere VMID wählen |
Cloud-Init not available |
Kein Cloud-Init-Drive |
Template prüfen |
Logs prüfen
1
2
3
4
5
| # Proxmox Task-Log
journalctl -u pvedaemon
# VM-spezifisches Log
cat /var/log/pve/tasks/active
|
Zusammenfassung
Die wichtigsten Befehle auf einen Blick:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # VM erstellen
qm clone <template> <vmid> --name <name> --full --storage <storage>
# Cloud-Init
qm set <vmid> --ipconfig0 ip=<ip>/<cidr>,gw=<gw>
qm set <vmid> --cicustom "user=<storage>:snippets/<file>.yml"
# Disk vergrößern
qm resize <vmid> scsi0 <size>
# VM starten
qm start <vmid>
# VM löschen
qm stop <vmid> && qm destroy <vmid>
|
Mit diesen Befehlen lassen sich VMs in Sekunden deployen - reproduzierbar, dokumentiert und automatisierbar. Die Kombination aus Templates und Cloud-Init macht das Setup neuer Systeme zum Kinderspiel.
Weiterführende Links