{"id":2432,"date":"2026-09-22T08:03:24","date_gmt":"2026-09-22T12:03:24","guid":{"rendered":"https:\/\/enterpriseadmins.org\/blog\/?p=2432"},"modified":"2026-09-22T08:03:24","modified_gmt":"2026-09-22T12:03:24","slug":"building-a-rocky-linux-9-8-template-vm-by-hand","status":"publish","type":"post","link":"https:\/\/enterpriseadmins.org\/blog\/virtualization\/building-a-rocky-linux-9-8-template-vm-by-hand\/","title":{"rendered":"Building a Rocky Linux 9.8 Template VM by Hand"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Most of my lab runs on Ubuntu VMs built and updated through Packer, but a recent project called for a Rocky Linux template. Since this isn&#8217;t something I expect to repeat often, I didn&#8217;t want to invest time building out a Packer pipeline for it &#8211; I built the template manually in vSphere instead. Here&#8217;s the process I used, documented for the next time I (or you) need it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Creating the VM<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Start with a new VM in vSphere using these settings:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Name:<\/strong> <code>template-rocky98-minimal<\/code><\/li>\n\n\n\n<li><strong>Compatibility:<\/strong> ESXi 8.0 U2 and later (<code>vmx-21<\/code>)<\/li>\n\n\n\n<li><strong>Guest OS Family:<\/strong> Linux<\/li>\n\n\n\n<li><strong>Guest OS Version:<\/strong> Rocky Linux (64-bit)<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">When customizing the hardware, the only change I made was bumping the hard disk from the default 16GB to <strong>20GB<\/strong>. Everything else was left at its default.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Power on the VM and attach the <code>Rocky-9.8-x86_64-minimal.iso<\/code> installer image.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Installing Rocky Linux<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">From the boot menu, select <strong>Install Rocky Linux Minimal 9.8<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the installer:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Confirm the automatic installation destination \u2014 it should default to the 20GB disk created earlier.<\/li>\n\n\n\n<li>Create a user account:\n<ul class=\"wp-block-list\">\n<li>Username: <code>template-admin<\/code><\/li>\n\n\n\n<li>Grant this user administrator privileges.<\/li>\n\n\n\n<li>Require a password to use the account: <code>VMware1!<\/code><\/li>\n\n\n\n<li>Leave the root account disabled.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Begin the installation.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Post-Install Configuration<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Once the install finishes and you&#8217;ve rebooted into the new system, run the following as root:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo -i\n\ndnf update -y\ndnf install open-vm-tools cloud-init -y\n\nsystemctl enable --now vmtoolsd\n\necho \"ssh_pwauth: unchanged\" | tee \/etc\/cloud\/cloud.cfg.d\/99-ssh-pwauth.cfg\nrm -f \/etc\/ssh\/ssh_host_*\n\nshutdown -h now<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A quick rundown of what this does:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Updates the system and installs <code>open-vm-tools<\/code> and <code>cloud-init<\/code> (so future clones can be provisioned with customization specifications).<\/li>\n\n\n\n<li>Enables and starts the <code>vmtoolsd<\/code> service.<\/li>\n\n\n\n<li>Drops a cloud-init override so it doesn&#8217;t touch the SSH password-authentication setting on first boot of a cloned VM.<\/li>\n\n\n\n<li>Removes the host&#8217;s SSH host keys, so each VM cloned from this template generates its own unique keys on first boot instead of sharing the template&#8217;s.<\/li>\n\n\n\n<li>Shuts the VM down cleanly, ready for conversion.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Finalizing the Template<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before converting, add a VM note for future reference \u2014 something like:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>2026-09-19: Created template<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then convert the VM to a template.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Updating the Template Later<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">If you ever need to make changes inside the guest OS, such as patching, adding packages, etc., you&#8217;ll need to convert the template back to a VM first. Before converting it back to a template again, repeat the cleanup steps so the next clone doesn&#8217;t inherit stale SSH configuration or host keys:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo -i\n\nrm -f \/etc\/ssh\/sshd_config.d\/50-cloud-init.conf\nrm -f \/etc\/ssh\/ssh_host_*\n\nshutdown -h now<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Once it&#8217;s powered off, convert it back to a template.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s it!  A simple, repeatable manual process for a template I don&#8217;t need to fully automate. If this becomes a more frequent need, it&#8217;d be a good candidate to eventually fold into the same Packer-based workflow I use for Ubuntu.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Most of my lab runs on Ubuntu VMs built and updated through Packer, but a recent project called for a Rocky Linux template. Since this isn&#8217;t something I expect to repeat often, I didn&#8217;t want to invest time building out &hellip; <a href=\"https:\/\/enterpriseadmins.org\/blog\/virtualization\/building-a-rocky-linux-9-8-template-vm-by-hand\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":6,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"footnotes":""},"categories":[9,4],"tags":[],"class_list":["post-2432","post","type-post","status-publish","format-standard","hentry","category-lab-infrastructure","category-virtualization"],"_links":{"self":[{"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/posts\/2432","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/comments?post=2432"}],"version-history":[{"count":1,"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/posts\/2432\/revisions"}],"predecessor-version":[{"id":2433,"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/posts\/2432\/revisions\/2433"}],"wp:attachment":[{"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/media?parent=2432"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/categories?post=2432"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/tags?post=2432"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}