Homelab Ansible
This repository runs Ansible playbooks against hosts from NetBox.
Set up the environment
cd ansible
source .venv/bin/activate
ansible-galaxy collection install -r requirements.yml
bao login -method=oidc
direnv allow
ansible-inventory --graph
.envrc loads NetBox credentials from OpenBao into NETBOX_API and NETBOX_TOKEN.
Ansible source, inventories, playbooks, and roles remain under ansible/.
Run a playbook
For hosts that use sudo instead of a root connection, prompt for the sudo password:
To run against one host or group, use:
ansible-playbook playbooks/maintenance.yml -e target_hosts=my-host
ansible-playbook playbooks/maintenance.yml -e target_hosts=proxmox_hosts
NetBox inventory fallback
NetBox is the source of truth through inventory/netbox.yml. If NetBox is down
or its API token is unavailable, use the checked-in static fallback inventory.
ansible-inventory -i inventory/fallback.yml --graph
ansible-playbook -i inventory/fallback.yml playbooks/ping.yml
ansible-playbook -i inventory/fallback.yml playbooks/maintenance.yml -e target_hosts=proxmox_hosts
inventory/fallback.yml uses the same NetBox group names: linux_hosts,
proxmox_hosts, k3s_cluster, grafana_alloy_hosts,
opentelemetry_collector_hosts, docker_hosts, and hermes_agent_hosts. The
playbooks need no changes during an incident. Keep the fallback small, and
update host membership in NetBox after it recovers. Refresh
the fallback from checked-in Terraform or DNS records only while it remains a
useful break-glass inventory.
Playbooks
| File | What it does | Default target |
|---|---|---|
playbooks/maintenance.yml |
Updates Linux hosts, sets timezone, optional reboot | linux_hosts |
playbooks/alloy.yml |
Installs Grafana Alloy | grafana_alloy_hosts |
playbooks/opentelemetry.yml |
Installs a host OpenTelemetry Collector for system metrics and journald logs | opentelemetry_collector_hosts |
playbooks/docker.yml |
Installs Docker | docker_hosts |
playbooks/ubuntu-lts-upgrade.yml |
Upgrades Ubuntu Docker hosts to the latest supported LTS, then refreshes Docker packages | docker_hosts |
playbooks/proxmox-ntp.yml |
Installs and starts NTP on Proxmox | proxmox_hosts |
playbooks/proxmox-logging.yml |
Sends Proxmox logs to remote syslog | proxmox_hosts |
playbooks/proxmox-network.yml |
Standardizes bridge names while mapping physical NICs per host. Requires explicit write confirmation and does not reload networking. | proxmox_hosts |
playbooks/proxmox-sdn.yml |
Installs Proxmox SDN packages | proxmox_hosts |
playbooks/proxmox-pve9-prereqs.yml |
Prepares Proxmox hosts for PVE 8→9 by updating apt suites to Trixie/PVE 9, removing duplicate legacy Proxmox apt entries, updating existing Ceph repositories to Squid, optionally writing deb822 Debian sources, and installing CPU microcode (intel-microcode or amd64-microcode) when needed. It does not touch guests. |
proxmox_hosts |
playbooks/k3s-check-time.yml |
Shows time and NTP status | k3s_cluster |
playbooks/k3s-clear-pod-logs.yml |
Truncates k3s pod logs | k3s_cluster |
playbooks/ping.yml |
Tests host access | linux_hosts |
playbooks/check-kernel.yml |
Prints kernel version | linux_hosts |
playbooks/resize-lvm-disk.yml |
Grows an Ubuntu LVM root disk | must set target_hosts |
playbooks/k8s-dns-record.yml |
Creates a DNS A record from localhost | localhost |
The OpenTelemetry playbook installs a pinned otelcol-contrib package, reads
host metrics and new journald entries, and forwards them over OTLP gRPC. Add the
opentelemetry or otel-collector tag to selected NetBox hosts. Set the backend
endpoint in inventory before running the playbook:
TLS verification is on by default. Keep authentication headers and TLS keys in
the existing secret store, not in the checked-in role defaults. Run the baseline
on selected hosts rather than linux_hosts; Kubernetes node telemetry remains
owned by the GitOps-managed collector from ADR 004.
Use the host OpenTelemetry Collector runbook to verify a rollout or remove the collector from a host.
Use common playbooks
To update hosts and reboot only if needed, run:
To install the QEMU guest agent, run:
ansible-playbook playbooks/maintenance.yml \
-e target_hosts=my-vm \
-e common_maintenance_install_qemu_guest_agent=true \
-e common_maintenance_apt_upgrade=false
Upgrade the Docker VM from Ubuntu 20.04 to the latest LTS supported by the Ubuntu LTS upgrader, 24.04 by default. Run the playbook against one host at a time. It performs each required LTS hop and reboots between hops. It then reruns the Docker role so the APT repository and packages match the new Ubuntu codename.
Only override the target after Ubuntu marks a newer LTS as supported in
meta-release-lts.
ansible-playbook playbooks/ubuntu-lts-upgrade.yml \
--ask-become-pass \
-e target_hosts=docker \
-e ubuntu_lts_upgrade_target_version=26.04
To prepare one Proxmox node for the PVE 8→9 apt upgrade without changing VMs or CTs, run:
The playbook follows the Proxmox VE 8→9 repository migration in the upgrade
guide. It changes existing Debian apt sources from Bookworm to Trixie and points
the Proxmox VE repository at PVE 9. It removes legacy list-style Proxmox entries,
including entries in /etc/apt/sources.list, to avoid duplicate targets. It also
updates an existing Ceph repository to Ceph Squid for Trixie, installs the CPU
microcode package for the host, and refreshes the apt cache.
The operator must still run apt policy, pve8to9 --full, and apt
dist-upgrade. The playbook does not run apt modernize-sources. That optional
post-upgrade command is unavailable on Debian Bookworm with PVE 8 apt. Set
proxmox_pve9_write_debian_deb822_sources=true to rewrite the Debian sources as
deb822.
Proxmox network contract
All nodes provide the same guest-facing bridges, even though their physical NIC names differ.
| Bridge | Purpose |
|---|---|
vmbr0 |
pfSense WAN, backed by the node-specific WAN NIC |
vmbr2 |
Native LAN and Proxmox management, backed by the node-specific trunk NIC |
vmbr20 |
VLAN 20 as a dedicated bridge |
vmbr30 |
VLAN 30 as a dedicated bridge |
vmbr99 |
VLAN 99 as a dedicated bridge |
vmbr1 |
Optional auxiliary physical network on nodes that have a third mapped NIC |
VMs and containers attach directly to their network bridge. A VLAN 20 guest uses
bridge=vmbr20 without a Proxmox VLAN tag. pfSense uses one NIC on each routed
bridge, matching VM 103 on pve2. Proxmox SDN packages remain installed, but the
cluster has no SDN zones or VNets that duplicate these physical bridges.
Physical interface mappings and management addresses are in
inventory/host_vars/<node>.yml. To review a node without changing it, run:
After you review the diff and confirm console access, write one node's persistent configuration:
ansible-playbook playbooks/proxmox-network.yml \
-e target_hosts=pve2 \
-e proxmox_network_confirm=true \
--diff
The playbook checks that the mapped NICs exist and that ifupdown2 can parse the
generated file. It does not reload networking. Run ifreload -a from the node's
console during a maintenance window. Verify pfSense and management connectivity
before continuing with the next node.
To create a DNS record, run:
DNS_UPDATE_KEY_SECRET=... ansible-playbook playbooks/k8s-dns-record.yml \
-e name=app \
-e ip=192.168.1.50
Where to change things
| Need | Edit |
|---|---|
| Add or remove hosts | NetBox |
| Change host groups | inventory/netbox.yml |
| Change group connection settings | inventory/group_vars/<group>.yml |
| Change a playbook target | hosts: in playbooks/*.yml |
| Change role defaults | roles/*/defaults/main.yml |
| Change role behavior | roles/*/tasks/main.yml |