Ansible

Updating Pinned Software

The Ansible project is the source of truth for pinned service versions. Review an upstream release, update its variable in https://github.com/tuero/homelab-ansible, run a verified backup for stateful services, deploy the affected tag, verify it, and commit the pin. Ansible is not scheduled to upgrade services automatically.

SoftwarePin variable(s)Deploy command
AdGuard Homeadguardhome_version./run.sh --limit infra_servers --tags adguard
Tailscaletailscale_version./run.sh --limit infra_servers --tags tailscale
Docker Enginedocker_ce_version, docker_containerd_version, docker_buildx_version, docker_compose_version./run.sh --limit services_servers --tags docker
ARR applicationsarr_images.radarr, arr_images.sonarr, arr_images.bazarr, arr_images.prowlarr./run.sh --limit services_servers --tags arr
Gluetun and qBittorrentgluetun_image, qbittorrent_image./run.sh --limit services_servers --tags downloads
Caddycaddy_version, caddy_cloudflare_module_version./run.sh --limit services_servers --tags proxy
Homepage and Uptime Kumahomepage_image, uptime_kuma_image./run.sh --limit services_servers --tags monitoring
LLVMllvm_version, llvm_package_version./run.sh --limit gpu_servers --tags dev
GCCgcc_version./run.sh --limit gpu_servers --tags dev
NVIDIA driver and CUDAnvidia_driver_package, cuda_toolkit_version, cuda_toolkit_package_version./run.sh --limit gpu_servers --tags cuda
JupyterLabjupyter_python_version, jupyterlab_version, jupyter_ipykernel_version./run.sh --limit gpu_servers --tags jupyter

Docker images are pinned by release tag and digest. A changed image reference pulls and recreates its container while retaining bind-mounted appdata under /srv/docker/appdata; do not delete application directories to upgrade.

Finding APT Package Pins

APT pins are long repository version strings. Do not try to increment them by hand: copy a version reported by the host’s configured repository.

apt-cache policy <package>
apt-cache madison <package>

For LLVM, first choose the target major in llvm_version, then inspect the matching clang package and copy its full Candidate value into llvm_package_version:

ssh tuero@10.0.0.111
apt-cache policy clang-23
 
for package in clang-23 clang-format-23 clangd-23 clang-tidy-23; do
  apt-cache policy "$package"
done

All four LLVM packages share llvm_package_version, so use a version available for all four. The same procedure finds pins for the other APT-managed software:

# Lumbridge
apt-cache policy tailscale
 
# Ardougne
for package in docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin; do
  apt-cache policy "$package"
done
 
# Varrock
apt-cache policy nvidia-driver-595-open cuda-toolkit-13-3

Repository:

Ansible configures already-created Ubuntu VMs. See Proxmox for VM creation and Backups and Recovery before rebuilding a stateful services VM.

Prerequisites

  • The controller can reach 10.0.0.111, 10.0.0.112, and 10.0.0.113 over SSH.
  • Cloud-Init has created user tuero and installed the controller’s SSH key.
  • The inventory IPs match Inventory and Services.
  • TrueNAS and required shares already exist.
  • Proxmox GPU passthrough is already attached to the GPU VM.
  • group_vars/all/vault.yml exists and is encrypted.

Install Ansible on the controller:

# Ubuntu
sudo apt update
sudo apt install -y ansible
 
# macOS
brew install ansible

Vault

The active roles reference these secret variables:

vault_truenas_smb_password
vault_github_private_key
vault_github_public_key
vault_jupyter_password_hash
vault_adguard_password
vault_pia_username
vault_pia_password
vault_cloudflare_api_token

Do not put secret values in this note. For a new repository only, create and encrypt the Vault without overwriting an existing file:

cd ~/Documents/homelab-ansible
test ! -e group_vars/all/vault.yml \
  && cp group_vars/all/vault.yml.example group_vars/all/vault.yml \
  && ansible-vault encrypt group_vars/all/vault.yml

Edit an existing encrypted Vault with:

cd ~/Documents/homelab-ansible
ansible-vault edit group_vars/all/vault.yml

The example file may lag the active roles. Ensure all variables above are present before a full run.

Inventory

inventory/hosts.yml currently defines:

gpu_servers:      gpu-server -> 10.0.0.111
infra_servers:    infra      -> 10.0.0.112
services_servers: services   -> 10.0.0.113

All hosts use SSH user tuero.

Full Deployment

Test connectivity, then run the site:

cd ~/Documents/homelab-ansible
ansible all -m ping --ask-vault-pass
./run.sh

run.sh installs required Ansible Galaxy collections and invokes site.yml --ask-vault-pass.

The full role order is:

all VMs: common
 
GPU VM:
dev_tools -> truenas_mounts -> github_ssh -> nvidia_cuda
          -> jupyter -> post_install
 
Infra VM:
tailscale -> adguard
 
Services VM:
truenas_mounts -> service_appdata_restore (recovery only) -> docker
               -> arr_stack -> downloads_stack -> reverse_proxy -> monitoring_stack
               -> service_backups

Targeted Runs

./run.sh --limit gpu_servers
./run.sh --limit infra_servers
./run.sh --limit services_servers
./run.sh --limit 'infra_servers:services_servers'

Examples for existing hosts:

./run.sh --limit infra_servers --tags tailscale
./run.sh --limit infra_servers --tags adguard
./run.sh --limit services_servers --tags arr
./run.sh --limit services_servers --tags downloads
./run.sh --limit services_servers --tags proxy
./run.sh --limit services_servers --tags monitoring
./run.sh --limit services_servers --tags backups
./run.sh --limit gpu_servers --tags jupyter

Tag-only runs assume their prerequisites already exist. For a normal fresh VM, prefer the full host-group run instead of assembling the machine from individual tags. The only exception is Backups and Recovery > Recover a Fresh Services VM, where appdata must be restored before Docker starts any service.

Fresh VM Expectations

A full run should install software, mount storage, render Compose configuration, create the shared Docker network, and start services. It does not restore Web UI-generated application state. The service_appdata_restore role has never and restore tags, so it is skipped unless explicitly selected and authorized.

On a blank deployment, complete Manual Steps > Services VM Starting Blank Only. On a recovery, use Backups and Recovery > Recover a Fresh Services VM; restored appdata includes the application Web UI configuration, so qBittorrent and ARR reconfiguration should not be necessary.

Verification

ansible all -m ping --ask-vault-pass
 
ssh tuero@10.0.0.111 nvidia-smi
ssh tuero@10.0.0.112 systemctl is-active AdGuardHome tailscaled
ssh tuero@10.0.0.113 systemctl is-active docker containerd
ssh tuero@10.0.0.113 systemctl list-timers service-appdata-backup.timer

The common role installs and starts qemu-guest-agent. Verify it inside each guest with:

systemctl is-active qemu-guest-agent