Introduction
In this blog post, we will explore how to automate the creation of Proxmox images using Packer and Ubuntu 24.04. This process allows us to quickly and efficiently generate customized Proxmox templates that can be used for various purposes, such as testing, development, or production environments.
-
Packer is a powerful tool for automating the creation of machine images across various platforms, including Proxmox. In this blog post, we will explore how to use Packer to create Proxmox images with Ubuntu 24.04 as the base operating system. This process allows us to automate the image creation, making it easier to maintain and update our Proxmox templates.
-
Proxmox VE is an open-source virtualization platform that provides a powerful and flexible environment for running virtual machines and containers. By using Packer, we can automate the creation of Proxmox images, ensuring consistency and efficiency in our infrastructure management.
-
Ubuntu 24.04 is the latest Long Term Support (LTS) release of the popular Linux distribution. It offers improved performance, security, and support for the latest hardware, making it an excellent choice for our Proxmox images.
Prerequisites
The following prerequisites are required to follow along with this guide:
- Proxmox VE installed and running
- Packer installed on your local machines
- Proxmox API access and credentials
- Ubuntu 24.04 ISO file available in your Proxmox storage pool
Code Structure
The directory layout for this project is organized as follows, making use of a modular approach to separate concerns and improve maintainability:
packer
└── linux
└── ubuntu
└── 24-04
├── cidata
│ ├── meta-data
│ └── user-data
├── provider.pkr.hcl
├── ubuntu.pkr.hcl
├── variables.pkr.hcl
└── .env
On the directory we have the following files:
cidata/meta-dataandcidata/user-data: These files under cidata directory contain the cloud-init configuration for the Proxmox image, allowing us to automate the initial setup of the VM.provider.pkr.hcl: This file defines the Proxmox provider configuration for Packer, including the connection details and authentication method.ubuntu.pkr.hcl: This file contains the Packer build configuration for creating the Proxmox image, specifying the source ISO, VM settings, and provisioning steps.variables.pkr.hcl: This file defines the variables used in the Packer configuration, allowing us to easily customize the build process without modifying the main configuration files..env: This file contains sensitive information such as Proxmox API credentials, which are loaded into the environment variables to ensure secure handling of sensitive data.
Setting Up the Proxmox Provider
In the provider.pkr.hcl file, we define the Proxmox provider configuration for Packer. This includes specifying the connection details to the Proxmox API, such as the API URL, username, and password. By using environment variables to store sensitive information, we can ensure that our credentials are not hardcoded in the configuration files, enhancing security.
packer {
required_version = ">= 1.10.3"
required_plugins {
proxmox = {
version = "v1.2.3"
source = "github.com/hashicorp/proxmox"
}
}
}
Setting up variables
In the variables.pkr.hcl file, we define the variables that will be used in our Packer configuration. This allows us to easily customize the build process by simply changing the values of these variables without modifying the main configuration files.
variable "proxmox_api_url" {
type = string
sensitive = true
}
variable "proxmox_username" {
type = string
sensitive = true
}
variable "proxmox_password" {
type = string
sensitive = true
}
variable "insecure_skip_tls_verify" {
type = bool
default = false
}
variable "ssh_authorized_key" {
type = string
sensitive = true
}
variable "ssh_password" {
type = string
sensitive = true
}
variable "vm_name" {
type = string
description = "Name of the Proxmox VM to create"
default = "ubuntu-24.04-template"
}
variable "vm_template_name" {
type = string
description = "Name of the Proxmox VM template to use for provisioning"
default = "ubuntu-24.04-template"
}
variable "iso_storage_pool" {
type = string
description = "Proxmox storage pool where the ISO file is located"
default = "local"
}
variable "iso_file" {
type = string
description = "Path to the ISO file for VM installation"
default = "local:iso/ubuntu-24.04.3-live-server-amd64.iso"
}
variable "network_bridge" {
type = string
description = "Proxmox network bridge to attach VMs to"
default = "vmbr0"
}
variable "storage_pool" {
type = string
description = "Proxmox storage pool for VM disks"
default = "local-zfs"
}
variable "cloudinit_storage_pool" {
type = string
description = "Proxmox storage pool for cloud-init disks"
default = "local"
}
variable "cloudinit_iso_files_dir" {
type = string
description = "Directory containing cloud-init ISO files to attach to VMs"
}
variable "ssh_host" {
type = string
description = "SSH host for provisioning"
default = "localhost"
}
Passing Credentials Securely
To securely pass credentials to Packer, we utilize environment variables. In the .env file, we define the necessary environment variables for Proxmox API access, such as PROXMOX_API_URL, PROXMOX_USERNAME, and PROXMOX_PASSWORD. By sourcing this file before running the Packer build, we ensure that the credentials are available in the environment without exposing them in the configuration files.
#!/bin/bash
export PKR_VAR_proxmox_api_url="https://10.3.0.1:8006/api2/json"
export PKR_VAR_proxmox_username="root@pam"
export PKR_VAR_proxmox_password="your-secure-password"
export PKR_VAR_ssh_authorized_key="ssh-ed25519..."
export PKR_VAR_ssh_password="ubuntu"
export PKR_VAR_ssh_private_key_file="~/.ssh/provisioning-homelab"
export PKR_VAR_vm_template_name="ubuntu-24.04-template"
export PKR_VAR_vm_name="ubuntu-24.04-template"
export PKR_VAR_iso_storage_pool="local"
export PKR_VAR_iso_file="local:iso/ubuntu-24.04-live-server-amd64.iso"
export PKR_VAR_network_bridge="vmbr1"
export PKR_VAR_cloudinit_storage_pool="local"
export PKR_VAR_ssh_host="10.3.1.250"
export PKR_VAR_cloudinit_iso_files_dir="./cidata/*"
Defining the Packer Build Configuration
In the ubuntu.pkr.hcl file, we define the Packer build configuration for creating the Proxmox image. This includes specifying the source ISO file, VM settings such as CPU, memory, and disk size, and the provisioning steps to automate the setup of the VM using cloud-init.
# Ubuntu Server 24.04
source "proxmox-iso" "ubuntu-server-noble" {
# Proxmox Connection Settings
proxmox_url = var.proxmox_api_url
insecure_skip_tls_verify = true
username = var.proxmox_username
password = var.proxmox_password
node = "pve"
task_timeout = "10m"
# VM General Settings
vm_id = "9001"
vm_name = var.vm_name
template_name = var.vm_template_name
template_description = "Ubuntu Server 2404 Image"
boot_iso {
iso_file = var.iso_file
iso_storage_pool = var.iso_storage_pool
unmount = true
}
cpu_type = "host"
sockets = "1"
cores = "4"
memory = "4096"
# VM Network Settings
network_adapters {
bridge = var.network_bridge
model = "virtio"
firewall = "false"
}
disks {
type = "virtio"
disk_size = "20G"
storage_pool = var.storage_pool
format = "raw"
}
os = "l26"
scsi_controller = "virtio-scsi-pci"
onboot = true
qemu_agent = true
bios = "seabios"
additional_iso_files {
cd_files = [var.cloudinit_iso_files_dir]
cd_label = "cidata"
iso_storage_pool = "local"
unmount = true
}
cloud_init = true
cloud_init_storage_pool = var.cloudinit_storage_pool
# Explicitly set boot device and timeout
boot = "c"
boot_wait = "5s"
boot_command = [
"<esc><wait>c",
"linux /casper/vmlinuz --- autoinstall ds=\"nocloud\"",
"<enter><wait5s>",
"initrd /casper/initrd",
"<enter><wait5s>",
"boot",
"<enter>"
]
http_directory = "./cidata/"
communicator = "ssh"
ssh_host = var.ssh_host
ssh_username = "ubuntu"
ssh_password = var.ssh_password
ssh_private_key_file = "~/.ssh/provisioning-homelab"
ssh_timeout = "20m"
}
# Build Definition to create the VM Template
build {
name = "ubuntu-server-2404-template-build"
sources = ["source.proxmox-iso.ubuntu-server-noble"]
provisioner "shell" {
inline = [
"while [ ! -f /var/lib/cloud/instance/boot-finished ]; do echo 'Waiting for cloud-init...'; sleep 1; done",
"sudo truncate -s 0 /etc/machine-id",
"sudo apt -y autoremove --purge",
"sudo apt -y clean",
"sudo apt -y autoclean",
"sudo cloud-init clean",
"sudo rm -f /etc/cloud/cloud.cfg.d/subiquity-disable-cloudinit-networking.cfg",
"sudo sync"
]
}
}
Defining Cloud-Init configuration
The meta-data and user-data files contain the cloud-init configuration for the Proxmox image. This allows us to automate the initial setup of the VM, such as configuring the hostname, setting up users, and installing necessary packages.
meta-data:
instance-id: ubuntu-server-2404-template
hostname: ubuntu-server-2404-template
user-data:
#cloud-config
autoinstall:
interactive-sessions: []
version: 1
locale: en_US
keyboard:
layout: us
ssh:
install-server: true
allow-pw: true
authorized_keys:
- "ssh-ed25519 ... provisioning-homelab"
storage:
layout:
name: direct
swap:
size: 0
network:
version: 2
ethernets:
ens18:
dhcp4: false
addresses:
- 10.3.1.250/24
gateway4: 10.3.0.1
nameservers:
addresses:
- 1.1.1.1
- 8.8.8.8
packages:
- qemu-guest-agent
- cloud-init
user-data:
package_upgrade: true
timezone: Europe/Madrid
users:
- name: ubuntu
passwd: "YOUR-SECURE-PASSWORD"
groups: [adm, sudo]
lock-passwd: false
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
The password for the ubuntu user should be set to a hashed value for security reasons. You can generate a hashed password using the mkpasswd command from the whois package:
~ ❯ mkpasswd --method=SHA-512 --rounds=4096
Password:
$6$rounds=4096$1O6VYVvmNjSMmkE2$j7zzMzvx2bFZzJlbYloUkeqyFdN9BtBZTRO4WYJk/GaApiJ7a3aqvJFqA6.2o4TD1WJgk4LkuSVOgLTI51BFk.
That credentials will be used for the initial setup of the VM, allowing us to log in and perform any necessary configurations after the image is created.
Running the Packer Build
When we have all the configuration files set up, we can run the Packer build process. First, we need to source the .env file to load the environment variables, and then we can execute the build.sh script to start the build process.
source .env
packer init .
packer validate .
packer build .
The output of the build process will show the steps being executed, including creating the CD cloudinit disk, starting the VM, provisioning it with cloud-init, and finally converting it to a template. Once the build is complete, we will have a Proxmox template ready to be used for creating new VMs.
linux/ubuntu/24-04 ❯ source ./cidata/pve-rfl/.env took 5s
linux/ubuntu/24-04 ❯ ./build.sh
The configuration is valid.
<sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: output will be in this color.
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Creating CD disk...
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: xorriso 1.5.6 : RockRidge filesystem manipulator, libburnia project.
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Drive current: -outdev 'stdio:/tmp/packer545272301.iso'
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Media current: stdio file, overwriteable
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Media status : is blank
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Media summary: 0 sessions, 0 data blocks, 0 data, 15.4g free
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: xorriso : WARNING : -volid text does not comply to ISO 9660 / ECMA 119 rules
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Added to ISO image: directory '/'='/tmp/packer_to_cdrom2129445467'
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: xorriso : UPDATE : 3 files added in 1 seconds
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: xorriso : UPDATE : 3 files added in 1 seconds
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: xorriso : UPDATE : 0.00% done
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: ISO image produced: 186 sectors
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Written to medium : 186 sectors at LBA 0
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Writing to 'stdio:/tmp/packer545272301.iso' completed successfully.
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Done copying paths from CD_dirs
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Uploaded ISO to local:iso/packer545272301.iso
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Creating VM
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Starting VM
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Starting HTTP server on port 8949
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Waiting 5s for boot
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Typing the boot command
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Using SSH communicator to connect: 10.3.1.250
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Waiting for SSH to become available...
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Connected to SSH!
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Provisioning with shell script: /tmp/packer-shell3249938312
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Waiting for cloud-init...
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Waiting for cloud-init...
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Waiting for cloud-init...
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Waiting for cloud-init...
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble:
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble:
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Reading package lists...
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Building dependency tree...
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Reading state information...
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: 0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble:
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble:
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble:
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Reading package lists...
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Building dependency tree...
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Reading state information...
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Stopping VM
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Converting VM to template
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Adding a cloud-init cdrom in storage pool local
==> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: Deleted generated ISO from local:iso/packer545272301.iso
Build '<sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble' finished after 20 minutes 9 seconds.
==> Wait completed after 20 minutes 9 seconds
==> Builds finished. The artifacts of successful builds are:
--> <sensitive>-server-2404-template-build.proxmox-iso.<sensitive>-server-noble: A template was created: 9001
Once the build process is complete, we will have a Proxmox template named ubuntu-24.04-template that can be used to create new VMs with the same configuration and setup as defined in our Packer configuration.
You can check it from the Proxmox web interface or using the Proxmox CLI:
root@pve:~# qm list
VMID NAME STATUS MEM(MB) BOOTDISK(GB) PID
...
9001 ubuntu-24.04-template stopped 2048 0.00 0
...


