Packer

Machine image builder - create reproducible VM templates for Proxmox and cloud providers.

Packer Basics

Initialize plugins
packer init .
Validate template
packer validate .
Format HCL files
packer fmt .
Build image
packer build .
Build with variables
packer build -var "iso_url=https://mirror.example.com/rocky-9.iso" .
packer build -var-file=prod.pkrvars.hcl .
Build specific source only
packer build -only=proxmox-iso.rocky9 .
Debug build (step-by-step)
PACKER_LOG=1 packer build -debug .

MUSCLE MEMORY: packer fmt . && packer validate . && packer build .

Proxmox Builder

Proxmox ISO builder template
packer {
  required_plugins {
    proxmox = {
      version = ">= 1.1.0"
      source  = "github.com/hashicorp/proxmox"
    }
  }
}

source "proxmox-iso" "rocky9" {
  proxmox_url              = var.proxmox_url
  username                 = var.proxmox_username
  token                    = var.proxmox_token
  node                     = "pve"
  insecure_skip_tls_verify = true

  vm_id                = 9000
  vm_name              = "rocky9-template"
  template_description = "Rocky 9 template - built {{ timestamp }}"

  iso_file    = "local:iso/Rocky-9-latest-x86_64-minimal.iso"
  unmount_iso = true

  qemu_agent = true
  os         = "l26"
  memory     = 2048
  cores      = 2
  cpu_type   = "host"
  sockets    = 1

  scsi_controller = "virtio-scsi-pci"

  disks {
    type         = "scsi"
    disk_size    = "32G"
    storage_pool = "local-lvm"
    format       = "raw"
  }

  network_adapters {
    model  = "virtio"
    bridge = "vmbr0"
  }

  cloud_init              = true
  cloud_init_storage_pool = "local-lvm"

  boot_command = [
    "<up><wait>",
    "e<wait>",
    "<down><down><end>",
    " inst.ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg",
    "<F10>"
  ]

  http_directory = "http"

  ssh_username = "root"
  ssh_password = var.ssh_password
  ssh_timeout  = "20m"
}
Build and convert to template
build {
  sources = ["source.proxmox-iso.rocky9"]

  provisioner "shell" {
    inline = [
      "dnf update -y",
      "dnf install -y qemu-guest-agent cloud-init",
      "systemctl enable qemu-guest-agent",
      "cloud-init clean",
    ]
  }

  provisioner "ansible" {
    playbook_file = "./ansible/harden.yml"
  }

  provisioner "shell" {
    inline = [
      "truncate -s 0 /etc/machine-id",
      "rm -f /var/lib/dbus/machine-id",
      "cloud-init clean --logs --seed",
    ]
  }
}

PATTERN: Template pipeline: ISO → Packer → Proxmox template → Terraform clones.

Variables

Variable definitions
# variables.pkr.hcl
variable "proxmox_url" {
  type        = string
  description = "Proxmox API URL"
}

variable "proxmox_username" {
  type        = string
  description = "Proxmox API token ID"
}

variable "proxmox_token" {
  type      = string
  sensitive = true
}

variable "ssh_password" {
  type      = string
  sensitive = true
  default   = ""
}
Variable file
# prod.pkrvars.hcl
proxmox_url      = "https://pve.inside.domusdigitalis.dev:8006/api2/json"
proxmox_username = "packer@pve!packer-token"
Environment variables
export PKR_VAR_proxmox_token="secret-token-value"
export PKR_VAR_ssh_password="build-password"
packer build .

SECURITY: Sensitive variables never appear in logs. Use sensitive = true and env vars.

Provisioners

Shell provisioner
provisioner "shell" {
  inline = [
    "dnf update -y",
    "dnf install -y vim htop tmux",
  ]
}

provisioner "shell" {
  script = "scripts/setup.sh"
  environment_vars = [
    "DEBIAN_FRONTEND=noninteractive",
  ]
}
File provisioner
provisioner "file" {
  source      = "configs/sshd_config"
  destination = "/etc/ssh/sshd_config"
}
Ansible provisioner
provisioner "ansible" {
  playbook_file = "./ansible/baseline.yml"
  extra_arguments = [
    "--extra-vars", "env=template",
    "-vv",
  ]
}

ORDER: provisioners run sequentially top-to-bottom. Put cleanup last.

Quick Reference

Task Command

Initialize plugins

packer init .

Validate template

packer validate .

Format HCL files

packer fmt .

Build image

packer build .

Build with variables

packer build -var "iso_url=…​" .

Build from var file

packer build -var-file=prod.pkrvars.hcl .

Build specific source

packer build -only=proxmox-iso.rocky9 .

Debug build (step mode)

PACKER_LOG=1 packer build -debug .

Inspect template

packer inspect .