{"id":50521240,"url":"https://github.com/dryvist/ansible-proxmox","last_synced_at":"2026-07-07T23:00:35.402Z","repository":{"id":332245614,"uuid":"1133178291","full_name":"dryvist/ansible-proxmox","owner":"dryvist","description":"Automate your Proxmox server setup in minutes instead of hours. Production-ready Ansible roles for performance tuning, ZFS swap, system limits, and monitoring—so every server is configured identically with a single command.","archived":false,"fork":false,"pushed_at":"2026-07-02T15:59:14.000Z","size":731,"stargazers_count":1,"open_issues_count":31,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-02T17:36:21.067Z","etag":null,"topics":["ansible","ansible-playbook","ansible-roles","automation","configuration-management","debian","devops","homelab","infrastructure-as-code","linux","proxmox","proxmox-ve","sysadmin","virtualization","zfs"],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dryvist.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-01-13T01:48:33.000Z","updated_at":"2026-07-02T15:59:06.000Z","dependencies_parsed_at":"2026-02-02T06:00:24.718Z","dependency_job_id":null,"html_url":"https://github.com/dryvist/ansible-proxmox","commit_stats":null,"previous_names":["jacobpevans/proxmox-ansible","jacobpevans/ansible-proxmox","dryvist/ansible-proxmox"],"tags_count":69,"template":false,"template_full_name":null,"purl":"pkg:github/dryvist/ansible-proxmox","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dryvist%2Fansible-proxmox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dryvist%2Fansible-proxmox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dryvist%2Fansible-proxmox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dryvist%2Fansible-proxmox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dryvist","download_url":"https://codeload.github.com/dryvist/ansible-proxmox/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dryvist%2Fansible-proxmox/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35245324,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-07T02:00:07.222Z","response_time":90,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","ansible-playbook","ansible-roles","automation","configuration-management","debian","devops","homelab","infrastructure-as-code","linux","proxmox","proxmox-ve","sysadmin","virtualization","zfs"],"created_at":"2026-06-03T04:03:39.968Z","updated_at":"2026-07-07T23:00:35.015Z","avatar_url":"https://github.com/dryvist.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Proxmox Ansible\n\n[![Ansible Lint][lint-badge]][lint-url]\n[![Molecule Test][molecule-badge]][molecule-url]\n\n**Automate your Proxmox server setup in minutes instead of hours.**\n\n## What This Does\n\nThis project uses [Ansible][ansible]—an industry-standard automation\ntool—to configure [Proxmox VE][proxmox] servers automatically. Instead\nof manually logging into each server and typing commands, you run one\ncommand and all your servers are configured identically.\n\n### The Problem It Solves\n\nSetting up a Proxmox server properly takes time:\n\n- Installing monitoring tools\n- Configuring swap space for memory management\n- Tuning kernel parameters for performance\n- Setting system limits so applications don't crash\n\nDoing this manually on one server takes 30-60 minutes. On multiple\nservers? Hours of repetitive work, with the risk of human error making\neach server slightly different.\n\n### The Solution\n\nRun a single command, and every server gets the same professional\nconfiguration:\n\n```bash\n./scripts/run-ansible.sh playbooks/site.yml\n```\n\n**Time saved**: 30-60 minutes per server\n**Consistency**: Every server configured identically\n**Repeatability**: Add a new server? One command. Rebuild? One command.\n\n## What Gets Configured\n\n| Component              | What It Does                                   |\n| ---------------------- | ---------------------------------------------- |\n| **Common Packages**    | Installs utilities: htop, iotop, lm-sensors    |\n| **ZFS Swap**           | Creates optimized swap on ZFS                  |\n| **Kernel Tuning**      | Optimizes memory and disk settings             |\n| **System Limits**      | Increases file and process limits              |\n| **Crash Diagnostics**  | System crash diagnostics configuration         |\n| **LXC Features**       | LXC container feature flags (fuse, nesting)    |\n| **Proxmox Monitoring** | Sets up historical monitoring (sysstat, atop)  |\n| **NAS Storage**        | Declarative ZFS + Samba NAS for Home Assistant |\n\n### Why Each Matters\n\n- **Common Packages**: See what your server is doing at a glance\n- **ZFS Swap**: Prevents out-of-memory crashes when VMs use too much RAM\n- **Kernel Tuning**: Better performance for NVMe drives and VMs\n- **System Limits**: Prevents \"too many open files\" errors under load\n\n## Installation\n\nRequires [Ansible][ansible-install] (Mac, Linux, WSL), SSH access to Proxmox server(s), and Proxmox VE 8.x.\n\n```bash\ngit clone https://github.com/JacobPEvans/ansible-proxmox.git\ncd ansible-proxmox\nansible-galaxy collection install -r requirements.yml\ncp inventory/hosts.yml.example inventory/hosts.yml\n# Edit inventory/hosts.yml with your server details\n```\n\n### Inventory resolution\n\nThis project consumes a host inventory produced by an upstream\ninfrastructure-provisioning step. The contract is a single JSON document\ncontaining OpenTofu outputs (such as `host_services`, `node_storage`, and\n`containers`); `playbooks/load_tofu.yml` resolves it at run time, in priority\norder (first that resolves wins):\n\n1. `TOFU_INVENTORY_PATH` — an explicit local file (pin / override, e.g. tests).\n2. **S3 published artifact** — the inventory JSON published to an S3 bucket.\n   Any runner with scoped AWS read creds (CI via OIDC, a cloud agent, or\n   `aws-vault`) fetches it with **no checkout and no terraform toolchain**. The\n   fetch is native (`amazon.aws.aws_caller_info` + `amazon.aws.s3_object`;\n   boto3 comes from the dev shell) — no `aws` CLI required. Override the\n   location with `TOFU_INVENTORY_S3_URI` (else it is derived from the account).\n3. `inventory/tofu_inventory.json` — a local cache for development.\n\nSo in CI or on a cloud agent you only need AWS read creds. The artifact is\nexpected to already exist in S3; provisioning and publishing it is outside\nthis repo's scope.\n\nCreate the SOPS secrets file:\n\n```bash\ncp secrets.sops.yml.example secrets.sops.yml\nsops secrets.sops.yml\n```\n\nSet `NAS_HOMEASSISTANT_SMB_PASSWORD` in the secrets file before saving.\n\n## Usage\n\nTest the configuration (doesn't change anything):\n\n```bash\nsops exec-env secrets.sops.yml 'doppler run -- ./scripts/run-ansible.sh playbooks/site.yml --check --diff'\n```\n\nApply the configuration:\n\n```bash\nsops exec-env secrets.sops.yml 'doppler run -- ./scripts/run-ansible.sh playbooks/site.yml'\n```\n\n### Commissioning a new rack server (PVE 9.x)\n\nUse `playbooks/commission_rack_server.yml` after a new rack server (Dell\nPowerEdge, HPE ProLiant, Supermicro, etc.) has PVE 9.x installed via its\nBMC's vKVM and has joined the cluster (`pvecm add`):\n\n```bash\nansible-playbook -i inventory playbooks/commission_rack_server.yml -l node-a\n```\n\nThe play deliberately does NOT import `load_tofu.yml` — that loader is\nNAS-focused and would block commissioning. Run `playbooks/site.yml` after\ncommissioning if you need NAS provisioning.\n\nRack-server group defaults live in `inventory/group_vars/rack_servers.yml`;\nper-host settings (real IPs, BMC addresses, expected hardware) live in\n`inventory/host_vars/\u003cnode\u003e.yml` (untracked). See\n`inventory/host_vars/rack-server.yml.example` for the schema.\n\n### Upgrading a node to the latest point release (PVE 9.x)\n\n`playbooks/upgrade.yml` brings a node to the current point release on its\nchannel (`apt full-upgrade`), then reboots for the new kernel and verifies\n`pveversion`. It first imports `playbooks/snapshot.yml`, which snapshots the\nZFS root (boot environment) dataset as a restore point — instant and near-zero\nspace. An OS upgrade does not touch guest disks (separate datasets), so the\nroot snapshot, not a guest backup, is the right rollback artifact. It then\napplies the `pve_repositories` role, which keeps the node on the\nno-subscription channel (deb822 `.sources`, enterprise repo disabled) without\ntouching the Debian base repos. If `pve_repositories_apt_proxy` is set (real URL\ninjected via the `APT_PROXY_URL` env var, e.g. an apt-cacher-ng instance), apt\n`http://` fetches are routed through that caching proxy. Run it with console\naccess available; the node reboots.\n\n```bash\n# Test (snapshot and reboot are skipped in check mode):\n./scripts/run-ansible.sh playbooks/upgrade.yml -l pve --check --diff\n\n# Apply:\n./scripts/run-ansible.sh playbooks/upgrade.yml -l pve\n```\n\n`playbooks/snapshot.yml` is also runnable on its own. If a node's root layout\ndiffers from the `rpool/ROOT/pve-1` default, override `pve_snapshot_dataset`.\nThe upgrade assumes the node already has working apt repos for its channel\n(`apt update` fails loudly otherwise). To upgrade now and reboot later, pass\n`-e pve_upgrade_reboot=false`. Roll back a bad upgrade from a rescue boot with\n`zfs rollback \u003csnapshot\u003e`.\n\n## Customization\n\nAll settings have sensible defaults. Override them in\n`inventory/group_vars/proxmox.yml`:\n\n```yaml\n# Swap size (default: 96GB - reduce for smaller systems)\nzfs_swap_size: \"32G\"\n\n# Kernel tuning (lower swappiness = prefer RAM over swap)\nkernel_tuning_swappiness: 10\n\n# System limits (increase for high-load applications)\nulimits_nofile: 65536\n```\n\n## Development Environment\n\nThis project uses [Nix flakes](https://wiki.nixos.org/wiki/Flakes) + [direnv](https://direnv.net/) for a reproducible dev environment.\n\nRequires [Nix](https://nixos.org/download/) with flakes enabled and\n[direnv](https://direnv.net/docs/installation.html) with [nix-direnv](https://github.com/nix-community/nix-direnv).\n\n```sh\ncd ~/git/ansible-proxmox/main    # or any worktree\ndirenv allow                     # one-time per worktree\n```\n\nTools provided: `ansible`, `ansible-lint`, `molecule`, `sops`, `age`,\n`python3` (with paramiko, jsondiff, pyyaml, jinja2), `jq`, `yq`, `pre-commit`.\n\n## Testing\n\nThis project includes automated tests using [Molecule][molecule] plus a\nOpenTofu inventory loading check:\n\n```bash\n# Run the default scenario\nANSIBLE_ALLOW_BROKEN_CONDITIONALS=1 molecule test\n\n# Run the NAS-focused scenario\nANSIBLE_ALLOW_BROKEN_CONDITIONALS=1 molecule test -s nas_storage\n\n# Verify OpenTofu inventory loading locally\ncp tests/inventory_load/tofu_inventory.json inventory/tofu_inventory.json\nTOFU_INVENTORY_PATH=$PWD/inventory/tofu_inventory.json \\\nPROXMOX_VE_HOSTNAME=localhost PROXMOX_VM_SSH_USERNAME=root \\\n  ansible-playbook tests/inventory_load/verify_inventory.yml -i inventory/hosts.yml -c local\n```\n\n## For Developers\n\n### Pre-commit Hooks\n\n```bash\n# pre-commit is provided by the Nix dev environment\npre-commit install\n```\n\n### Linting\n\n```bash\nansible-lint\nyamllint .\n```\n\n## Cost-Benefit Summary\n\n| Metric              | Manual Setup       | With Ansible    |\n| ------------------- | ------------------ | --------------- |\n| Time per server     | 30-60 min          | 2-5 min         |\n| Consistency         | Variable           | 100% identical  |\n| Documentation       | In your head       | In the code     |\n| Disaster recovery   | Start from scratch | Re-run playbook |\n| Onboarding new team | Shadow someone     | Read the code   |\n\n## License\n\nApache License 2.0 - see [LICENSE](LICENSE) for details.\n\n[lint-badge]: https://github.com/JacobPEvans/ansible-proxmox/actions/workflows/ansible-lint.yml/badge.svg\n[lint-url]: https://github.com/JacobPEvans/ansible-proxmox/actions/workflows/ansible-lint.yml\n[molecule-badge]: https://github.com/JacobPEvans/ansible-proxmox/actions/workflows/molecule.yml/badge.svg\n[molecule-url]: https://github.com/JacobPEvans/ansible-proxmox/actions/workflows/molecule.yml\n[ansible]: https://www.ansible.com/\n[proxmox]: https://www.proxmox.com/\n[ansible-install]: https://docs.ansible.com/ansible/latest/installation_guide/\n[molecule]: https://docs.ansible.com/projects/molecule/\n\n---\n\n\u003e Part of a [larger ecosystem of ~40 repos](https://docs.jacobpevans.com) — see how it all fits together.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdryvist%2Fansible-proxmox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdryvist%2Fansible-proxmox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdryvist%2Fansible-proxmox/lists"}