Mastering HashiCorp Packer: Automating Proxmox and VMware VM Template Creation

Virtualization tutorial - IT technology blog
Virtualization tutorial - IT technology blog

Stop being a slave to manual OS installations

During my first days at work, my biggest nightmare was manually ‘spinning up’ (installing) virtual machines. Every time the dev team needed a new Ubuntu or CentOS instance, I’d manually mount the ISO, click ‘Next’ until my fingers hurt, set usernames, copy SSH keys… Doing one or two was fine, but by the 10th one in a day, it became exhausting.

Currently, I manage a Proxmox Homelab cluster with over 15 VMs. If I stuck to manual installs, I’d waste 30 minutes on every server. Not to mention, it’s easy to forget repo configurations or disabling firewalls. That’s why I switched entirely to HashiCorp Packer. This tool lets you turn the installation process into clean code (Infrastructure as Code). Just run a command, grab a coffee, and by the time you’re back, the template is ready on Proxmox.

Installing Packer in three easy steps

You can install Packer on any machine—Windows, Mac, or Linux. If you’re on Ubuntu, just drop these commands into your terminal:

wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install packer

Type packer version to make sure everything is working. Then, create a dedicated folder for your first project:

mkdir packer-lab && cd packer-lab
touch ubuntu-2204.pkr.hcl

Don’t forget to run packer init . so it can download the necessary plugins automatically.

Under the hood: How does Packer work?

Many people mistakenly think Packer installs over an existing machine. In reality, the process is very professional:

  1. Initialize a temporary VM: Packer tells Proxmox/VMware to create a brand new virtual machine from the original ISO file.
  2. Auto-fill forms: It uses user-data (Cloud-init) files to automatically answer OS installation questions (timezone, language, partitioning).
  3. Run provisioning scripts: Once the OS is up, Packer SSHs in to install Docker, Nginx, or monitoring agents as needed.
  4. ‘Bake’ the Template: Finally, it shuts down the machine, converts it into a Template, and cleans up any temporary files.

HCL (HashiCorp Configuration Language) is the primary language here. If you’ve played with Terraform, you’ll feel right at home. When working with CI/CD, I sometimes need to convert configuration files; I often use the YAML ↔ JSON Converter for quick processing. The advantage is that this tool runs directly in the browser, so there’s no risk of exposing sensitive configuration data.

Hands-on: Building a Template on Proxmox

Here is a basic HCL file to create an Ubuntu template right away. Make sure to have your Proxmox API Token ready before running it.

# ubuntu-2204.pkr.hcl

source "proxmox-iso" "ubuntu" {
  proxmox_url = "https://192.168.1.100:8006/api2/json"
  username    = "root@pam!packer_token"
  token       = "your-secret-here"
  
  node                 = "pve"
  iso_file            = "local:iso/ubuntu-22.04-live-server-amd64.iso"
  vm_name              = "ubuntu-2204-template"
  memory               = 2048
  cores                = 2
  
  network_adapters {
    model = "virtio"
    bridge = "vmbr0"
  }

  ssh_username = "ubuntu"
  ssh_password = "itfromzero-random-pass"
  ssh_timeout  = "20m"
}

A quick security tip: Never hardcode passwords in your files. I usually use the Password Generator to create a random string and store it in an environment variable. This gives you peace of mind when pushing code to GitHub.

What about VMware (vSphere)?

The syntax for VMware is similar; just change the builder to vsphere-iso. Using a consistent configuration framework ensures your servers are always uniform, regardless of the virtualization platform they run on.

Advanced Techniques: Cloud-init and System Cleanup

A great template is one that can self-configure on boot. You should combine Packer with Cloud-init to pre-load SSH keys. Also, use provisioner "shell" to optimize the OS right during the build:

build {
  sources = ["source.proxmox-iso.ubuntu"]

  provisioner "shell" {
    inline = [
      "sudo apt-get update",
      "sudo apt-get install -y qemu-guest-agent",
      "sudo truncate -s 0 /etc/machine-id"
    ]
  }
}

Note: The command to clear machine-id is mandatory. If forgotten, all child VMs created from this template will have duplicate IDs, leading to extremely annoying IP conflicts in DHCP networks.

Before building, ensure your ISO file isn’t corrupted. I usually use the Hash Generator to check the SHA-256 checksum. It’s better to spend 10 seconds checking than an hour debugging why the installation failed.

Hard-learned lessons when using Packer

  • Absolutely no hardcoding: Use variables.pkr.hcl for IP settings, usernames, and passwords.
  • Check iso_checksum: Packer will stop immediately if the ISO file is corrupt, saving you from wasted effort.
  • Leverage Makefiles: Group build commands into a Makefile for quick execution, for example, make build-ubuntu.
  • Enable Logging on errors: If a build fails, run PACKER_LOG=1 packer build . to see exactly what it’s doing step-by-step.

Hopefully, this article helps you free your hands from manual VM installations. The sooner you automate, the more time you’ll have to research cooler things. Good luck!

Share: