Skip to content

traefikturkey/oncall

Packer Templates for Proxmox

Automated VM template creation for Proxmox using HashiCorp Packer and Ansible.


Table of Contents


Introduction

This repository provides infrastructure-as-code tooling for automating the creation of virtual machine templates on Proxmox. Built with HashiCorp Packer and Ansible, these tools enable consistent, repeatable deployment of standardized VM images.

Key Features

  • Automated VM Template Creation - Build production-ready templates with a single command
  • Multi-Distribution Support - Linux (Ubuntu, RHEL family, Debian, SUSE) and Windows 11
  • Customizable Storage Layouts - Simple partitions, LVM, and CIS-compliant configurations
  • Network Flexibility - Static IP or DHCP configuration
  • Cloud-Init Ready - Modern cloud-init support for rapid provisioning
  • Dual Boot Support - UEFI and BIOS bootloader options
  • Docker Containerized - Consistent builds across Windows, macOS, and Linux
  • Infrastructure-as-Code - Version controlled with HCL2

Supported Operating Systems

Operating System Version Custom Storage Static IP UEFI BIOS VM ID
AlmaLinux 10, 9, 8 random
CentOS Stream 10, 9 10013-14
Debian 12, 11 10011-12
NixOS 25.11 10016
OpenSUSE Leap 15.6, 15.5 10009-10
Oracle Linux 9, 8 10007-08
Rocky Linux 10, 9, 8 10004-06
Ubuntu Server 26.04, 24.04, 22.04, 20.04 LTS 10000-03, 10015
Windows Desktop 11 random

All templates include:

  • QEMU Guest Agent for improved VM management
  • SSH access with key-based authentication
  • Ansible automation user pre-configured
  • Cloud-init support (Linux)
  • Latest security updates at build time

Quick Start

Prerequisites

  • Docker and Docker Compose installed
  • Linux host required - Docker Desktop on Windows has networking limitations that prevent Packer HTTP server connectivity
  • Access to Proxmox infrastructure (v8.0+)
  • Proxmox API token with appropriate permissions

3-Step Setup

1. Clone and Initialize

# Linux (required for Docker networking)
git clone https://github.com/traefikturkey/oncall.git
cd oncall
./docker-build.sh setup

This builds the Docker image and creates configuration template files in ./config/.

2. Configure for Your Environment

Edit configuration files in the config/ directory:

Essential configuration files:

  • proxmox.pkrvars.hcl - Proxmox API credentials and node
  • build.pkrvars.hcl - VM build user credentials
  • ansible.pkrvars.hcl - Ansible automation user
  • network.pkrvars.hcl - Network settings (VLANs, subnets)
  • linux-storage.pkrvars.hcl - Storage pools and partitions
Example: Proxmox Configuration
// config/proxmox.pkrvars.hcl
proxmox_api_token_id        = "packer@pam!packer-token"
proxmox_api_token_secret    = "<your-api-token-secret>"
proxmox_insecure_connection = true
proxmox_hostname            = "proxmox.local"
proxmox_node                = "pve-node-01"
Example: Network Configuration
// config/network.pkrvars.hcl
vm_bridge_interface = "vmbr0"
vm_vlan_tag         = "100"

// Optional: Static IP (defaults to DHCP if commented)
// vm_ip_address = "10.10.10.100"
// vm_ip_netmask = 24
// vm_ip_gateway = "10.10.10.1"
// vm_dns_list   = ["10.10.10.10", "10.10.10.11"]

3. Build a Template

# Linux/macOS/WSL
./docker-build.sh build

# Windows PowerShell
.\docker-build.ps1 build

Select your desired OS from the interactive menu (e.g., option 15 for Ubuntu 24.04 LTS).

Validation

Validate all templates before building:

# Linux/macOS/WSL
./docker-build.sh validate

# Windows PowerShell
.\docker-build.ps1 validate

Requirements

Infrastructure Platform

  • Proxmox VE 8.0 or later

Docker Environment (Recommended)

  • Docker 20.10+
  • Docker Compose 2.0+

All dependencies (Packer, Ansible, plugins) are included in the Docker image.

Manual Installation (Alternative)

Ubuntu - Install Packer & Ansible
# Add HashiCorp repository
sudo bash -c 'wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor > /usr/share/keyrings/hashicorp-archive-keyring.gpg'
sudo bash -c 'echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
https://apt.releases.hashicorp.com $(lsb_release -cs) main" > /etc/apt/sources.list.d/hashicorp.list'

# Install Packer
sudo apt update && sudo apt install packer

# Install Ansible
sudo apt install -y software-properties-common
sudo add-apt-repository --yes --update ppa:ansible/ansible
sudo apt install -y ansible-core
CentOS/RHEL - Install Packer & Ansible
# Install Packer
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo yum -y install packer

# Install Ansible
sudo dnf -y install ansible

Required Packer Plugins (auto-downloaded on first run):


Configuration Guide

Directory Structure

oncall/
├── ansible/          # Ansible roles for OS configuration
├── builds/           # Packer templates per OS
├── config/           # Your specific settings (YOU EDIT THESE)
├── manifests/        # Build manifests (auto-generated)
└── tests/            # Validation test suites

Configuration Scripts

Configuration templates are automatically created when you run ./docker-build.sh setup.

Optional: Create additional config directories for multiple environments:

./config.sh dev          # Creates ./dev/ directory
./config.sh prod         # Creates ./prod/ directory

Then customize the .pkrvars.hcl files for your infrastructure.

Local NixOS QEMU Smoke Test

The NixOS template also has a local Packer+QEMU smoke test under tests/nixos-qemu.

This path is useful for iterating on the installer boot sequence and generated configuration.nix without needing Proxmox credentials.

Requirements:

  • packer
  • qemu-system-x86_64
  • qemu-img

Example:

cp tests/nixos-qemu/test.pkrvars.hcl.example tests/nixos-qemu/test.pkrvars.hcl
./tests/nixos-qemu/run.sh

The QEMU smoke test currently defaults to a BIOS install path to keep local testing simple. The main Proxmox NixOS build remains available under builds/linux/nixos/25.11.

The config folder is the default folder. You can override the default by passing an alternate value as the first argument.

Essential Configuration Files

1. Proxmox Connection (config/proxmox.pkrvars.hcl)

proxmox_api_token_id        = "packer@pam!packer-token"
proxmox_api_token_secret    = "<api-token-secret>"
proxmox_insecure_connection = true  // false with valid TLS cert
proxmox_hostname            = "proxmox.local"
proxmox_node                = "pve-node-01"

API Token Setup: Token must have PVEAdmin role. See Proxmox API documentation.

2. Build User Credentials (config/build.pkrvars.hcl)

build_username           = "admin"
build_password           = "<plaintext-password>"
build_password_encrypted = "<sha512-hash>"
build_key                = "<ssh-public-key>"

Generate SHA-512 password hash:

mkpasswd -m sha512crypt

Generate SSH key:

ssh-keygen -t ecdsa -b 521 -C "automation"

3. Ansible User (config/ansible.pkrvars.hcl)

ansible_username = "ansible"
ansible_key      = "<ansible-ssh-public-key>"

4. Network Settings (config/network.pkrvars.hcl)

// Proxmox Network
vm_bridge_interface = "vmbr0"
vm_vlan_tag         = "100"

// Optional: Static IP (comment out for DHCP)
// vm_ip_address = "10.10.10.100"
// vm_ip_netmask = 24
// vm_ip_gateway = "10.10.10.1"
// vm_dns_list   = ["10.10.10.10", "10.10.10.11"]

5. Storage Configuration (config/linux-storage.pkrvars.hcl)

vm_storage_pool     = "local-lvm"
vm_efi_storage_pool = "local-lvm"
vm_disk_device      = "vda"
vm_disk_use_swap    = true
Storage Layout: Simple Single Partition (UEFI)
vm_disk_partitions = [
  {
    name = "efi", size = 1024,
    format = { label = "EFIFS", fstype = "fat32" },
    mount = { path = "/boot/efi", options = "" },
    volume_group = "",
  },
  {
    name = "boot", size = 1024,
    format = { label = "BOOTFS", fstype = "ext4" },
    mount = { path = "/boot", options = "" },
    volume_group = "",
  },
  {
    name = "root", size = -1,  // All remaining space
    format = { label = "ROOTFS", fstype = "ext4" },
    mount = { path = "/", options = "" },
    volume_group = "",
  },
]
Storage Layout: LVM with CIS-Compliant Hardening
vm_disk_partitions = [
  { name = "efi", size = 1024, format = { label = "EFIFS", fstype = "fat32" },
    mount = { path = "/boot/efi", options = "" }, volume_group = "" },
  { name = "boot", size = 1024, format = { label = "BOOTFS", fstype = "ext4" },
    mount = { path = "/boot", options = "" }, volume_group = "" },
  { name = "sysvg", size = -1, format = { label = "", fstype = "" },
    mount = { path = "", options = "" }, volume_group = "sysvg" },
]

vm_disk_lvm = [
  {
    name: "sysvg",
    partitions: [
      { name = "lv_root", size = 10240, format = { label = "ROOTFS", fstype = "ext4" },
        mount = { path = "/", options = "" }},
      { name = "lv_home", size = 4096, format = { label = "HOMEFS", fstype = "ext4" },
        mount = { path = "/home", options = "nodev,nosuid" }},
      { name = "lv_tmp", size = 4096, format = { label = "TMPFS", fstype = "ext4" },
        mount = { path = "/tmp", options = "nodev,noexec,nosuid" }},
      { name = "lv_var", size = 2048, format = { label = "VARFS", fstype = "ext4" },
        mount = { path = "/var", options = "nodev" }},
      { name = "lv_var_log", size = 4096, format = { label = "VARLOGFS", fstype = "ext4" },
        mount = { path = "/var/log", options = "nodev,noexec,nosuid" }},
    ],
  }
]

6. Common Settings (config/common.pkrvars.hcl)

common_iso_storage      = "local"  // Proxmox storage with ISO files
common_data_source      = "http"   // or "disk" for isolated networks
common_http_port_min    = 8000
common_http_port_max    = 8099
common_ip_wait_timeout  = "20m"
common_shutdown_timeout = "15m"

Firewall Configuration (if using http data source):

# iptables
iptables -A INPUT -p tcp --match multiport --dports 8000:8099 -j ACCEPT

# firewalld
firewall-cmd --zone=public --add-port=8000-8099/tcp --permanent
firewall-cmd --reload

Building VM Templates

Interactive Build

./build.sh
# Or with Docker:
./docker-build.sh build

Select from the menu:

  • Options 1-14: Various Linux distributions
  • Option 15: Ubuntu 24.04 LTS
  • Option 21: Ubuntu 26.04 LTS
  • Option 22: NixOS 25.11
  • Options 18-20: Windows 11

Debug Mode

./build.sh --debug
# Or with Docker:
docker-compose run --rm packer ./build.sh --debug

Enables verbose output and pauses on errors.

Build Process

  1. Initialize: Packer downloads required plugins (first run)
  2. Create VM: Temporary VM created in Proxmox
  3. Boot & Install: Automated OS installation from ISO
  4. Provision: Ansible applies configuration, updates, packages
  5. Convert: VM converted to reusable template
  6. Manifest: Build metadata saved to manifests/

Template Features

All templates include:

  • QEMU Guest Agent
  • SSH access (key-based)
  • Ansible automation user
  • Cloud-init support (Linux)
  • Latest security patches
  • Customizable storage layouts

Multiple Environments

# Development environment
./config.sh dev
./build.sh dev

# Production environment
./config.sh prod
./build.sh prod

Docker Usage

Important: Docker containerized builds require a Linux host. Docker Desktop on Windows/macOS has networking limitations that prevent the Packer HTTP server from being accessible to Proxmox VMs during autoinstall.

Quick Commands (Linux Only)

./docker-build.sh setup      # Initial setup (first time)
./docker-build.sh build      # Run interactive build
./docker-build.sh validate   # Validate all templates
./docker-build.sh shell      # Open shell in container
./docker-build.sh clean      # Remove Docker resources
./docker-build.sh rebuild    # Rebuild image from scratch

Using Docker Compose Directly

# Build image locally
docker-compose build

# Run interactively
docker-compose run --rm packer

# Run specific command
docker-compose run --rm packer ./validate.sh

# Debug mode
docker-compose run --rm packer ./build.sh --debug

Custom Config Path

docker-compose run --rm packer ./build.sh /workspace/my-custom-config

Environment Variables

Enable Packer logging:

PACKER_LOG=1 docker-compose run --rm packer ./build.sh

Or add to docker-compose.yml:

environment:
  - PACKER_LOG=1
  - PACKER_LOG_PATH=/workspace/packer.log

Volume Mounts

By default, the following are mounted:

  • .//workspace (entire project)
  • ./config/workspace/config (your configurations)
  • ./manifests/workspace/manifests (build outputs)
  • ~/.ssh/root/.ssh:ro (SSH keys, read-only)

Network Mode

Uses host network mode for Proxmox connectivity and HTTP server. Modify network_mode in docker-compose.yml if needed.

Building Without Docker Compose

# Build image
docker build -t packer-proxmox:latest .

# Run interactively
docker run -it --rm --network host \
  -v "$(pwd):/workspace" \
  -v "$(pwd)/config:/workspace/config" \
  -v "$(pwd)/manifests:/workspace/manifests" \
  -v "$HOME/.ssh:/root/.ssh:ro" \
  packer-proxmox:latest

# Run single command
docker run -it --rm --network host \
  -v "$(pwd):/workspace" \
  -v "$(pwd)/config:/workspace/config" \
  packer-proxmox:latest \
  ./validate.sh

Docker Benefits

  • Consistent Environment - Same tools/versions across all systems
  • Portability - Works on Windows, macOS, Linux without manual setup
  • Isolation - No pollution of host system
  • Easy Updates - Pull latest image or rebuild locally
  • Team Collaboration - Everyone uses identical environment

Advanced Configuration

Per-OS Template Settings

Each OS has a config file: config/linux-<os>-<version>.pkrvars.hcl

Example config/linux-ubuntu-24-04-lts.pkrvars.hcl:

// Guest OS Settings
vm_os_language = "en_US"
vm_os_keyboard = "us"
vm_os_timezone = "America/Los_Angeles"

// Hardware
vm_cpu_count   = 2
vm_cpu_sockets = 1
vm_cpu_type    = "host"  // "host" for best performance
vm_mem_size    = 4096
vm_disk_size   = "40G"

// Boot & Storage
vm_bios        = "ovmf"  // UEFI (or "seabios" for BIOS)
vm_disk_type   = "virtio"
vm_disk_format = "raw"

// Cloud-Init
vm_cloudinit   = true

// ISO
iso_path       = "iso"
iso_file       = "ubuntu-24.04-live-server-amd64.iso"
iso_checksum   = "https://releases.ubuntu.com/noble/SHA256SUMS"

Cloud-Init Support

Enable/disable per OS:

vm_cloudinit           = true   // Enable cloud-init
vm_cloudinit_disk_type = "ide"  // or "scsi", "virtio"

When cloning templates with cloud-init:

  • Set hostname and network
  • Inject SSH keys
  • Run custom scripts
  • Configure users and packages

Terraform Integration

Deploy VMs from templates using Terraform. See:

  • example_uefi_ubuntu_terraform/ - Ubuntu deployment example
  • terraform_import/ - Import existing VMs

Troubleshooting

Configuration Issues

Problem: Build fails with config errors

Solution:

  1. Verify all required config files edited
  2. Check Proxmox credentials are correct
  3. Test connectivity: ping proxmox.local

Build Timeouts

Problem: Build exceeds timeout

Solution: Increase timeout in OS-specific variables:

// In config/linux-ubuntu-24-04-lts.pkrvars.hcl
variable "timeout" {
  default = "120m"  // Increase from default 90m
}

ISO Not Found

Problem: Packer can't find ISO file

Solution:

  1. Verify ISO uploaded to Proxmox storage
  2. Check common_iso_storage matches storage name
  3. Confirm iso_path and iso_file are correct
  4. Test: Navigate to Proxmox web UI → Storage → ISO images

Network Connectivity

Problem: Can't reach Proxmox or HTTP server timeouts

Solution:

  1. Ensure you're running on a Linux host (not Docker Desktop on Windows/macOS)
  2. Verify vm_bridge_interface exists: pvesh get /nodes/<node>/network
  3. Check VLAN tag matches network config
  4. Ensure firewall allows ports 8000-8099
  5. Verify --network host is used (default in docker-compose.yml)
  6. Test: curl http://<packer-host>:8000/

Note: Docker Desktop on Windows/macOS has network isolation that prevents --network host from working properly. For these platforms, install Packer and Ansible directly on the host.

SSH Connection Failures

Problem: Packer can't SSH to VM

Solution:

  1. Verify credentials in config/build.pkrvars.hcl
  2. Check VM has network connectivity (console in Proxmox)
  3. Verify QEMU guest agent starting: systemctl status qemu-guest-agent
  4. Check Proxmox firewall rules

Packer Plugin Errors

Problem: Plugin download or compatibility issues

Solution: Re-initialize plugins:

cd builds/linux/ubuntu/24-04-lts/
packer init .

Permission Issues (Docker)

Problem: File permission errors on mounted volumes

Solution:

sudo chown -R $(id -u):$(id -g) config/ manifests/

Proxmox Connection Issues (Docker)

Checklist:

  • Container can reach Proxmox (check proxmox_hostname)
  • Network mode is host in docker-compose.yml
  • Firewall allows HTTP ports 8000-8099
  • No proxy blocking connections

Known Issues

Windows Builds

Windows templates require:

  • Valid product keys (not included)
  • Correct OS image names in config
  • VirtIO drivers for storage/network

See config/windows-desktop-11.pkrvars.hcl.example for configuration details.

Proxmox API Permissions

Currently requires PVEAdmin role. Least-privilege configuration documentation in progress.

Packer Proxmox Plugin

Pinned to v1.2.1 due to CPU bug in newer versions.


Credits

Based on:

Technologies:


Infrastructure as Code
Network Automation & Infrastructure Engineering

Releases

No releases published

Packages

 
 
 

Contributors

Languages