To use, run git clone https://github.com/SRF-Audio/utility-scripts.git && cd utility-scripts && ./bootstrap.sh
This repo is a list of useful setup scripts for different Linux Distros, and various cloud/kubernetes tools that I use. These allow me to spin up a new VM or container, and quickly bring it back to my preferred configuration.
If you find these useful, but see a way to make them better, or more efficient, feel free to open an issue. I appreciate the contribution.
Below is a pattern I’ve had good luck with on mixed-environment homelabs. It follows the directory layout and role-centric workflow the Ansible docs call “sample-setup”, adding only enough structure to keep your desktop, hypervisor, VM, k3s and add-on services cleanly separated. (docs.ansible.com)
inventories/
└── homelab/
├── hosts.ini
└── group_vars/
├── all.yml
├── desktops.yml # KDE Fedora workstations & laptops
├── proxmox.yml # Bare-metal hypervisors
├── vms_fedora.yml # CoreOS / Server VMs
├── k3s_control.yml
└── k3s_worker.yml
- Hosts go in the most specific group only; use Ansible’s built-in group inheritance (
children=blocks) if something truly belongs to several groups. - Put behaviour in
group_vars, secrets invault.yml(or call the 1Password lookup plug-in there). This keeps secrets out of playbooks and roles. (docs.ansible.com, docs.ansible.com)
Roles are how you make the codebase composable and testable. Each role owns exactly one slice of configuration and can be reused on any host that needs it. (docs.ansible.com)
| Role name | What it does | Typical tags |
|---|---|---|
common |
Users, base packages, 1Password CLI, Tailscale client | base |
updates |
DNF/Yum/Apt upgrade or rpm-ostree upgrade with autoreboot guard |
updates |
workstation_kde |
KDE settings, Plasma look-and-feel, Flatpak/pkg install | gui |
proxmox_host |
/etc/hosts, cluster join, pve-no-subscription repo, zfs tune |
hypervisor |
coreos_base |
Ignition tweaks, rpm-ostree layers, podman | vm |
ssh_keys |
Generate ED25519 keys, sync public key from 1Password item, distribute | ssh |
k3s_control |
Install k3s server, configure etcd-external, set node-labels | k3s |
k3s_worker |
Join worker, taints, GPU runtime, kube-proxy flags | k3s |
k8s_deploy |
k8s / helm module calls that stand up Home-Assistant, InfluxDB, etc. |
apps |
Anything that may be useful on more than one host belongs in its own role; resist the urge to combine “desktop tweaks” with “OS updates”.
Keep playbooks thin—just “which hosts, which roles, in what order”. Example:
# playbooks/site.yml ← run for the full stack
- name: Workstations
hosts: desktops
roles:
- common
- workstation_kde
- ssh_keys
- updates
- name: Proxmox hypervisors
hosts: proxmox
gather_facts: false # PVE shell is fast; facts optional
roles:
- common
- proxmox_host
- ssh_keys
- updates
- name: Fedora / CoreOS VMs
hosts: vms_fedora
roles:
- common
- coreos_base
- updates
- name: k3s control plane
hosts: k3s_control
roles:
- k3s_control
- k8s_deploy # if you want apps immediately
- name: k3s workers
hosts: k3s_worker
roles:
- k3s_workerplaybooks/
├── site.yml # full convergence
├── maintenance.yml # just updates & reboots
└── k8s.yml # (re)deploy apps only
| Question to ask | Answer |
|---|---|
| “Could this role ever target a different host type?” | If yes, keep it separate (ex: ssh_keys, updates). |
| “Does this task get skipped 90 % of the time?” | Give it a tag (gui, apps) so you can --tags gui or --skip-tags gui. |
“Do I have >200 lines in a single role’s tasks/main.yml?” |
Split into tasks/update.yml, tasks/firewall.yml, etc. and call with import_tasks. |
| “Is this only called from another role?” | Put it in that role’s meta/ as a dependency instead of its own top-level playbook. |
| High-level job | Command |
|---|---|
| One-shot full converge | ansible-navigator run playbooks/site.yml -i inventories/homelab |
| Desktop GUI tweaks only | ansible-playbook playbooks/site.yml --tags gui --limit desktops |
| Patch Tuesday | ansible-playbook playbooks/maintenance.yml --tags updates |
| Redeploy apps after editing Helm values | ansible-playbook playbooks/k8s.yml --tags apps |
Because roles carry their own tags, you stay flexible without bloating the playbooks.
- Separation of concerns – inventory = where, roles = what, playbooks = when/which.
- Predictable overrides –
group_varshierarchy means a workstation can inheritcommondefaults but overridednf_automatic: true. - Idempotence tests – each role is unit-testable with Molecule (Docker or Vagrant driver) before it ever touches the homelab.
- Secrets-aware – 1Password lookup lives only in
group_vars/all/vault.yml; roles stay secrets-agnostic.
Adopt or drop pieces to taste, but sticking to this pattern will keep “desktop tweaks” from leaking into your hypervisor config and vice-versa—no more sauce mixing.