Create a VM Template for Rocky Linux 9

It’s fairly easy, but not entirely straightforward, to create a good Linux VM template on VMware vSphere. You’ve come to the right place, though! Let’s walk through all the steps needed to create a reliable, small, and secure VM template on VMware vSphere and VMware Cloud Foundation using Rocky Linux 9.

Create a New VM

First, we need a fresh VM. Make new VM the latest virtual hardware version you can. See “Upgrade VM Hardware Versions” for more discussion on this.

Choose the right operating system. In this case, Rocky Linux is in the list. Alternately, you could choose Red Hat Enterprise Linux 9 for EL-family Linux distributions.

I create all my template VMs as 2 CPU, 4 GB of RAM, and 50 GB of disk. Once we are done partitioning the storage there will be 36 GB free, which is often enough space for my needs. If I need more I just add a second virtual disk and add it to the logical volume manager group.

Ensure the SCSI controller is VMware Paravirtual and the NIC is VMXNET3 and on the correct port group. Linux has had support for pvscsi and vmxnet3 in the kernel for decades, so there is no reason to use other virtual peripheral types.

In VM Options, ensure that the Firmware is set to EFI, and Secure Boot is enabled. You may want to set a boot delay as well. I set mine to 10 seconds (10000 milliseconds) so that my remote console connects in time.

Don’t be concerned about applying the Security Configuration Guide controls at this point, we’ll do that at the end.

Check the Installation Media

Get the Rocky Linux installation ISO from their site. I used the Minimal ISO, figuring I’d get the rest from their online repositories. If that’s not something you can do then make accommodations for yourself.

When you boot you have the option of testing the media. Better yet, you should check to make sure that what you downloaded is the same as what they’re serving. To do that, Rocky Linux supplies a CHECKSUM file with the SHA256 hash of the ISO right on the download page:

# Rocky-x86_64-minimal.iso: 1829634048 bytes

SHA256 (Rocky-x86_64-minimal.iso) = ee3ac97fdffab58652421941599902012179c37535aece76824673105169c4a2

In Powershell you can compute the SHA256 hash of a file with this command:

PS C:\Users\plankers\Downloads> Get-FileHash -Algorithm SHA256 .\Rocky-9.4-x86_64-minimal.iso

Algorithm       Hash                                                                   Path

---------       ----                                                                   ----

SHA256          EE3AC97FDFFAB58652421941599902012179C37535AECE76824673105169C4A2  

These two hashes match so I know I have a good copy of the installation media.

Use the checksum for the file YOU downloaded, not this one! This is just an example.

Install Rocky Linux on the Template VM

Mount the ISO and boot. If you checked the SHA256 hash you probably don’t need to test the media. Select your language and keyboard.

Configure the Network

I want to be able to configure network time and other things from this installation process, so I configure the network first. I give all my templates a known IP address of their own. Because I am not using IPv6 I disable it. Toggle the switch to turn the connection on.

Set the Time & Date

Configure the time zone for your preferences. If you want to use NTP and you configured the network you can toggle this on.

Software Selection

In general, I recommend people do a minimal installation on their templates, then install the packages they need later. Only add things to a template that are absolutely necessary for all the deployed VMs to connect to however you configure your systems. In my case I will almost immediately attach the system to Puppet, which will take care of everything else.

In this case I have the minimal ISO, so the only option for me is “Minimal Install.” If you have the full DVD ISO you will have other options. Choose what you want but keep it small.

Installation Destination

I am not a fan of the cloud-esque “one big root filesystem” approach. For starters, when it fills up someday, and it will, you won’t be able to get into the machine. Another reason is that common security and compliance guidelines require us to isolate certain filesystems, like /var/log/audit. Might as well do that in the template and save some time, especially since mount points are hard to change later.

Select “Custom” under Storage Configuration, then click Done. You will be taken to the Manual Partitioning dialog.

Ensure that new mount points will use the LVM partitioning scheme. Do not check “Encrypt my data” without further consideration. It is often better to use VM Encryption or vSAN Data-at-Rest encryption to protect virtual machine storage.

Click “Click here to create them automatically” to give you a starting point.

Configure Partitions

Once you have some sample partitions, you can edit their parameters. One of the beauties of using LVM partitions is that you can grow them on the fly, dynamically, so you can create smaller template filesystems and allocate space where you need it for workloads later.

Edit and add filesystems so that you have something like what I have:

  • / = 4 GiB
  • /boot/efi = Leave the Default
  • /boot = Leave the Default
  • /var = Add, 2 GiB
  • /opt, Add, 1 GiB
  • /tmp, Add, 1 GiB
  • /home, Add, 1 GiB
  • /var/log, Add, 1 GiB
  • /var/log/audit, Add, 500 MiB
  • /var/tmp, Add, 500 MiB

I also reduce swap to 1 GiB. Some swap is good for an OS, but if you’re doing a lot of paging to disk you should add memory.

One other thing to consider before you leave this screen: changing the name of the volume group on your Linux VM template. Each Linux distribution seems to rename the default volume group to it’s own thing, like “rl” for Rocky Linux. My installations from 20+ years ago used the name “Volume00” and I have lots of scripts that assume that’s the name. So I modify the volume group and change its name. You may want to, too.

When you’re done, you should show 36+ GiB of available space in the volume group. That’s good, it’ll allow you to grow and add filesystems for most workloads without having to resize the VM, and with thin provisioning and UNMAP support that space won’t be wasted.

Clicking Done will get you a list of all the changes. Check them, then accept.


Are you planning for your VMs to crash a lot? I’m not. Do you have a specific need to gather the crash dump information when it does? No, I don’t, either. Can we turn this on later if we need it? Yes.

Shut off kdump so it doesn’t consume RAM we can use in more productive ways.

Root Password

Yes, leaving root enabled long-term is a bad idea. However, someone is going to have to configure this Linux VM template after it’s deployed, and it’s a lot easier to do it via SSH as root. If you don’t use root you’ll have to create another user to do it, and now you have two privileged accounts to protect. Plus, you don’t want to create an actual user in the template, because that doesn’t sit well with least privilege. Create them later after deployment.

My advice here is to set a root password you know, and then use your post-deployment processes to change it to something else after you add local users that can use sudo to elevate their privileges.

Set a root password you can type or paste (because you’ll need to, a few times) and check the “Allow root SSH login with password” box.

User Creation

Don’t. Just use root for right now, as discussed above.

Security Profile

Similar to the root password discussion, I would not do this to a template, for a couple reasons. One, not all workloads have the same requirements, so which one do you pick? Two, these sorts of things break applications, and having the ability to deploy a clean VM to see if it works without the security settings is helpful. Three, once you set it you can’t undo it. Make it part of your deployment process instead.

Begin Install

Click Begin Install and go have lunch. When you get back Reboot and let it come back up.

Post-Install Configuration

At this point you can SSH into the VM as root. You can also log into the console as root, but it’s easier to paste commands into an SSH terminal.

Remove Unneeded Software

A minimal installation is pretty sparse, but you don’t need these hardware firmware packages for a Linux VM template.

yum erase -y linux-firmware-whence linux-firmware microcode_ctl

Add Needed Software

We are going to need a few things, and unfortunately installing Perl will also install hundreds of CPAN modules. We need them for the VMware Tools customization, though.

yum install -y nano bind-utils perl open-vm-tools dbus-tools

Nano is a great editor and it’s simple. Editor holy wars are stupid. Judge yourself and others on the things you get done, not on the tools you used. Bind-utils gets you nslookup. Perl is needed for open-vm-tools, and dbus-tools contains the dbus-uuidgen tool that recreates /etc/machine-id during the VMware Tools customization process.

These are not set up as dependencies in open-vm-tools because some places want to use cloud-init instead. However, what cloud-init needs is a pain in a different direction, so we’ll stick with what works.

Enable LVM Discards

We want to enable LVM to send TRIM and UNMAP discard information down to vSAN, to help keep our VMs space-efficient over time. We want to do this in the template because, as part of the template prep, we are also going to zero out the space so the template is as small as possible.

nano /etc/lvm/lvm.conf

Ctrl-W to search for “issue_discards” and change the line from:

# issue_discards = 0


issue_discards = 1

Make sure you remove the octothorpe (hash) for the comment.

Ctrl-X to save, Y, hit enter to save it to the same file.

Enable the periodic fstrim operation with:

systemctl enable fstrim.timer

This will cause the VM to TRIM its filesystems once a week, on a random timer. This is good, it will keep your VM small on disk.

Update the Linux VM Template

yum -y update

Shut the VM down

shutdown -h now

Take a VM snapshot so you can go back to this state if you need to.

Remove Unnecessary Virtual Hardware

Edit the VM and remove the following items if present. You most likely do not need them for ongoing operations, and they represent additional attack surface, as occasionally there will be a vulnerability disclosed against these types of devices. If you don’t have them on your VMs then you are protected.

  • CD/DVD Drive 1
  • SATA Controller 0 (have to remove the CD/DVD drive first, though)
  • USB Controller

Save the changes, then edit the VM again. This time, in VM Options:

  • VMware Remote Console Options, Maximum number of sessions: 1
  • Encryption, Encrypted vMotion: Required
  • Encryption, Encrypted FT: Required
  • Boot Options, Boot Delay: 5000 milliseconds (helps when trying to attach to the console)
  • Power Management, Standby Response: Suspend the virtual machine

Save the changes.

This guidance comes from the VMware vSphere 8 Security Configuration & Hardening Guide, which I maintain.

Add Advanced Parameters for Security

By default the virtual machine has its advanced parameters configured securely, however I want to go a step further and prevent network booting. To do this I edit the VM and add:

bios.bootDeviceClasses with the value "allow:hd"

bios.bootDeviceClasses has the format “allow:XXXX” or “deny:XXXX” where XXXX is a comma-delimited list of boot classes. Boot classes are net (network PXE boot), usb (from attached USB devices), pcmcia (PCMCIA expansion cards, not used nowadays), cd (from attached virtual CD/DVD devices), hd (from attached virtual hard disks), fd (from attached virtual floppy devices), reserved (from unknown devices), efishell (into the EFI shell), all, or any (same as all).

Use of allow or deny also implicitly states the opposite. For example, deny:all disallows all boot, deny:net disallows network boot but allows all others, allow:hd allows only hd boot denies all others, allow:hd,cd allows hd then cd device boot and denies all others.

Save the changes.

Test Cloning & Customization

From here you should test cloning and guest OS customization. The Event Log under “Monitor -> Tasks and Events” in the vSphere Client will show you if the customization succeeded, and if not, where the error log is. Common problems stem from forgetting to install the bind-utils, perl, open-vm-tools, or dbus-tools packages as directed above!

Midjourney rendering of Linux VM Templates