Skip to content

Automate a Ubuntu Server Daily Build on a VMware Desktop Hypervisor

tenthirtyam/packer-vmware-desktop-ubuntu-daily automates the build of a baseline Ubuntu Server virtual machine on VMware Fusion 13 or later, or VMware Workstation 17 or later, from the latest Ubuntu daily release using Packer and cloud-init.

Run ./ubuntu-daily.sh and the pipeline discovers the current daily ISO, validates the SHA256 checksum, performs a fully unattended installation via cloud-init autoinstall, takes a snapshot, and cleans up. The output is a ready-to-use Ubuntu Server virtual machine, named by build date and architecture, accessible over SSH.

What It Does

The project automates the complete lifecycle of building a baseline Ubuntu Server virtual machine on a local desktop hypervisor:

Downloads the latest Ubuntu Server daily ISO

The script fetches the current daily build directly from Ubuntu's official repository, validates the SHA256 checksum, and caches it locally. If a valid copy is already present, it skips the download entirely.

Builds a virtual machine with Packer

The Packer Plugin for VMware Desktop Hypervisors (vmware-iso builder) creates and configures the virtual machine, handling boot commands, hardware settings, and guest installation end to end.

Installs Ubuntu fully unattended via cloud-init

A cloud-init autoinstall configuration handles the entire OS installation without user interaction: locale, keyboard layout, timezone, SSH server, open-vm-tools, passwordless sudo, and a clean GRUB configuration.

Creates a snapshot and cleans up

After the build completes, a snapshot is taken and temporary files are cleaned up. The virtual machine lands in the output/ directory, organized by build date, ready for use.

Quick Start

The prerequisites are minimal:

Clone the repository and run the build script:

git clone https://github.com/tenthirtyam/packer-vmware-desktop-ubuntu-daily
cd packer-vmware-desktop-ubuntu-daily
./ubuntu-daily.sh

That is the entire workflow. The script handles everything from ISO discovery to the final snapshot.

Password Options

By default, the script generates a cryptographically secure random 12-character password using OpenSSL. The password is displayed in the build summary so you know what it is.

If you prefer a specific password, pass it at invocation without exposing it in your shell history:

./ubuntu-daily.sh --password=<your_password>

How It Works

The Shell Script

ubuntu-daily.sh is the entry point and orchestrator. It handles everything that happens outside of Packer:

  1. Prepends the VMware binary directory to PATH so vmware-vmx is discoverable regardless of how VMware was installed.
  2. Validates that all required tools are present.
  3. Detects the running VMware hypervisor and its version.
  4. Detects the system architecture (AMD64 or ARM64) automatically.
  5. Fetches the latest ISO filename and SHA256 checksum from Ubuntu's daily build server concurrently using background processes.
  6. Downloads and validates the ISO, skipping the download if a valid copy already exists.
  7. Generates or accepts a password, encrypts it with SHA-512 for cloud-init, and passes everything to Packer as variables.
  8. Runs packer init, packer validate, and packer build in sequence.

The script prints a colorized build summary before the build begins, including the detected hypervisor, architecture, ISO filename, checksum, VM name, hostname, username, and generated password.

The Packer Configuration

ubuntu-daily.pkr.hcl defines the vmware-iso source and the build. It requires the Packer Plugin for VMware Desktop Hypervisors v2 or later:

packer {
  required_version = "~> 1"
  required_plugins {
    vmware = {
      source  = "github.com/vmware/vmware"
      version = "~> 2"
    }
  }
}

The configuration handles architecture differences transparently. For ARM64 builds, the firmware is forced to EFI, the guest OS type changes to arm-ubuntu-64, the disk adapter switches to NVMe, and the network adapter uses VMXNET3. These adjustments happen automatically through local variable expressions based on the arch variable passed in by the shell script.

The cloud-init Configuration

The data/user-data.pkrtpl.hcl template drives the unattended Ubuntu installation:

#cloud-config
autoinstall:
  version: 1
  locale: ${locale}
  keyboard:
    layout: ${keyboard_layout}
  identity:
    hostname: ${hostname}
    username: ${username}
    password: ${password}
  ssh:
    install-server: true
    allow-pw: true
  packages:
    - openssh-server
    - open-vm-tools
  user-data:
    disable_root: false
    timezone: ${timezone}
  late-commands:
    - sed -i -e 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/g' /target/etc/ssh/sshd_config
    - echo '${username} ALL=(ALL) NOPASSWD:ALL' > /target/etc/sudoers.d/${username}

Packer serves this file over HTTP during the build. The Ubuntu installer fetches it via the ds=nocloud-net boot parameter, performs a completely hands-off installation, and hands control back to Packer for post-installation steps.

Default Virtual Machine Configuration

Out of the box, the build produces a virtual machine with the following settings:

Setting Default
VM Name ubuntu-YYYYMMDD-{arch} (e.g., ubuntu-20260326-arm64)
Username ubuntu
Password Cryptographically secure random (12 characters)
Memory 4 GB
Disk 20 GB
CPUs 2
Locale en_US
Keyboard Layout us
Timezone UTC
Firmware EFI (automatic for ARM64)

Customizing the Build

If the defaults do not match your needs, create an overrides.pkrvars.hcl file from the provided example:

cp overrides.pkrvars.hcl.example overrides.pkrvars.hcl

Then edit the file to override only the settings you care about. The script detects overrides.pkrvars.hcl automatically and passes it to Packer as a variable file:

# Hardware
vm_cpu    = 4
vm_memory = 12288

# Locale
locale          = "en_GB"
keyboard_layout = "uk"
timezone        = "Europe/London"

# Timeouts
ssh_timeout      = "30m"
shutdown_timeout = "20m"

The keyboard_layouts.json, locales.json, and timezones.json files in the repository root provide the complete list of valid values for their respective settings and are loaded at build time for validation.

Architecture Support

The project supports both AMD64 and ARM64. The architecture is detected automatically at runtime using uname -m. The appropriate Ubuntu Server daily ISO for the detected architecture is fetched from Ubuntu's CDN.

On Apple Silicon Macs running VMware Fusion, the build runs natively as ARM64, producing an ARM64 virtual machine. On Intel Macs and Windows/Linux systems running VMware Workstation, the build produces an AMD64 virtual machine.

ARM64 Differences

ARM64 builds enforce EFI firmware, NVMe disk adapter, VMXNET3 network adapter, and USB XHCI controller automatically. These settings are required for ARM64 guests in VMware and are applied via local variable expressions in the Packer configuration. No manual configuration is needed.

The Virtual Machine Name

Virtual machines are named using the pattern ubuntu-YYYYMMDD-{arch}. For example, a build run on March 26, 2026 on an Apple Silicon Mac produces a VM named ubuntu-20260326-arm64. The same build on an Intel system produces ubuntu-20260326-amd64.

The --force flag is passed to packer build, so running the script again on the same day replaces the existing virtual machine cleanly. This makes the project well suited to a daily build routine where you always want a fresh baseline.

Get the Project

The project is available on GitHub at tenthirtyam/packer-vmware-desktop-ubuntu-daily.

References

Disclaimer

This is not an official VMware by Broadcom document. This is a personal blog post. The information is provided as-is with no warranties and confers no rights. It is not intended to replace official documentation. Please, refer to official documentation for the most up-to-date information.