Introduction

Proxmox VE is an open-source virtualization platform for KVM virtual machines and LXC containers. The community.general collection provides modules to automate Proxmox through its REST API — create VMs from templates, manage LXC containers, handle storage, snapshots, and cluster operations. This article covers the complete Proxmox automation workflow with Ansible.

Prerequisites

# Install the collection
ansible-galaxy collection install community.general

# Install Python dependency
pip install proxmoxer requests

Connection Variables

# group_vars/proxmox.yml (encrypt sensitive values with Vault)
proxmox_host: pve.example.com
proxmox_user: root@pam
proxmox_password: "{{ vault_proxmox_password }}"
# Or use API token (recommended)
proxmox_api_user: ansible@pve
proxmox_api_token_id: automation
proxmox_api_token_secret: "{{ vault_proxmox_token }}"

Create API Token in Proxmox

# On Proxmox host
pveum user add ansible@pve
pveum aclmod / -user ansible@pve -role PVEAdmin
pveum user token add ansible@pve automation --privsep=0
# Save the token value — shown only once

Module Reference

ModuleDescription
community.general.proxmoxManage LXC containers
community.general.proxmox_kvmManage KVM virtual machines
community.general.proxmox_templateManage VM/CT templates
community.general.proxmox_snapManage snapshots
community.general.proxmox_diskManage VM disks
community.general.proxmox_nicManage VM network interfaces
community.general.proxmox_storage_infoQuery storage information
community.general.proxmox_tasks_infoQuery task status

Create a KVM Virtual Machine

From Template (Clone)

---
- name: Create VM from template
  hosts: localhost
  gather_facts: false
  vars:
    proxmox_host: pve.example.com
    proxmox_api_user: ansible@pve
    proxmox_api_token_id: automation
    proxmox_api_token_secret: "{{ vault_proxmox_token }}"
  tasks:
    - name: Clone VM from template
      community.general.proxmox_kvm:
        api_host: "{{ proxmox_host }}"
        api_user: "{{ proxmox_api_user }}"
        api_token_id: "{{ proxmox_api_token_id }}"
        api_token_secret: "{{ proxmox_api_token_secret }}"
        node: pve-node1
        name: webserver-01
        clone: ubuntu-2404-template
        vmid: 200
        full: true
        storage: local-lvm
        timeout: 300
      register: vm_result

    - name: Configure VM resources
      community.general.proxmox_kvm:
        api_host: "{{ proxmox_host }}"
        api_user: "{{ proxmox_api_user }}"
        api_token_id: "{{ proxmox_api_token_id }}"
        api_token_secret: "{{ proxmox_api_token_secret }}"
        node: pve-node1
        vmid: 200
        cores: 4
        memory: 4096
        balloon: 2048
        onboot: true
        update: true

    - name: Start VM
      community.general.proxmox_kvm:
        api_host: "{{ proxmox_host }}"
        api_user: "{{ proxmox_api_user }}"
        api_token_id: "{{ proxmox_api_token_id }}"
        api_token_secret: "{{ proxmox_api_token_secret }}"
        node: pve-node1
        vmid: 200
        state: started

Create VM from ISO

- name: Create VM from scratch
  community.general.proxmox_kvm:
    api_host: "{{ proxmox_host }}"
    api_user: "{{ proxmox_api_user }}"
    api_token_id: "{{ proxmox_api_token_id }}"
    api_token_secret: "{{ proxmox_api_token_secret }}"
    node: pve-node1
    name: db-server-01
    vmid: 201
    cores: 8
    memory: 16384
    bios: ovmf
    machine: q35
    scsihw: virtio-scsi-single
    scsi:
      scsi0: "local-lvm:64,format=raw,iothread=1"
    ide:
      ide2: "local:iso/ubuntu-24.04-live-server-amd64.iso,media=cdrom"
    net:
      net0: "virtio,bridge=vmbr0,firewall=1"
    boot: order=scsi0;ide2;net0
    ostype: l26
    agent: 1
    onboot: true

Manage LXC Containers

---
- name: Create LXC container
  hosts: localhost
  gather_facts: false
  tasks:
    - name: Create container
      community.general.proxmox:
        api_host: "{{ proxmox_host }}"
        api_user: "{{ proxmox_api_user }}"
        api_token_id: "{{ proxmox_api_token_id }}"
        api_token_secret: "{{ proxmox_api_token_secret }}"
        node: pve-node1
        hostname: nginx-ct
        vmid: 300
        ostemplate: "local:vztmpl/ubuntu-24.04-standard_24.04-1_amd64.tar.zst"
        storage: local-lvm
        disk: 10
        cores: 2
        memory: 1024
        swap: 512
        netif: '{"net0":"name=eth0,bridge=vmbr0,ip=dhcp,firewall=1"}'
        password: "{{ vault_ct_root_password }}"
        pubkey: "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"
        onboot: true
        unprivileged: true
        state: present

    - name: Start container
      community.general.proxmox:
        api_host: "{{ proxmox_host }}"
        api_user: "{{ proxmox_api_user }}"
        api_token_id: "{{ proxmox_api_token_id }}"
        api_token_secret: "{{ proxmox_api_token_secret }}"
        node: pve-node1
        vmid: 300
        state: started

Bulk VM Provisioning

---
- name: Provision multiple VMs
  hosts: localhost
  gather_facts: false
  vars:
    vms:
      - name: web-01
        vmid: 200
        cores: 2
        memory: 2048
        template: ubuntu-2404-template
      - name: web-02
        vmid: 201
        cores: 2
        memory: 2048
        template: ubuntu-2404-template
      - name: db-01
        vmid: 210
        cores: 4
        memory: 8192
        template: ubuntu-2404-template
      - name: cache-01
        vmid: 220
        cores: 2
        memory: 4096
        template: ubuntu-2404-template
  tasks:
    - name: Clone VMs from template
      community.general.proxmox_kvm:
        api_host: "{{ proxmox_host }}"
        api_user: "{{ proxmox_api_user }}"
        api_token_id: "{{ proxmox_api_token_id }}"
        api_token_secret: "{{ proxmox_api_token_secret }}"
        node: pve-node1
        name: "{{ item.name }}"
        clone: "{{ item.template }}"
        vmid: "{{ item.vmid }}"
        full: true
        storage: local-lvm
        timeout: 300
      loop: "{{ vms }}"

    - name: Configure VM resources
      community.general.proxmox_kvm:
        api_host: "{{ proxmox_host }}"
        api_user: "{{ proxmox_api_user }}"
        api_token_id: "{{ proxmox_api_token_id }}"
        api_token_secret: "{{ proxmox_api_token_secret }}"
        node: pve-node1
        vmid: "{{ item.vmid }}"
        cores: "{{ item.cores }}"
        memory: "{{ item.memory }}"
        onboot: true
        update: true
      loop: "{{ vms }}"

    - name: Start all VMs
      community.general.proxmox_kvm:
        api_host: "{{ proxmox_host }}"
        api_user: "{{ proxmox_api_user }}"
        api_token_id: "{{ proxmox_api_token_id }}"
        api_token_secret: "{{ proxmox_api_token_secret }}"
        node: pve-node1
        vmid: "{{ item.vmid }}"
        state: started
      loop: "{{ vms }}"

Snapshots

- name: Create VM snapshot
  community.general.proxmox_snap:
    api_host: "{{ proxmox_host }}"
    api_user: "{{ proxmox_api_user }}"
    api_token_id: "{{ proxmox_api_token_id }}"
    api_token_secret: "{{ proxmox_api_token_secret }}"
    vmid: 200
    hostname: webserver-01
    snapname: "pre-upgrade-{{ ansible_date_time.date }}"
    description: "Snapshot before system upgrade"
    state: present
    vmstate: true

- name: Rollback to snapshot
  community.general.proxmox_snap:
    api_host: "{{ proxmox_host }}"
    api_user: "{{ proxmox_api_user }}"
    api_token_id: "{{ proxmox_api_token_id }}"
    api_token_secret: "{{ proxmox_api_token_secret }}"
    vmid: 200
    hostname: webserver-01
    snapname: "pre-upgrade-2026-04-25"
    state: rollback

Download Templates

- name: Download container template
  community.general.proxmox_template:
    api_host: "{{ proxmox_host }}"
    api_user: "{{ proxmox_api_user }}"
    api_token_id: "{{ proxmox_api_token_id }}"
    api_token_secret: "{{ proxmox_api_token_secret }}"
    node: pve-node1
    storage: local
    template: ubuntu-24.04-standard_24.04-1_amd64.tar.zst
    content_type: vztmpl
    state: present

Dynamic Inventory

Use the Proxmox dynamic inventory plugin to auto-discover VMs:

# proxmox.yml (inventory file)
plugin: community.general.proxmox
url: https://pve.example.com:8006
user: ansible@pve
token_id: automation
token_secret: !vault |
  $ANSIBLE_VAULT;1.1;AES256
  ...
validate_certs: false
want_facts: true

# Group by tags
groups:
  webservers: "'web' in (proxmox_tags | default(''))"
  databases: "'db' in (proxmox_tags | default(''))"

# Set connection variables
compose:
  ansible_host: proxmox_agent_interfaces[0].ip_addresses[0] | default(proxmox_name)
# Test inventory
ansible-inventory -i proxmox.yml --list

Troubleshooting

Authentication Failed

fatal: "500 Internal Server Error: authentication failure"
  • Use API token instead of password (more reliable)
  • Verify token has PVEAdmin or appropriate role
  • Check privsep=0 on the token

VM Clone Timeout

# Increase timeout for large disks
- community.general.proxmox_kvm:
    clone: template-name
    timeout: 600      # 10 minutes
    full: true

"proxmoxer" Module Not Found

pip install proxmoxer requests
# Or in a virtualenv
pip install proxmoxer requests urllib3

Best Practices

  1. Use API tokens over passwords — more secure, no session management
  2. Use templates — clone from a golden image, don't install from ISO
  3. Snapshot before changes — automate pre-change snapshots
  4. Tag your VMs — enables dynamic inventory grouping
  5. Use onboot: true — VMs start automatically after host reboot
  6. Enable QEMU agent — agent: 1 gives Ansible access to guest IP addresses
  7. Unprivileged containers — always use unprivileged: true for LXC

Conclusion

The community.general Proxmox modules automate the full VM and container lifecycle — clone from templates, configure resources, manage snapshots, and provision at scale. Use API tokens for authentication, the dynamic inventory plugin for auto-discovery, and templates for consistent provisioning. Proxmox plus Ansible gives you a fully automated, open-source virtualization platform.