Configuration¶
Dynamic Proxmox Inventory¶
This project uses dynamic inventory for Proxmox VE. The inventory files inventory/amd64.proxmox.yaml and inventory/arm64.proxmox.yaml use the community.proxmox.proxmox plugin to connect to a Proxmox VE instance and retrieve information about LXC containers. This allows for dynamic discovery of hosts based on your Proxmox setup.
Creating a Proxmox API Token¶
To use the dynamic inventory, you need to create a Proxmox API token. Here's how to do it:
- Log in to the Proxmox web interface.
- Navigate to
Datacenter->Permissions->API Tokens. - Click
Addto create a new API token. - Select the user you want to create the token for (e.g.,
root@pam). - Provide a
Token ID(e.g.,ansible). - Uncheck the
Privilege Separationcheckbox. This is important for the dynamic inventory to work correctly. - Click
Add. - Copy the
Token IDandSecret. You will need these for your Ansible configuration. The secret will not be shown again, so make sure to save it in a secure location.
Security Recommendation
For enhanced security, it is recommended to create a dedicated, non-root user for Ansible and to generate the API token under that user. This user should be granted only the minimum necessary permissions for Ansible to manage your Proxmox resources.
Options¶
The following options can be configured in inventory/amd64.proxmox.yaml and inventory/arm64.proxmox.yaml:
plugin: The Ansible plugin to use. This should be set tocommunity.proxmox.proxmox.url: The URL of your Proxmox VE instance.validate_certs: Whether to validate the SSL certificate of the Proxmox server. Defaults tofalse.want_facts: Whether to retrieve facts about the Proxmox nodes. Defaults totrue.user: The Proxmox user to connect with.token_id: The ID of the Proxmox API token.token_secret: The secret of the Proxmox API token. This should be encrypted with Ansible Vault, see the Secrets guide.
Example¶
---
plugin: community.proxmox.proxmox
url: https://pve01.l.nicholaswilde.io
validate_certs: false
want_facts: true
# Proxmox credentials. Create a token on the Proxmox node.
user: root@pam
token_id: ansible
# password file .vault_pass
token_secret: !vault |
$ANSIBLE_VAULT;1.1;AES256
63356539313533663964636139333037386262616239373638333136643834303631653139633437
6562613738653338613134343635383639363237343833390a353364373034383664343661316339
64333066646635396134323334336164633965373830666665353431326338363131386530383631
3939643133346134300a393136636137326431303965353537386665323766313464666331333337
62326331663361376632393331396439383666333739323766316432393761666561356266643938
3165353364633639326632336539313466343531363431373465
compose:
ansible_host: proxmox_agent_interfaces[1]['ip-addresses'][0] | default(proxmox_net0.ip) | ansible.utils.ipaddr('address')
ansible_user: "'root'"
ansible_user Quoting
The ansible_user value needs to be in single quotes inside of double quotes (e.g., "'root'"). This specific quoting is necessary due to the multi-layered parsing involved:
- YAML Parsing: The outer double quotes (
"...") instruct the YAML parser to treat the entire content ('root') as a single string. - Jinja2 Evaluation: Ansible's
composefeature then evaluates this string using the Jinja2 templating engine. The inner single quotes ('...') ensure that the final output of this Jinja2 evaluation is a literal string'root', which is what the underlying system expects for theansible_uservariable.
The ansible_user variable in the compose section sets the default SSH user for all discovered Proxmox LXC containers. In the example above, it is set to 'root' for all containers.
Conditionally Setting ansible_user¶
You can conditionally set the ansible_user for specific hosts within the dynamic inventory by using a Jinja2 expression in the compose section. This is useful when most hosts use a default user (like root), but a few require a different user.
The name variable, which corresponds to the Proxmox guest's name, can be used in the conditional.
For example, to use the nicholas user for the host named arm64 and root for all other hosts discovered by this inventory source, you can set ansible_user as follows:
compose:
ansible_host: proxmox_agent_interfaces[1]['ip-addresses'][0] | default(proxmox_net0.ip) | ansible.utils.ipaddr('address')
ansible_user: "'nicholas' if name == 'arm64' else 'root'"
This approach keeps the user configuration within the dynamic inventory file, avoiding the need for separate static inventory files for overrides.
Raspberry Pi Hosts¶
I have multiple Raspberry Pis on my network that are not part my dynamic inventory. They are managed using a static inventory file and specific playbooks.
Inventory¶
The inventory for the Raspberry Pi hosts is defined in inventory/rpis.yaml. This is a static inventory file that lists the hosts and their connection information.
inventory/rpis.yaml
Playbooks¶
There are several playbooks available for managing the Raspberry Pi hosts:
-
Update All Raspberry Pis: The
playbooks/update_rpis.yamlplaybook updates all Raspberry Pi hosts. It uses theupdate_aptandupdate_gitroles.To run this playbook:
-
Run a Single Task: The
playbooks/task_rpis.yamlplaybook runs a single task on all Raspberry Pi hosts. It uses thesinglerole.To run this playbook:
OpenMediaVault Host¶
I have an OpenMediaVault (OMV) instance running as a VM on my Proxmox host. It is managed as a single host.
Playbooks¶
-
Update OMV: The
playbooks/update_omv.yamlplaybook updates the OMV host. It runs theomv-updatecommand.To run this playbook:
Note
The
omv-updatecommand is a wrapper script that is the recommended way to update OpenMediaVault. It is a non-interactive script that runsapt updateandapt upgradeand also handles other OMV-specific configurations and checks to ensure the system remains stable.
Homelab-Pull¶
Playbooks¶
-
Remove homelab-pull: The
playbooks/remove_homelab_pull.yamlplaybook removes thehomelab-pullservice and timer from all hosts.To run this playbook:
Role Configuration Variables¶
Variables for individual roles are stored in the roles/<role name>/defaults/main.yaml
Example
---
setup_git_email: "[email protected]"
setup_git_signing_key: "69FF3D02ABFCD01F328778D5374FA199233281E4"
setup_git_repo: "[email protected]:nicholaswilde/homelab.git"
setup_git_homelab_folder: "git/nicholaswilde/homelab"
setup_nfs_path: "storage -fstype=nfs4,rw 192.168.2.19:/storage"
# setup_proxy: "http://192.168.2.40:3142"
setup_proxy: "http://aptcache.l.nicholaswilde.io:3142"
setup_beszel_key: ""
setup_dotfiles_repo: "https://github.com/nicholaswilde/dotfiles.git"
setup_dotfiles_folder: "git/nicholaswilde/dotfiles"
setup_reprepro_base_url: "http://deb.l.nicholaswilde.io"
setup_reprepro_key_url: "http://deb.l.nicholaswilde.io/public.gpg.key"
setup_syncthing_port: '8384'
setup_syncthing_control_node_ip: "192.168.2.28"
setup_syncthing_control_node_label: "amd2"
setup_debug_enabled: false
setup_adguard_home_url: "http://adguard01.l.nicholaswilde.io"
setup_ssh_public_key_url: "https://github.com/nicholaswilde.keys"
Ansible Configuration File¶
The ansible.cfg file contains default settings for Ansible. Here are the key configurations used in this project:
[defaults]
inventory = ./inventory/
playbook = ./playbooks/update_all.yaml
timeout = 25
vault_password_file = ./.vault_pass
interpreter_python = auto_silent
roles_path = ./roles/
host_key_checking = False
private_key_file = /home/nicholas/.ssh/id_ed25519
[ssh_connection]
scp_if_ssh = True
Explanation of Key Settings¶
inventory: Specifies the default inventory directory.playbook: Sets a default playbook to run if none is specified (e.g.,update_lxc.yaml).timeout: Sets the default SSH connection timeout to 25 seconds.vault_password_file: Points to the.vault_passfile for Ansible Vault passwords.interpreter_python: Automatically detects the Python interpreter on remote hosts.roles_path: Specifies the directory where Ansible roles are located.host_key_checking: Disables host key checking for SSH connections (use with caution in production environments).private_key_file: Specifies the default private key file for SSH connections.scp_if_ssh: Forces Ansible to usescpfor file transfers over SSH, even ifsftpis available. ```