Skip to main content

MacStadium VDI Environment

How to Use This Guide

This is a quick reference for troubleshooting common issues. Each section is organized by symptom (what users report or what you observe), followed by its likely causes and diagnostic steps. During an incident:
  1. Find the symptom that matches your situation
  2. Follow the diagnostic commands in order
  3. Apply the recommended solution
  4. Document what worked for your post-incident review
Tool usage guidelines:
  • Primary method: Always use Ansible playbooks for VM operations (deploy, delete, start, stop, image management)
  • Advanced diagnostics: You can SSH to hosts and use orka-engine CLI commands for lower-level troubleshooting
  • Examples: orka-engine vm list, orka-engine vm run --image <image> --net-interface en0
  • Note: All production operations should go through Ansible playbooks to maintain consistency
If your issue isn’t listed here: Escalate using the procedures in Guide B: Day-2 Operations Guide.

VM Provisioning Issues

Symptom: VM Deployment Fails Completely

What you see: deploy.yml playbook fails with error messages Quick diagnostic:
Likely causes and solutions: Most common fix: Image name/tag typo or a registry authentication failure.

Symptom: VMs Deploy But Won’t Start

What you see: Deployment succeeds but VMs show “Stopped” or error status Quick diagnostic:

Likely causes and solutions:

Most common fix: Corrupted image during pull. Re-pull the image to the host and redeploy.

Symptom: Wrong Number of VMs Deployed

What you see: Requested 10 VMs but only 7 deployed, or deployment stopped partway through Quick diagnostic:
Likely causes and solutions: Most common fix: You may have hit the max_vms_per_host limit. Add more hosts to distribute VM load.

Symptom: Can’t Delete VMs

What you see: delete.yml or vm.yml with desired_state=absent fails Quick diagnostic:
Likely causes and solutions: Most common fix: VM is stuck in a hung state. Force stop and delete the VM via SSH to the host.

Citrix VDA Registration Failures

Symptom: New VMs Won’t Register with Citrix

What you see: VMs show as “Unregistered” in Citrix Cloud Console → Monitor → Machines Quick diagnostic:
Likely causes and solutions: Most common fix: Firewall blocking outbound HTTPS from VMs to Citrix Cloud Connector. Verify ports 443, 1494, and 2598 are open.

Symptom: VMs Were Registered, Now Show as Unregistered

What you see: VMs that were working now show “Unregistered” status Quick diagnostic:
  1. Verify the VM is running: ansible-playbook -i dev/inventory list.yml | grep <vm-name>
  2. VNC into the VM and check VDA status: ssh admin@<host-ip> open vnc://<vm-ip>:5900
  3. Navigate to: System Preferences → Citrix VDA. Should show: “Registered” with Cloud Connector details.
  4. Test network connectivity from the VM: ping <cloud-connector-ip> curl https://api.cloud.com
  5. Check VDA service logs. On the VM: Console.app → Search for “Citrix”
Likely causes and solutions: Most common fix: Cloud Connector lost network connectivity or service crashed. Restart the Cloud Connector.

Symptom: VDA Shows “Registration in Progress” Indefinitely

What you see: VDA status remains stuck on “Registering…” and never completes Quick diagnostic:
  1. Check if Cloud Connector is up by navigating to Citrix Cloud Console → Monitor → Cloud Connectors, and look for: Status “Up” or “Down”.
  2. Check if multiple VMs are affected: Monitor → Machines → Filter by Delivery Group. Check if all VMs show as unregistered, or just some.
  3. Test connectivity from VM to Cloud Connector by running ssh admin@<host-ip>, VNC to the VM, then run: ping <cloud-connector-ip>
  4. Check the VDA service on the VM: System Preferences → Citrix VDA.
Likely causes and solutions: Most common fix: Verify that the VM can resolve the Cloud Connector hostname or configure it with a correct/updated IP address.

Symptom: VMs Register But Users Can’t Connect

What you see: Citrix Console shows VMs are “Registered” but users get connection errors Quick diagnostic:
  1. Verify the user is in the correct Delivery Group by navigating to Citrix Cloud Console → Manage → Delivery Groups → Search for the user
  2. Check that the VM is actually in an “Available” state by navigating to Monitor → Machines → and checking the ‘Status’ column. This should show “Available” not “In Use” or “Maintenance”.
  3. Test the connection yourself with a test account by launching a desktop from Citrix Workspace.
  4. Check for Citrix policy issues. Policies → Review policies applied to the impacted Delivery Group.
Likely causes and solutions: Most common fix: User was not added to the Delivery Group. Add the user via Citrix Cloud Console.

Network and Connectivity Problems

Symptom: VMs Can’t Reach Internet

What you see: Users report “No internet connection” / Can’t browse web or download updates Quick diagnostic:
  1. Test basic connectivity from the VM by VNCing into the VM:
    ping 8.8.8.8
    ping google.com
    curl https://google.com
  2. Check the VM network configuration
    ifconfig route -n get default
  3. Check DNS configuration
    cat /etc/resolv.conf
  4. Test connecting from the host to rule out any host issues
    ssh admin@<host-ip>
    ping 8.8.8.8
Likely causes and solutions: Most common fix: DNS is not configured in the golden image. Add DNS servers (e.g., 8.8.8.8, 8.8.4.4) to network config in the image template.

Symptom: VMs Can’t Reach Internal Corporate Services

What you see: “Can’t access file shares” / “Internal apps unreachable” / “Need VPN” Quick diagnostic:
  1. Test connecting from the VM to internal services
ping <internal-server-ip> telnet
<internal-server-ip> <port>
  1. Check routing: traceroute <internal-server-ip>
  2. Test from host (confirm the host has access)
ssh admin@<host-ip>
ping <internal-server-ip>
  1. Check if the VM subnet is allowed through company firewalls. Contact your network IT team with the following information:
Source: VM or subnet
Destination: Internal service IP
Ports needed
Likely causes and solutions: Most common fix: Your firewall rules don’t include the VM subnet. Work with your network team to add the appropriate ‘allow’ rules.

Symptom: Bridged Mode VMs Getting Wrong IPs (192.168.64.x)

What you see: VMs should get corporate IPs but are getting 192.168.64.x private range instead Important prerequisite: Bridged networking requires a DHCP server on your network that can assign IP addresses to VMs. If you don’t have DHCP configured, VMs will fall back to NAT mode with 192.168.64.x addresses. Quick diagnostic:
  1. Check cluster configuration on the MacStadium VDI management node: cat /path/to/cluster.yml | grep vm_network_mode. This should show: vm_network_mode: bridge.
  2. Check host interface configuration: cat /path/to/nodes.yml | grep osx_node_vm_network_interface or check the hosts file: cat /path/to/hosts | grep osx_node_vm_network_interface
  3. Verify that the interface exists on the host: ssh admin@<host-ip> ifconfig | grep <interface-name>
  4. Check DHCP traffic on the interface: ssh admin@<host-ip> sudo tcpdump -i <interface-name> port 67 and port 68
  5. Deploy a test VM and watch for DHCP requests/replies
Likely causes and solutions: Solution steps:
  1. Delete all VMs (this is required before switching networking modes)
ansible-playbook -i dev/inventory delete.yml \
-e "vm_name=<vm-name>"
Run this command once for each additional VM, using a unique vm_name each time.
  1. Verify configuration files
cat cluster.yml should have: vm_network_mode: bridge
cat nodes.yml should have: osx_node_vm_network_interface: <interface>
  1. Reapply the host configuration: ansible-playbook -i dev/inventory configure-hosts.yml
  2. Deploy a test VM:
ansible-playbook -i dev/inventory deploy.yml \
-e "vm_name=test-01" \
-e "vm_image=<your-image>"
  1. Verify that the VM received a corporate IP address: ansible-playbook -i dev/inventory list.yml -e "vm_name=test-01"
Most common fix: osx_node_vm_network_interface is not set or was set incorrectly. Verify the interface name, then reapply the configuration.

Symptom: Intermittent Network Connectivity

What you see: Network works sometimes, drops randomly, packet loss Quick diagnostic:
  1. Run a continuous ping test from the VM by VNCing into the VM and running: ping -c 100 8.8.8.8. Look for the packet loss percentage.
  2. Check for interface errors on the host, and look for errors/drops in output:
ssh admin@<host-ip>
netstat -i
  1. Check host network utilization:
ssh admin@<host-ip>
nload (or: iftop)
  1. Check if the connectivity issue is specific to one host, or impacts all hosts. Test VMs on different hosts to confirm.
Likely causes and solutions: Most common fix: Network congestion or host overloaded. Reduce VMs per host or work with network team on quality of service improvements.

Image Cache and Distribution Issues

Symptom: Image Pull Extremely Slow

What you see: pull_image.yml takes 30+ minutes for reasonably sized images Quick diagnostic:
  1. Test registry connection and speed:
ssh admin@<host-ip>
time curl -o /dev/null https://<registry>/test-file
  1. Check image size by viewing this in your container registry UI
  2. Monitor network utilization during the image pull process
ssh admin@<host-ip>
nload
  1. Check if the repository is rate limiting. Look for throttling messages in the image pull output to confirm/deny this.
ansible-playbook -i dev/inventory pull_image.yml \
-e "remote_image_name=<image>" \
-vvv | grep -i "limit\|throttle"
Likely causes and solutions: Most common fix: Registry is located in a geographically distant datacenter. Deploy the registry closer to Orka hosts or use registry replication.

Symptom: Image Pull Fails with Authentication Error

What you see: “unauthorized” / “authentication required” / “403 Forbidden” Quick diagnostic:
  1. Test registry authentication manually: curl -u <username>:<password> https://<registry>/v2/_catalog
  2. Verify credentials in the Ansible playbook command, and check that the registry_username and registry_password are correct
  3. Test pull with credentials:
ansible-playbook -i dev/inventory pull_image.yml \
-e "remote_image_name=<image>" \
-e "registry_username=<user>" \
-e "registry_password=<pass>" \
-vvv
  1. If available, check the registry access logs. Look for any authentication failures.
Likely causes and solutions: Most common fix: Credentials are outdated or incorrect. Verify and update your registry_username and registry_password values.

Symptom: Image Pull Succeeds, But Deploy Fails

What you see: pull_image.yml succeeds but deploy.yml can’t find image Quick diagnostic:
  1. Verify the image was pulled successfully:
ansible-playbook -i dev/inventory list.yml
  1. Try pulling the image again with verbose output:
ansible-playbook -i dev/inventory pull_image.yml \
-e "remote_image_name=<image-name>" \
-vvv
  1. Check the image name and tags match exactly
  2. Try pulling the image to a specific host
ansible-playbook -i dev/inventory deploy.yml \
-e "vm_name=test-01" \
-e "vm_image=<exact-image-name>" \
--limit <specific-host>
Likely causes and solutions: Most common fix: Image name/tag mismatch between pull and deploy. Ensure an exact match, including image tags.

Symptom: Can’t Push New Image to Registry

What you see: create_image.yml fails during push phase Quick diagnostic:
  1. Run the create_image.yml Ansible playbook with verbose output:
ansible-playbook -i dev/inventory create_image.yml \
-e "vm_image=<source>" \
-e "remote_image_name=<destination>" \
-e "registry_username=<user>" \
-e "registry_password=<pass>" \
-vvv
  1. Check registry authentication
    curl -u <user>:<pass> https://<registry>/v2/_catalog
  2. Check registry storage space
  3. Verify sufficient host disk space: ansible hosts -i dev/inventory -m shell -a "df -h /var/orka"
Likely causes and solutions: Most common fix: Registry authentication or insufficient storage space. Verify credentials and check registry capacity.

Symptom: Inconsistent Images Across Hosts

What you see: The same image name on different hosts, but with different behavior/versions Quick diagnostic:
  1. List VMs on all hosts to check deployment times
ansible-playbook -i dev/inventory list.yml
  1. Check when VMs were last deployed using list.yml to show the VM status
  2. Test pulling an image to verify registry performance
ansible-playbook -i dev/inventory pull_image.yml \
-e "remote_image_name=<image-name>" \
--limit <single-host>
  1. Check the registry for image versions
Likely causes and solutions:

Solution steps:

  1. Pull a fresh image to all hosts
    ansible-playbook -i dev/inventory pull_image.yml \
    -e "remote_image_name=<image>"
  2. Verify all hosts completed pull successfully, check playbook output for any errors
  3. Redeploy VMs from the freshly pulled image
    ansible-playbook -i dev/inventory deploy.yml \
    -e "vm_name=<vm-name>" \
    -e "vm_image=<image>"
    Run this command once for each VM to deploy.
Most common fix: Images were pulled at different times, with registry updates between. Re-pull images to all hosts for consistency.

Performance and Latency Problems

Symptom: Desktop Feels Sluggish for Users What you see: Users report slow response, lag, choppy mouse movement, etc. Quick diagnostic:
  1. Check host resource utilization
    ansible hosts -i dev/inventory -m shell -a "top -l 1 | head -20"
  2. Count VMs per host
    ansible-playbook -i dev/inventory list.yml | grep <host-name> | wc -l
  3. Check specific VM resources by VNCing into the VM:
    open vnc://<vm-ip>:5900
    Open Activity Monitor → Check CPU, Memory, Disk, Network
  4. Test the user’s network latency (if remote). Ask the user to ping the VM IP, or use the Citrix HDX Tester tool
Likely causes and solutions: Most common fix: Host is overloaded. Redistribute VMs across hosts or add capacity.

Symptom: Poor Video Quality or Choppy Playback

What you see: Pixelated screen, blurry text, stuttering video Quick diagnostic:
  1. Check the user’s network bandwidth
  2. Ask the user to run: Speedtest by Ookla - The Global Broadband Speed Test
  1. Check the user’s HDX Visual Quality policy by navigating to: Citrix Cloud Console → Policies.
  1. Test bandwidth/performance with Citrix HDX Monitor (if available), as this shows real-time HDX metrics
  2. Check the user’s connection type (Are they connecting remotely/via VPN? On wifi? Wired?)
Likely causes and solutions: Most common fix: HDX Visual Quality policy too conservative. Increase quality for users with good connections.

Symptom: Slow Login Times (>2 Minutes)

What you see: Long wait from launching desktop to usable desktop Quick diagnostic:
  1. Measure login time components
  1. Check if VM had to boot ansible-playbook -i dev/inventory list.yml | grep <vm-name>
  1. Check user profile size (if using roaming profiles)
  1. Monitor VM resources during login: Watch Activity Monitor during the login process
Most common fix: Large roaming profiles. Implement folder redirection and profile cleanup policies.

Symptom: Application Launches Are Slow

What you see: Apps take 30+ seconds to launch after clicking Quick diagnostic:
  1. Test from within the VM directly
  1. Check if the app is on network share vs. local storage
  1. Check VM disk I/O
  1. Check available memory
Most common fix: Applications installed on network shares. Pre-install in golden image for local execution.

Symptom: High CPU Usage Even When Idle

What you see: VM consuming 50%+ CPU with no user activity Quick diagnostic:
  1. Identify the process consuming CPU by VNCing into the VM, then navigate to Activity Monitor → Sort by %CPU
  2. Check for runaway processes
  1. Check for malware (unlikely but possible)
  1. Monitor over time: Is the CPU spike temporary or sustained?
Likely causes and solutions: Most common fix: Spotlight indexing or macOS maintenance tasks. Usually resolves itself within an hour.

Authentication and Access Control

Symptom: User Can’t Log Into Desktop (Credentials Rejected)

What you see: The user enters their credentials, but gets an “Invalid username or password” error Quick diagnostic:
  1. Verify the user exists in your identity provider by checking Active Directory or Azure AD
  2. Test user login capabilities with a known-good account
  1. Check if the issue is specific to one VM or is impacting all VMs
  1. Check VDA domain binding (if using AD)
Most common fix: The user’s password is expired. Have the user reset their password through your normal corporate process.

Symptom: User Can Log In But Has the Wrong Permissions

What you see: User is authenticated, but they can’t access files/apps they should have access to Quick diagnostic:
  1. Check the user’s group memberships
  1. Verify user permissions on restricted resources
  1. Test with a known-good user from the same group
  1. Check GPO application (if using AD)
Most common fix: The user is not in the required AD group(s). Add them to the appropriate group(s), and then force a GPO refresh.

Symptom: Single Sign-On (SSO) Not Working

What you see: Users are prompted for their SSO credentials despite being logged into iCloud/corporate network Quick diagnostic:
  1. Check Citrix Workspace SSO configuration
  1. Verify Citrix Gateway/SSO configuration is correct
  1. Test SSO login capability with manual credentials
  1. Check the user’s SSO/company domain login
Likely causes and solutions: Most common fix: SSO is not enabled in Citrix Workspace. Enable SSO in the user’s Workspace preferences.

Symptom: Can’t Access Citrix Cloud Admin Console

What you see: Admins can’t log into Citrix Cloud Console to manage environment(s) Quick diagnostic:
  1. Try using a different browser
    • Some browsers cache authentication differently
  2. Clear browser cookies and cache, then try logging in again
  3. Verify your admin account is not locked, check with Citrix support or another admin
  4. Check Citrix Cloud status: https://status.cloud.com
Most common fix: Browser cache issue. Clear your cookies and cache, or try using incognito/private mode.

Ansible Playbook Errors

Symptom: Playbook Fails with “Host unreachable”

What you see: Playbook errors: “Failed to connect to the host via ssh” / “Host is unreachable” Quick diagnostic:
  1. Test basic connectivity ping <host-ip>
  2. Test SSH manually ssh admin@<host-ip>
  3. Check inventory file cat dev/inventory
  1. Test Ansible ping module ansible hosts -i dev/inventory -m ping
Likely causes and solutions: Most common fix: SSH key is not in authorized_keys on host. Add the Ansible control node’s public key to the host.

Symptom: Playbook Fails with “Permission denied”

What you see: Playbook errors with permission/sudo errors during execution Quick diagnostic:
  1. Test basic connectivity ping <host-ip>
  2. Test SSH manually ssh admin@<host-ip>
  3. Check inventory file cat dev/inventory
  1. Test Ansible ping module ansible hosts -i dev/inventory -m ping
Likely causes and solutions: Most common fix: SSH key is not in authorized_keys on host. Add the Ansible control node’s public key to the host.

Symptom: Playbook Fails with “Permission denied”

What you see: Playbook errors with permission/sudo errors during execution Quick diagnostic:
  1. Test sudo access manually
    ssh admin@<host-ip>
    sudo ls /var/orka
  2. Check Ansible inventory settings:
    cat dev/inventory | grep ansible_become
  3. Run the playbook with verbose output ansible-playbook -i dev/inventory <playbook> -vvv
  4. Check if a specific task is failing, and/or look at which task in the playbook fails
Likely causes and solutions: Most common fix: ansible_become=yes not set in inventory. Add to [all:vars] section.

Symptom: Playbook Times Out

What you see: Your Ansible playbook runs, but it times out on specific tasks without completing Quick diagnostic:
  1. Run with verbose output to see where the playbook hangs: ansible-playbook -i dev/inventory <playbook> -vvv
  2. Test the specific command manually by SSHing to the host and running the command that’s timing out
  3. Check if the task requires a long time to complete
  1. Monitor host resources during tasks by running:
    ssh admin@<host-ip>
    top
Likely causes and solutions: Most common fix: Legitimate long-running task (such as an image pull). Increase the async timeout or be patient.

Symptom: Playbook Variables Not Being Applied

What you see: Playbook runs but doesn’t use the variables you specified with -e Quick diagnostic:
  1. Check command syntax
  1. Run with verbose output: ansible-playbook -i dev/inventory <playbook> \ -e "var1=value1" \ -e "var2=value2" \ -vv
  2. Check playbook for variable names, and ensure they match exactly (variable names are case-sensitive)
  3. Check for hard-coded values in the playbook, these might override other variables
Likely causes and solutions: Most common fix: Variable name typo. Check playbook documentation for exact variable names (these are case-sensitive).

Symptom: Playbook Fails Partway Through

What you see: The playbook starts successfully, but fails on a specific task Quick diagnostic:
  1. Run the playbook with verbose output to see the exact error: ansible-playbook -i dev/inventory <playbook> -vvv
  2. Check the specific task that failed, reviewing the error logs carefully
  3. Test the failing task’s command manually by SSHing into the host and running the command
  4. Check if the task is stuck in a partially successful state and needs cleanup, or needs to be re-run
Most common fix: Network or resource interruption. Verify connectivity and available resources, then re-run the playbook.

Symptom: Playbook Says “Changed” But Nothing Actually Changed

What you see: Playbook reports changes, but its state appears identical Quick diagnostic:
  1. Check what the playbook claims to change, look at the task output while the playbook is running
  2. Verify the actual state on the MacStadium VDI host ssh admin@<host-ip> and check if the claimed changes actually exist
  3. Run the playbook in check mode: ansible-playbook -i dev/inventory <playbook> --check
  4. Check for idempotency issues, and run the playbook twice. The task status should display “ok,” the second time, and not “changed”.
Most common fix: The playbook is not properly checking the existing state before making changes (idempotency issue).

Escalation Quick Reference

When to escalate: