Omnissa Horizon – Ubuntu 24.04 Desktop Instant Clone Template

This page documents the steps I took to build an Ubuntu 24.04 LTS Desktop golden image for use as an Omnissa Horizon Instant Clone template in my Lab environment. The template uses the Horizon Agent 2506 Easy Installer, realmd and SSSD for AD domain join, and pam_mount with NFS for home directory mounting at login. Since this is an Instant Clone template, the template is not domain joined at snapshot time — Horizon handles domain join for each clone at provision time using a dedicated service account.

Environment

Template VMubt-2404-tpl
OSUbuntu 24.04 LTS Desktop (Noble)
Horizon Agent2506 (Omnissa-horizonagent-linux-x86_64-2506-8.16.0)
Domaindomain.local
PoolHZUBTP1 (Ubuntu instant clone pool)
Pool-accessGU_HZ_HZUBTP1 (AD Entitlement Group)
NFS home servernfsserver.domain.local
NFS export/srv/home/hzubtp1

Prerequisites

  • Ubuntu 24.04 LTS Desktop ISO
  • Horizon Agent 2506 Linux installer package (tar.gz) downloaded from Omnissa
  • DNS A and PTR records created for the template VM before starting
  • NFS home directory server already set up (see Ubuntu NFS Home Directory Server Setup)
  • A dedicated domain join service account with permissions to join computers to the correct OU
  • The computer OU DN where instant clone computer accounts should be created

Step 1 – OS Installation

Install Ubuntu 24.04 LTS Desktop using the standard installer. During installation set the hostname to your template naming convention. After installation, fix /etc/hosts — the installer places a loopback entry using 127.0.1.1 which needs to be replaced with the actual IP and FQDN. Also disable IPv6 to keep things clean in a Windows-dominated AD environment:

Shell
# Fix /etc/hosts - comment out the 127.0.1.1 line and add the real IP
# 127.0.1.1 ubt-2404-tpl
x.x.x.x ubt-2404-tpl.domain.local ubt-2404-tpl
# Disable IPv6
sudo tee -a /etc/sysctl.conf << 'EOF'
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
EOF
sudo sysctl -p

Step 2 – Install VMware Tools and SSH

Use the open-vm-tools-desktop variant — this includes display and clipboard components needed for vSphere console access and Horizon. Plain open-vm-tools is for headless servers only.

Shell
sudo apt update && sudo apt upgrade -y
sudo apt install -y open-vm-tools-desktop openssh-server

Verify VMware Tools is running:

Shell
sudo systemctl status open-vm-tools --no-pager

Step 3 – Install Horizon Agent Prerequisites

The following packages are required before running the Horizon Agent installer. The full list is documented in the Omnissa documentation – Install Linux Dependency Packages for Horizon Agent.

Shell
sudo apt install -y libnss3-tools pulseaudio-utils ca-certificates curl gpg apt-transport-https software-properties-common

Shut down the VM and take a snapshot in vSphere at this point — call it something like 01-base-prereqs. This gives a clean rollback point before running the agent installer.

Step 4 – Install Horizon Agent

Copy the Horizon Agent installer to the VM via SCP and extract it:

PowerShell
scp Omnissa-horizonagent-linux-x86_64-2506-*.tar.gz sysadm@x.x.x.x:/tmp/
ssh sysadm@x.x.x.x
cd /tmp
tar -zxvf Omnissa-horizonagent-linux-x86_64-2506-*.tar.gz
cd Omnissa-horizonagent-linux-x86_64-2506-*/

Run the easy installer. This handles domain join, SSSD configuration, and agent installation in one wizard. When prompted, provide the domain FQDN, the domain join service account credentials, and the OU DN for the computer account. Leave the hostname field blank — instant clones get unique hostnames at provision time.

Shell
sudo ./easyinstall_viewagent.sh

The installer will:

  • Install realmd, sssd-ad, and krb5-user
  • Join the VM to the domain using the provided service account
  • Configure SSSD and start the service
  • Install the Horizon Agent

After installation reboot the VM and verify the agent service is running:

Shell
sudo systemctl status viewagent.service --no-pager

Step 5 – Configure SSSD

The easy installer configures SSSD but leaves use_fully_qualified_names = True and uses the default homedir path. These need to be adjusted so that usernames resolve as short names (required for NFS home directories to work correctly) and the home directory path matches the NFS mount point:

Shell
sudo tee /etc/sssd/sssd.conf << 'EOF'
[sssd]
domains = domain.local
config_file_version = 2
services = nss, pam
[domain/domain.local]
default_shell = /bin/bash
krb5_store_password_if_offline = True
cache_credentials = True
krb5_realm = DOMAIN.LOCAL
realmd_tags = manages-system joined-with-adcli
id_provider = ad
fallback_homedir = /home/%u
ad_domain = domain.local
use_fully_qualified_names = False
ldap_id_mapping = True
access_provider = ad
dyndns_update = False
EOF
sudo chmod 600 /etc/sssd/sssd.conf
sudo sss_cache -E
sudo systemctl restart sssd

Verify that user resolution works with short names and that the UID matches what the NFS server produces for the same user. Both machines must use identical SSSD configuration to guarantee UID consistency:

Shell
id username

Step 6 – Configure NFS Home Directory Mount

Install the NFS client and pam_mount, then enable automatic home directory creation:

Shell
sudo apt install -y nfs-common libpam-mount
sudo pam-auth-update --enable mkhomedir

Configure pam_mount to mount the NFS share at /home on login. Find the closing </pam_mount> tag in the config file and insert the volume entry before it:

Shell
sudo sed -i 's|</pam_mount>|<volume fstype="nfs" server="nfsserver.domain.local" path="/srv/home/hzubtp1" mountpoint="/home" options="rw,sync" />\n</pam_mount>|' /etc/security/pam_mount.conf.xml

Test the mount by switching to a domain user:

Shell
sudo -u username -i
pwd
ls -la
exit

On first login pam_mkhomedir will create the user’s subfolder on the NFS server automatically with correct ownership.

Step 7 – Restrict Domain Logins to Pool Group

Use realmd to restrict which AD group can log in to this desktop. This ensures only entitled users for this pool can authenticate:

Shell
sudo realm deny --all
sudo realm permit -g GU_HZ_HZUBTP1
sudo realm list | grep permitted

Step 8 – Install Applications

Install any applications that should be available to all users in the pool. In this environment the following were installed:

Shell
# PuTTY and Nemo file manager
sudo apt install -y putty nemo
# Set Nemo as default file manager
sudo tee /usr/share/applications/mimeapps.list << 'EOF'
[Default Applications]
inode/directory=nemo.desktop
application/x-gnome-saved-search=nemo.desktop
EOF
# Add Nemo as default for new user home directories
sudo mkdir -p /etc/skel/.config
sudo tee /etc/skel/.config/mimeapps.list << 'EOF'
[Default Applications]
inode/directory=nemo.desktop
application/x-gnome-saved-search=nemo.desktop
EOF
# Google Chrome
wget -q https://dl-ssl.google.com/linux/linux_signing_key.pub -O /tmp/google.pub
sudo gpg --no-default-keyring --keyring /etc/apt/keyrings/google-chrome.gpg --import /tmp/google.pub
echo 'deb [arch=amd64 signed-by=/etc/apt/keyrings/google-chrome.gpg] http://dl.google.com/linux/chrome/deb/ stable main' | sudo tee /etc/apt/sources.list.d/google-chrome.list
sudo apt update
sudo apt install -y google-chrome-stable
# Devolutions Remote Desktop Manager (download deb from devolutions.net first)
sudo apt install -y /tmp/RemoteDesktopManager_*_amd64.deb

Step 9 – Disable Automatic Updates

Automatic updates must be disabled on an instant clone template. If the OS updates itself between snapshots it can change the system state unexpectedly or break the Horizon agent. Updates are applied manually by rebuilding and re-snapshotting the template.

Shell
sudo systemctl disable --now unattended-upgrades
sudo apt remove --autoremove unattended-upgrades -y
sudo systemctl disable apt-daily.timer
sudo systemctl disable apt-daily-upgrade.timer

Step 10 – Remove GNOME Initial Setup

Remove the GNOME first-run wizard so users don’t see it on first login. Also add the done flag to /etc/skel so all new home directories get it automatically:

Shell
sudo apt remove --autoremove gnome-initial-setup -y
sudo mkdir -p /etc/skel/.config
sudo bash -c 'echo "yes" > /etc/skel/.config/gnome-initial-setup-done'

Step 11 – Grant Sudo Access

If pool users need sudo access, add the pool entitlement group to sudoers:

Shell
sudo visudo
# Add the following line at the end:
%gu_hz_hzubtp1 ALL=(ALL:ALL) ALL

Verify the syntax is correct before saving:

Shell
sudo visudo -c

Step 12 – Clean Up and Snapshot

Clean up any temporary files and shut down the VM cleanly before taking the final snapshot:

Shell
sudo rm -rf /tmp/*
sudo shutdown -h now

In vSphere, take a snapshot of the powered-off VM. Name it clearly with a version and date, for example 05-final-template-20260609. This snapshot is what you point the Horizon desktop pool at.

Snapshot History

During the build, snapshots were taken at key milestones to allow rollback without starting from scratch:

01-base-prereqsAfter OS install, VMware Tools, SSH, and Horizon prerequisites
02-domain-joined-nfs-configuredAfter domain join, SSSD configuration, and NFS home mount working
03-horizon-agent-installedAfter Horizon Agent 2506 installation and reboot
04-apps-installedAfter PuTTY, Nemo, Chrome, and RDM installation
05-final-templateAfter disabling updates, removing GNOME setup wizard, configuring sudoers

Omnissa Documentation:

Other Sources:

Disclaimer: Every tips/tricks/posting I have published here, is tried and tested in different IT-solutions. It is not guaranteed to work everywhere, but is meant as a tip for other users out there. Remember, Google is your friend and don’t be afraid to steal with pride! Feel free to comment below as needed.