Fernwartung Download starten

Proxmox REST-API mit Python automatisieren: VMs, Backups und Cluster steuern

ProxmoxVirtualisierungLinux
Proxmox REST-API mit Python automatisieren: VMs, Backups und Cluster steuern

Die Proxmox VE-Weboberfläche ist komfortabel — aber bei 50 VMs, wiederkehrenden Aufgaben oder Multi-Cluster-Umgebungen stößt man schnell an Grenzen. Die Proxmox REST-API bietet programmatischen Zugriff auf sämtliche Funktionen: VMs erstellen, starten, stoppen, klonen, Snapshots anlegen, Backup-Jobs triggern und Cluster-Status abfragen. Mit der Python-Bibliothek proxmoxer wird die Automatisierung besonders einfach.

API-Zugang einrichten

API-Token erstellen

API-Tokens sind die empfohlene Methode für den programmatischen Zugriff. Im Gegensatz zu Benutzername/Passwort laufen Tokens nicht ab und können granulare Berechtigungen erhalten.

  1. Navigieren Sie in der Weboberfläche zu Datacenter → Permissions → API Tokens
  2. Klicken Sie auf Add:
    • User: root@pam (oder ein dedizierter API-User)
    • Token ID: automation
    • Privilege Separation: Aktiviert (empfohlen)
  3. Notieren Sie den angezeigten Token-Wert — er wird nur einmal angezeigt

Das Token-Format ist: user@realm!tokenid=token-uuid

Beispiel: root@pam!automation=a1b2c3d4-e5f6-7890-abcd-ef1234567890

Dedizierten API-User erstellen

Für Produktivumgebungen sollte ein dedizierter User mit minimalen Rechten verwendet werden:

# User erstellen
pveum user add apiuser@pve

# API-Token erstellen
pveum user token add apiuser@pve automation

# Rolle zuweisen (nur benötigte Rechte)
pveum aclmod / -user apiuser@pve -role PVEVMAdmin
pveum aclmod /storage -user apiuser@pve -role PVEDatastoreUser

Benutzerdefinierte Rolle mit minimalen Rechten

pveum role add AutomationRole -privs "VM.Allocate VM.Audit VM.Clone VM.Config.Disk VM.Config.Memory VM.Config.Network VM.Config.Options VM.Console VM.PowerMgmt VM.Snapshot Datastore.AllocateSpace Datastore.Audit"

pveum aclmod / -user apiuser@pve -role AutomationRole

proxmoxer installieren und verbinden

Installation

pip install proxmoxer requests

Verbindung mit API-Token

from proxmoxer import ProxmoxAPI

proxmox = ProxmoxAPI(
    'pve01.example.com',
    user='apiuser@pve',
    token_name='automation',
    token_value='a1b2c3d4-e5f6-7890-abcd-ef1234567890',
    verify_ssl=False  # Nur für Self-Signed Certs
)

# Verbindung testen
version = proxmox.version.get()
print(f"Proxmox VE {version['version']} (Release {version['release']})")

Verbindung mit Benutzername/Passwort

proxmox = ProxmoxAPI(
    'pve01.example.com',
    user='root@pam',
    password='geheim',
    verify_ssl=False
)

Die Token-Methode ist vorzuziehen, da sie kein Passwort im Code erfordert und die Token-UUID in einer Umgebungsvariable gespeichert werden kann.

VMs erstellen

Einfache VM erstellen

def create_vm(node, vmid, name, cores=2, memory=4096, disk_size='32G'):
    """Erstellt eine neue VM mit Grundkonfiguration."""
    proxmox.nodes(node).qemu.create(
        vmid=vmid,
        name=name,
        cores=cores,
        memory=memory,
        cpu='host',
        ostype='l26',
        scsihw='virtio-scsi-single',
        scsi0=f'local-zfs:{disk_size},iothread=1,discard=on',
        net0='virtio,bridge=vmbr0,firewall=1',
        boot='order=scsi0;ide2',
        agent='enabled=1',
        onboot=1,
        start=0  # Nicht automatisch starten
    )
    print(f"VM {vmid} ({name}) auf {node} erstellt")

# Beispiel
create_vm('pve01', 200, 'web-server-01', cores=4, memory=8192, disk_size='64G')

VM aus Template klonen

def clone_vm(node, template_id, new_vmid, name, full_clone=True):
    """Klont eine VM aus einem Template."""
    proxmox.nodes(node).qemu(template_id).clone.create(
        newid=new_vmid,
        name=name,
        full=1 if full_clone else 0,
        target=node
    )
    print(f"VM {new_vmid} ({name}) aus Template {template_id} geklont")

# Beispiel: 5 Web-Server aus Template klonen
for i in range(5):
    clone_vm('pve01', 9000, 300 + i, f'web-{i+1:02d}')

Cloud-Init-VM erstellen

def create_cloudinit_vm(node, vmid, name, template_id, ip, gateway,
                         cores=2, memory=2048, ssh_keys=None):
    """Erstellt eine VM aus Cloud-Init-Template mit Netzwerkkonfiguration."""
    # Template klonen
    proxmox.nodes(node).qemu(template_id).clone.create(
        newid=vmid,
        name=name,
        full=1
    )

    # Cloud-Init-Parameter setzen
    config = {
        'cores': cores,
        'memory': memory,
        'ipconfig0': f'ip={ip}/24,gw={gateway}',
        'nameserver': '10.0.20.1',
        'searchdomain': 'example.com',
    }
    if ssh_keys:
        config['sshkeys'] = ssh_keys

    proxmox.nodes(node).qemu(vmid).config.put(**config)
    print(f"Cloud-Init VM {vmid} ({name}) mit IP {ip} konfiguriert")

# Beispiel
create_cloudinit_vm(
    node='pve01',
    vmid=210,
    name='db-server-01',
    template_id=9001,
    ip='10.0.20.50',
    gateway='10.0.20.1',
    cores=4,
    memory=16384
)

VMs steuern: Start, Stop, Reboot

Einzelne VM steuern

def vm_action(node, vmid, action):
    """Führt eine Aktion auf einer VM aus (start, stop, reboot, shutdown, reset)."""
    endpoint = getattr(proxmox.nodes(node).qemu(vmid).status, action)
    task = endpoint.post()
    print(f"VM {vmid}: {action} ausgeführt (Task: {task})")
    return task

# Beispiele
vm_action('pve01', 200, 'start')
vm_action('pve01', 200, 'shutdown')  # ACPI Shutdown (sauber)
vm_action('pve01', 200, 'stop')      # Sofortiger Stop (wie Stecker ziehen)
vm_action('pve01', 200, 'reboot')    # ACPI Reboot

Mehrere VMs gleichzeitig starten

import time

def bulk_start(node, vmids, delay=5):
    """Startet mehrere VMs mit optionaler Verzögerung."""
    for vmid in vmids:
        try:
            status = proxmox.nodes(node).qemu(vmid).status.current.get()
            if status['status'] != 'running':
                vm_action(node, vmid, 'start')
                time.sleep(delay)
            else:
                print(f"VM {vmid} läuft bereits")
        except Exception as e:
            print(f"Fehler bei VM {vmid}: {e}")

# Alle Webserver starten
bulk_start('pve01', [300, 301, 302, 303, 304])

Auf Task-Abschluss warten

import time

def wait_for_task(node, task_id, timeout=300):
    """Wartet auf den Abschluss eines Proxmox-Tasks."""
    start = time.time()
    while time.time() - start < timeout:
        task_status = proxmox.nodes(node).tasks(task_id).status.get()
        if task_status['status'] == 'stopped':
            if task_status.get('exitstatus') == 'OK':
                print(f"Task {task_id} erfolgreich abgeschlossen")
                return True
            else:
                print(f"Task {task_id} fehlgeschlagen: {task_status.get('exitstatus')}")
                return False
        time.sleep(2)
    print(f"Task {task_id} Timeout nach {timeout}s")
    return False

Cluster-Status abfragen

Cluster-Übersicht

def get_cluster_status():
    """Zeigt den Cluster-Status aller Nodes."""
    nodes = proxmox.nodes.get()
    print(f"{'Node':<15} {'Status':<10} {'CPU':<10} {'RAM':<15} {'Uptime':<12}")
    print("-" * 62)
    for node in nodes:
        cpu_pct = f"{node['cpu'] * 100:.1f}%"
        ram_used = node['mem'] / (1024**3)
        ram_total = node['maxmem'] / (1024**3)
        ram_str = f"{ram_used:.1f}/{ram_total:.1f} GB"
        uptime_days = node['uptime'] // 86400
        print(f"{node['node']:<15} {node['status']:<10} {cpu_pct:<10} "
              f"{ram_str:<15} {uptime_days} Tage")

get_cluster_status()

Beispielausgabe:

Node            Status     CPU        RAM             Uptime
--------------------------------------------------------------
pve01           online     23.4%      48.2/128.0 GB   142 Tage
pve02           online     31.7%      62.1/128.0 GB   142 Tage
pve03           online     18.9%      35.8/128.0 GB   89 Tage

VM-Inventar über alle Nodes

def get_all_vms():
    """Listet alle VMs im Cluster mit Status und Ressourcen."""
    vms = []
    for node in proxmox.nodes.get():
        for vm in proxmox.nodes(node['node']).qemu.get():
            vms.append({
                'node': node['node'],
                'vmid': vm['vmid'],
                'name': vm.get('name', 'unnamed'),
                'status': vm['status'],
                'cpu': vm.get('cpus', 0),
                'mem_gb': vm.get('maxmem', 0) / (1024**3),
                'disk_gb': vm.get('maxdisk', 0) / (1024**3),
            })
    return sorted(vms, key=lambda x: x['vmid'])

# Als Tabelle ausgeben
vms = get_all_vms()
for vm in vms:
    print(f"[{vm['node']}] VM {vm['vmid']}: {vm['name']} "
          f"({vm['status']}, {vm['cpu']} CPU, {vm['mem_gb']:.0f} GB RAM)")

Snapshots verwalten

def create_snapshot(node, vmid, name, description='', include_ram=False):
    """Erstellt einen Snapshot einer VM."""
    proxmox.nodes(node).qemu(vmid).snapshot.create(
        snapname=name,
        description=description,
        vmstate=1 if include_ram else 0
    )
    print(f"Snapshot '{name}' für VM {vmid} erstellt")

def list_snapshots(node, vmid):
    """Listet alle Snapshots einer VM."""
    snapshots = proxmox.nodes(node).qemu(vmid).snapshot.get()
    for snap in snapshots:
        if snap['name'] != 'current':
            print(f"  {snap['name']}: {snap.get('description', '')} "
                  f"({snap.get('snaptime', 'N/A')})")

def rollback_snapshot(node, vmid, name):
    """Rollt eine VM auf einen Snapshot zurück."""
    proxmox.nodes(node).qemu(vmid).snapshot(name).rollback.post()
    print(f"VM {vmid} auf Snapshot '{name}' zurückgesetzt")

# Vor Update: Snapshot erstellen
create_snapshot('pve01', 200, 'pre-update-2026-04',
                description='Vor Kernel-Update')

Backup-Jobs automatisieren

Einzelnes Backup starten

def backup_vm(node, vmid, storage='pbs-backup', mode='snapshot',
              compress='zstd'):
    """Startet ein Backup einer VM."""
    task = proxmox.nodes(node).vzdump.create(
        vmid=vmid,
        storage=storage,
        mode=mode,
        compress=compress,
        notes_template='{{guestname}} - API Backup {{date}}'
    )
    print(f"Backup für VM {vmid} gestartet (Task: {task})")
    return task

backup_vm('pve01', 200)

Alle VMs einer Gruppe sichern

def backup_vms_by_tag(tag, storage='pbs-backup'):
    """Sichert alle VMs mit einem bestimmten Tag/Pool."""
    vms = get_all_vms()
    for vm in vms:
        if vm['status'] == 'running':
            config = proxmox.nodes(vm['node']).qemu(vm['vmid']).config.get()
            if tag in config.get('tags', ''):
                print(f"Backup: VM {vm['vmid']} ({vm['name']}) auf {vm['node']}")
                backup_vm(vm['node'], vm['vmid'], storage=storage)

# Alle VMs mit Tag "production" sichern
backup_vms_by_tag('production')

Storage-Status abfragen

def get_storage_status():
    """Zeigt den Storage-Status aller Nodes."""
    for node_info in proxmox.nodes.get():
        node = node_info['node']
        print(f"\n=== {node} ===")
        storages = proxmox.nodes(node).storage.get()
        for s in storages:
            if s.get('active'):
                used_pct = (s.get('used', 0) / s.get('total', 1)) * 100
                total_tb = s.get('total', 0) / (1024**4)
                used_tb = s.get('used', 0) / (1024**4)
                print(f"  {s['storage']:<20} {used_tb:.2f}/{total_tb:.2f} TB "
                      f"({used_pct:.1f}%) [{s['type']}]")

get_storage_status()

Praxisbeispiel: Deployment-Script

Ein vollständiges Script, das eine Umgebung aus mehreren VMs erstellt:

#!/usr/bin/env python3
"""Proxmox Deployment Script: Web-Applikation mit DB und Load Balancer."""

import os
import sys
import time
from proxmoxer import ProxmoxAPI

# Konfiguration aus Umgebungsvariablen
PVE_HOST = os.environ.get('PVE_HOST', 'pve01.example.com')
PVE_USER = os.environ.get('PVE_USER', 'apiuser@pve')
PVE_TOKEN_NAME = os.environ.get('PVE_TOKEN_NAME', 'automation')
PVE_TOKEN_VALUE = os.environ['PVE_TOKEN_VALUE']

TEMPLATE_ID = 9001  # Debian 12 Cloud-Init Template
NETWORK = '10.0.20'
GATEWAY = '10.0.20.1'

DEPLOYMENT = [
    {'vmid': 400, 'name': 'lb-01',  'ip': f'{NETWORK}.40', 'cores': 2, 'mem': 2048},
    {'vmid': 401, 'name': 'web-01', 'ip': f'{NETWORK}.41', 'cores': 4, 'mem': 4096},
    {'vmid': 402, 'name': 'web-02', 'ip': f'{NETWORK}.42', 'cores': 4, 'mem': 4096},
    {'vmid': 403, 'name': 'db-01',  'ip': f'{NETWORK}.43', 'cores': 4, 'mem': 8192},
]

def main():
    proxmox = ProxmoxAPI(PVE_HOST, user=PVE_USER,
                          token_name=PVE_TOKEN_NAME,
                          token_value=PVE_TOKEN_VALUE,
                          verify_ssl=False)

    node = 'pve01'
    for vm in DEPLOYMENT:
        print(f"Erstelle {vm['name']} (VMID {vm['vmid']})...")
        proxmox.nodes(node).qemu(TEMPLATE_ID).clone.create(
            newid=vm['vmid'], name=vm['name'], full=1)
        time.sleep(3)

        proxmox.nodes(node).qemu(vm['vmid']).config.put(
            cores=vm['cores'], memory=vm['mem'],
            ipconfig0=f"ip={vm['ip']}/24,gw={GATEWAY}",
            tags='webapp;production')

        proxmox.nodes(node).qemu(vm['vmid']).status.start.post()
        print(f"  {vm['name']} gestartet mit IP {vm['ip']}")

    print("\nDeployment abgeschlossen.")

if __name__ == '__main__':
    main()

Sicherheitshinweise

  • Tokens statt Passwörter: Verwenden Sie immer API-Tokens mit minimalen Rechten
  • Umgebungsvariablen: Speichern Sie Token-Werte nie im Code, sondern in Umgebungsvariablen oder einem Secret Manager
  • TLS verifizieren: Setzen Sie verify_ssl=True und verwenden Sie gültige Zertifikate in Produktivumgebungen
  • Audit-Log: Proxmox protokolliert alle API-Zugriffe — prüfen Sie regelmäßig /var/log/pveproxy/access.log
  • Rate Limiting: Begrenzen Sie API-Aufrufe in Ihren Scripts, um den Cluster nicht zu überlasten

Fazit

Die Proxmox REST-API mit proxmoxer macht Infrastruktur-Automatisierung zugänglich. Ob VM-Deployments, Backup-Orchestrierung oder Cluster-Monitoring — Python-Scripts ersetzen repetitive manuelle Arbeit in der Weboberfläche und ermöglichen reproduzierbare, versionierte Infrastruktur. Die Kombination aus API-Tokens mit minimalen Rechten und Umgebungsvariablen für Credentials hält die Automatisierung sicher.

IT-Beratung gewünscht?

Kontaktieren Sie uns für eine unverbindliche Beratung zu Proxmox, OPNsense, TrueNAS und mehr.

Jetzt Kontakt aufnehmen