Using Ansible with Proxmox: PART 2

In Part 1B, we finished setting up our Ansible controller and ensured it could securely connect to our Proxmox environment. With that in place, we’re now ready to organise our automation workspace so everything has its place and purpose.

In this part, we’ll be creating an organised and thought-out Ansible folder structure, defining our inventory, installing the necessary collections, and securing our credentials using Ansible Vault. This structure will serve as the backbone for all the playbooks we’ll write in the coming posts.

Step 1: Create Your Ansible Folder Structure

Now, Let’s create this structure inside ~/Automation/Ansible/:

mkdir -p automation/ansible/{playbooks,inventories,group_vars/all,roles/windows_vm/tasks,roles/windows_vm/other_scripts,roles/windows_vm/vars}
touch automation/ansible/{ansible.cfg,requirements.yml,inventories/hosts.ini,playbooks/create-windows2019-template.yml,roles/windows_vm/tasks/main.yml,roles/windows_vm/vars/main.yml}

This gives you:

automation/
└── ansible/
    ├── ansible.cfg
    ├── inventories
    │   └── hosts.ini
    ├── requirements.yml
    ├── group_vars/
    │   └── all
    │       └── vault.yml (created in step 5)
    ├── playbooks/
    │   └── create-windows2019-template.yml
    └── roles/
        └── windows_vm/
            ├── tasks/
            │   └── main.yml
            ├── vars/
            │   └── main.yml
            └── other_scripts/

File Explanations

  • ansible.cfg – Configures Ansible defaults (e.g., inventory location, Python interpreter).

  • inventories/hosts.ini – Lists Proxmox server(s) to interact with.

  • requirements.yml - for installing ansible collections

  • group_vars/all/vault.yml – Stores global vars like proxmox_api_user, proxmox_api_token_id.

  • playbooks/create-windows2019-template.yml – The main playbook you will run.

  • roles/windows_vm/tasks/main.yml – All provisioning logic in one file. Also a directory you'll use for other specific roles and tasks, when running a multi-file playbook.

  • other_scripts/ – Optional for config files or scripts.


Step 2: Create Hosts.ini and Test host connection:

Create Your Inventory File

Host.ini file: might include direction to private ssh key, AND localhost ansible_connection)

Ansible needs to know which servers to manage. Create a file like this if not already done:

nano ~/Automation/Ansible/inventories/hosts.ini
automation/
└── ansible/
    ├── ansible.cfg
    ├── inventories
      ├   └── hosts.ini

Paste:

[proxmox]
192.168.1.125 ansible_user=Ansible

Save (ctrl + o), press enter, and exit (ctrl + x).

NOTE: Remember how you spell the host name, ansible can be case sensitive so using the wrong case can cause errors.

Step 3: Test Ansible Connection

Run a quick ping test to ensure Ansible can talk to your Proxmox server:

ansible -i ~/Automation/Ansible/inventories/hosts.ini all -m ping

You should get:

192.168.1.125 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

If not, SSH key or permissions are probably misconfigured.


Step 4: Use Ansible to Create a VM on Proxmox

We’ll use a special Proxmox community-provided modules that lets Ansible create or clone VMs on Proxmox.

Install Proxmox Collection

Install the Ansible collection to interact with the Proxmox API:

ansible-galaxy collection install community.general
ansible-galaxy collection install community.libvirt

(You'll mostly use community.general.proxmox_kvm)

if either of these do no work then you can do via a requirments.yml file:

Alternative - Using a requirements.yml

Alternatively, you can create requirements.yml file for installing ansible collections (community.libvert 1.0.2).

Save in ansible directory (~/Automation/Ansible)

# requirements.yml
collections:
  - name: community.libvirt
    version: "1.0.2"  # or any available version

Then run:

ansible-galaxy collection install -r requirements.yml

Step 5: Create Ansible Vault for Proxmox Credentials

Run the following (while in the Ansible file):

ansible-vault create group_vars/all/vault.yml

Add this inside:

proxmox_api_user: "your_proxmox_username"
proxmox_api_token_id: "your_proxmox_token_id"
proxmox_api_token_secret: "your_proxmox_token_secret"

⚠️ Don’t use the Proxmox web password in plaintext elsewhere — only reference it from Vault!

Assuming you're in ~/Automation/Ansible/, you should now have:

automation/
└── ansible/
    ├── ansible.cfg
    ├── inventory.yml
    ├── requirements.yml
      ├── group_vars/
        │   └── all/
        │       └── vault.yml

Encrypt it:

ansible-vault encrypt vault.yml

Honestly, im not a fan of Vim and MUCH prefer Nano, so to get the vault.yml open and edit securely in Nano we can do the below: NOTE: Doing the below without the export command (so just the ansible command) will open vault.yml in Vim… Not sure why you’d want that though:

export EDITOR=nano
ansible-vault edit vault.yml

If you ever want to decrypt it temporarily:

ansible-vault decrypt vault.yml

If you just want to view contents (read-only), use:

ansible-vault view vault.yml

Step 6: Setting up Vault password file (vault_pass.txt):

Usually, vault_pass.txt is stored on the machine locally where you run Ansible (your control node), not inside your Git repo or project directory — because it’s essentially the “key” to decrypt all your encrypted Ansible Vault secrets.

A common practice is:

Example:

~/.vault_pass.txt

How to set it up

# Create the vault password file in your home directory
echo "MySuperSecretVaultPassword" > ~/.vault_pass.txt

# Restrict file permissions so only you can read it
chmod 600 ~/.vault_pass.txt

Secure the .vault_pass.txt file:

chmod 600 ~/.vault_pass.txt
  • 600 means:

    • Only the file owner can read and write to the file.

    • All others (group + others) get no access at all.

  • This is important because your .vault_pass.txt file contains the plain text Vault password. If it's left world-readable (644), any local user could decrypt your secrets.

  • If your machine is multi-user (e.g., a shared VM or server), unprotected secrets can easily be leaked or misused. Setting 600 ensures only you can read the file.

Why store it there

  • Keeps it outside of version control so it never gets pushed to GitHub.

  • Prevents accidental exposure since only your user can read it (chmod 600).

  • You can point Ansible to it in ansible.cfg so you don’t have to pass -vault-password-file every time.

ansible.cfg example

[defaults]
inventory = inventory.yml
vault_password_file = ~/.vault_pass.txt

Step 7 – Verify Your Setup:

You can now run playbooks without being prompted for a vault password:

ansible-playbook playbooks/create_windows_vm.yml

If everything’s set up correctly, Ansible will:

  • Load your inventory

  • Will automatically decrypt your secrets.

  • Use the Proxmox API module to create or manage VMs

We’ve now prepared our Ansible controller and ensured our SSH keys are ready for secure, passwordless communication with our target machines. In the next posts, we’ll move on to the fun part — actually writing and running our first playbook.

We’ll cover:

  • Single-file playbooks – quick and simple automation in one YAML file.

  • Multi-file playbooks – a modular approach with roles, variables, and cleaner structure.

  • By the end, you’ll not only know how to type up your playbook but also run it successfully from start to finish.

If you feel certain steps or lines of code could have been done more efficiently, please let me know. At the end of the day, positive, constructive criticism, is one of the best ways to grow and improve not only as an IT Professional but life in general.

Thanks!

0
Subscribe to my newsletter

Read articles from Mike Kobbie Tieku TABI directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Mike Kobbie Tieku TABI
Mike Kobbie Tieku TABI