In the previous post, I covered how to license a standalone ESX 9.0 host by importing a private license file directly on the host with esxcli. That workflow was straightforward: generate a keypair, grab a license file from the portal, scp both files to the host, run two esxcli commands, done.

VCF 9.1 changes everything.

Starting with 9.1, you cannot generate individual ESX host licenses from the VCF Business Services console and apply them directly. Instead, Broadcom introduced a License Server appliance — a small OVA that sits between the portal and your hosts. You import your private license file into the License Server, and the License Server issues host-scoped licenses to each ESX host via API.

This post walks through the full end-to-end workflow based on the official VCF 9.1 Licensing – Private License Files documentation.


The Big Disclaimer (Again)

Same rules apply from the previous post:

  • You need a valid subscription/entitlement
  • You need access to the VCF Business Services licensing portal
  • You must be approved for private license files

If you don’t have entitlements, this won’t help — and it shouldn’t.


What Changed in 9.1 vs 9.0

VCF 9.0VCF 9.1
License deliveryDirect private license file → ESX hostLicense Server OVA → host-scoped licenses
esxcli workflowImport key + token directly on hostImport host-scoped token from License Server
License ServerNot required for standalone hostsRequired — even without VCF Operations
Portal license type“ESX host”“License server and standalone hosts without VCF Operations (9.1+)”
9.0 → 9.1 upgradeN/AHost loses its license and is not in evaluation mode — you must complete the new workflow before workloads can run

⚠️ Critical: If you upgrade a standalone host from 9.0 to 9.1, the host loses its license immediately and is not placed in evaluation mode. You cannot start workloads until the new licensing workflow is complete. Plan accordingly.


High-Level Workflow

Here’s the 30,000-foot view before we dive into each step:

  1. Deploy the License Server OVA (can run on any vCenter, even pre-9.x)
  2. Generate an RSA keypair for the License Server
  3. Create a Private License File in the VCF Business Services portal (type: standalone hosts)
  4. Import the private key into the License Server (via API)
  5. Import the license file into the License Server (via API)
  6. Get the host ID from the ESX 9.1 host (ESXCLI)
  7. Get the core count from the ESX host (ESXCLI)
  8. Request a host-scoped license from the License Server (API)
  9. Download the host-scoped license from the License Server (API)
  10. Apply the host-scoped license to the ESX host (ESXCLI)

What You Need

  • A vCenter instance (any version, even pre-9.x) to deploy the License Server OVA
  • The License Server OVA file from support.broadcom.com
  • SSH access to the ESX 9.1 host
  • A machine with openssl and curl (or PowerShell)
  • Access to the VCF Business Services console

Step 1 — Deploy the License Server OVA

Download the License Server OVA from support.broadcom.com and deploy it in any vCenter instance.

During the OVA deployment, pay attention to these settings under Customize template:

SettingValue
Unique Registration Key (under Application)Set to NA
API Key (under Advanced Configuration)Set a unique client secret — you’ll need this for every API call

💡 Tip: Treat the API Key like a password. You’ll use it as an X-API-Key header in every API call to the License Server.


Step 2 — Generate an RSA Key Pair

Same as before — generate a 4096-bit RSA keypair:

openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:4096
openssl rsa -pubout -in private_key.pem -out public_key.pem

Optionally combine them:

cat private_key.pem public_key.pem > keypair.pem

🔐 Keep both keys safe. The portal does not save the public key unless you explicitly check “Save Public Keys” during the wizard.


Step 3 — Create a Private License File in the Portal

Log in to the VCF Business Services console and:

  1. Navigate to License ManagementVCF Operations Registrations
  2. Click Create Private License File
  3. In the Define Private License File section:
    • Enter a display name
    • Max VCF Version: select 9.1 (or higher)
    • Licensed Environment: select “License server and standalone hosts without VCF Operations (9.1+)”
    • Click Save
  4. In the Allocate Licenses section:
    • Enter a display name for the license server (doesn’t need to match the hostname)
    • Select the licenses to allocate, click Confirm
  5. In the Download and Import Private License File section:
    • Paste the encoded RSA public key (PEM format) under “Enter Public Key for Standalone License Server”
    • (Optional) Check Save Public Keys
    • Click Download to get the license file
    • Click Done

⚠️ Wrong license type = failure. If you select “VCF Operations with license servers” instead of the standalone option, the license assignment will fail when you try to use it.


Step 4 — Import the Private Key into the License Server

Use the License Server API to import your private key:

Bash (curl):

# Variables
LS_IP="10.1.2.3"                     # License Server IP or FQDN
API_KEY="your-api-key-here"          # The API Key from OVA deployment
KEY_PATH="/path/to/private_key.pem"  # Path to the private key

curl -X POST "https://$LS_IP/lss/external/api/v1/identity/key" \
  -H "X-API-Key: $API_KEY" \
  -F "file=@$KEY_PATH"

PowerShell:

# Variables
$licenseServer = "license-server.example.local"
$apiKey = "your-api-key-here"
$privateKeyPemFilePath = "C:\path\to\private_key.pem"

$headers = @{ "X-API-Key" = $apiKey }

Invoke-RestMethod -Uri "https://$licenseServer/lss/external/api/v1/identity/key" `
                  -Method Post `
                  -Headers $headers `
                  -Form @{ file = Get-Item $privateKeyPemFilePath }

Step 5 — Import the License File into the License Server

Now import the license file you downloaded from the portal:

Bash (curl):

LS_IP="10.1.2.3"
API_KEY="your-api-key-here"
LIC_PATH="/path/to/vcf-license.lic"

curl -X POST "https://$LS_IP/lss/external/api/v1/license" \
  -H "X-API-Key: $API_KEY" \
  -F "file=@$LIC_PATH"

PowerShell:

$licenseServer = "license-server.example.local"
$apiKey = "your-api-key-here"
$licenseFilePath = "C:\path\to\vcf-license.lic"

$headers = @{ "X-API-Key" = $apiKey }

Invoke-RestMethod -Uri "https://$licenseServer/lss/external/api/v1/license" `
                  -Method Post `
                  -Headers $headers `
                  -Form @{ file = Get-Item $licenseFilePath }

Step 6 — Get the Host ID and Core Count from the ESX Host

SSH into the ESX 9.1 host and grab two pieces of information:

Get the host hardware ID:

esxcli licensing host id get

Get the core count:

esxcli hardware cpu global get

Look for the CPU Cores value. Write both down — you’ll need them for the next API call.


Step 7 — Get the Available Allocations from the License Server

Before you can request a host-scoped license, you need to know which license allocation to use:

Bash (curl):

LS_IP="10.1.2.3"
API_KEY="your-api-key-here"

curl -X GET "https://$LS_IP/lsc/entitlements/standalone" \
  -H "X-API-Key: $API_KEY"

PowerShell:

$licenseServer = "license-server.example.local"
$apiKey = "your-api-key-here"
$headers = @{ "X-API-Key" = $apiKey }

Invoke-RestMethod -Uri "https://$licenseServer/lsc/entitlements/standalone" `
                  -Method Get `
                  -Headers $headers

Note the allocation_id from the response — you’ll need it next.


Step 8 — Request a Host-Scoped License

Now tie it all together. Use the allocation ID, host ID, and core count to request a host-scoped license:

Bash (curl):

LS_IP="10.1.2.3"
API_KEY="your-api-key-here"
ALLOC_ID="3fa85f64-5717-4562-b3fc-2c963f66afa6"     # From Step 7
HOST_ID="642351e9-a7ac-48af-98f0-18d373e3528f"       # From Step 6
USAGE=32                                              # Core count from Step 6

curl -X POST "https://$LS_IP/lsc/entitlements/standalone/assignments" \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"allocation_id\": \"$ALLOC_ID\",
    \"assets\": [
      {
        \"id\": \"$HOST_ID\",
        \"product_family\": \"VMware ESX Server\",
        \"product_family_version\": \"9.1\",
        \"usage\": $USAGE
      }
    ]
  }"

PowerShell:

$licenseServer = "license-server.example.local"
$apiKey = "your-api-key-here"
$allocationId = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
$hostHardwareId = "642351e9-a7ac-48af-98f0-18d373e3528f"
$coreUsage = 32

$headers = @{
    "X-API-Key" = $apiKey
    "Content-Type" = "application/json"
}

$body = @{
    allocation_id = $allocationId
    assets = @(
        @{
            id = $hostHardwareId
            product_family = "VMware ESX Server"
            product_family_version = "9.1"
            usage = $coreUsage
        }
    )
} | ConvertTo-Json

Invoke-RestMethod -Uri "https://$licenseServer/lsc/entitlements/standalone/assignments" `
                  -Method Post `
                  -Headers $headers `
                  -Body $body

Step 9 — Download the Host-Scoped License

Download the license that was just generated for your specific host:

Bash (curl):

LS_IP="10.1.2.3"
API_KEY="your-api-key-here"
HOST_ID="642351e9-a7ac-48af-98f0-18d373e3528f"

curl -X GET "https://$LS_IP/lsc/assets/standalone/$HOST_ID/entitlement" \
  -H "X-API-Key: $API_KEY" \
  -o /tmp/host-scoped-entitlement.token

PowerShell:

$licenseServer = "license-server.example.com"
$apiKey = "your-api-key-here"
$hostId = "642351e9-a7ac-48af-98f0-18d373e3528f"
$headers = @{ "X-API-Key" = $apiKey }

Invoke-RestMethod -Uri "https://$licenseServer/lsc/assets/standalone/$hostId/entitlement" `
                  -Method Get `
                  -Headers $headers `
                  -OutFile "host-scoped-entitlement.token"

Copy the downloaded token to the ESX host:

scp /tmp/host-scoped-entitlement.token root@<esx-host>:/tmp/

Step 10 — Apply the Host-Scoped License on the ESX Host

SSH into the ESX host and apply the token:

esxcli licensing entitlement add --file /tmp/host-scoped-entitlement.token

Verify it:

esxcli licensing entitlement list

Your host should now show a valid license. 🎉


Complete Bash Script

Here’s a consolidated script that covers the License Server API steps (4–9). Run this from a workstation that can reach both the License Server and the ESX host:

#!/bin/bash
set -euo pipefail

# ── Configuration ──────────────────────────────────────
LS_IP="10.1.2.3"                          # License Server IP/FQDN
API_KEY="your-api-key-here"               # License Server API Key
KEY_PATH="/tmp/private_key.pem"           # RSA private key
LIC_PATH="/tmp/vcf-license.lic"           # License file from portal
ESX_HOST="root@esx-host.example.local"    # ESX host SSH target

# ── Step 4: Import private key into License Server ─────
echo ">>> Importing private key into License Server..."
curl -s -X POST "https://$LS_IP/lss/external/api/v1/identity/key" \
  -H "X-API-Key: $API_KEY" \
  -F "file=@$KEY_PATH"

# ── Step 5: Import license file into License Server ────
echo -e "\n>>> Importing license file into License Server..."
curl -s -X POST "https://$LS_IP/lss/external/api/v1/license" \
  -H "X-API-Key: $API_KEY" \
  -F "file=@$LIC_PATH"

# ── Step 6: Get host ID and core count from ESX host ───
echo -e "\n>>> Getting host ID from ESX host..."
HOST_ID=$(ssh "$ESX_HOST" "esxcli licensing host id get" | awk '{print $NF}')
echo "Host ID: $HOST_ID"

CORE_COUNT=$(ssh "$ESX_HOST" "esxcli hardware cpu global get" | grep "CPU Cores" | awk '{print $NF}')
echo "Core Count: $CORE_COUNT"

# ── Step 7: Get available allocations ──────────────────
echo -e "\n>>> Getting available allocations..."
ALLOC_RESPONSE=$(curl -s -X GET "https://$LS_IP/lsc/entitlements/standalone" \
  -H "X-API-Key: $API_KEY")
echo "$ALLOC_RESPONSE" | python3 -m json.tool

# NOTE: You'll need to extract the allocation_id from the response above.
# Replace the value below with the actual allocation_id.
ALLOC_ID="REPLACE_WITH_ALLOCATION_ID"

# ── Step 8: Request host-scoped license ────────────────
echo -e "\n>>> Requesting host-scoped license..."
curl -s -X POST "https://$LS_IP/lsc/entitlements/standalone/assignments" \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"allocation_id\": \"$ALLOC_ID\",
    \"assets\": [
      {
        \"id\": \"$HOST_ID\",
        \"product_family\": \"VMware ESX Server\",
        \"product_family_version\": \"9.1\",
        \"usage\": $CORE_COUNT
      }
    ]
  }"

# ── Step 9: Download host-scoped license ───────────────
echo -e "\n>>> Downloading host-scoped license..."
curl -s -X GET "https://$LS_IP/lsc/assets/standalone/$HOST_ID/entitlement" \
  -H "X-API-Key: $API_KEY" \
  -o /tmp/host-scoped-entitlement.token

# ── Step 10: Apply to ESX host ─────────────────────────
echo -e "\n>>> Copying token to ESX host and applying..."
scp /tmp/host-scoped-entitlement.token "$ESX_HOST":/tmp/
ssh "$ESX_HOST" "esxcli licensing entitlement add --file /tmp/host-scoped-entitlement.token"
ssh "$ESX_HOST" "esxcli licensing entitlement list"

echo -e "\n✅ Done. Host should now be licensed."

Upgrading from 9.0 to 9.1? Extra Steps

If you’re upgrading a standalone host that was previously licensed under the 9.0 workflow (from the previous post):

  1. Deploy a License Server OVA (Steps 1–2 above)
  2. In the VCF Business Services console, edit your existing private registration:
    • Update Max VCF Version to 9.1
    • Change Licensed Environment to “License server and standalone hosts without VCF Operations”
    • Provide the new public key for the License Server
    • Download the new license file
  3. Import the license file into the License Server (Step 5)
  4. Upgrade the host to ESX 9.1
  5. Complete Steps 6–10 to apply the host-scoped license

⚠️ After the upgrade, the host has no license and is NOT in evaluation mode. VMs will not power on. Complete the licensing workflow before upgrading, or plan for downtime.


Reclaiming License Capacity

If you reinstall an ESX host, replace hardware, or decommission a server, you’ll need to reclaim the license capacity from the License Server so it can be reassigned:

# Get current license assignments for a host
curl -X GET "https://$LS_IP/lsc/assets/standalone/$HOST_ID/entitlement" \
  -H "X-API-Key: $API_KEY"

Consult the official PDF (page 25) for the full reclaim procedure — it requires additional API calls with the allocation ID.


License Server Maintenance Notes

  • License Servers cannot be updated in-place. If you need a newer version, deploy a new OVA and re-import your keys and license file.
  • The License Server can run on any vCenter instance, including pre-9.x versions.
  • Existing host licenses are not affected when you swap the License Server appliance.
  • You can use the same public/private key pair on the new License Server, or generate new ones.

Common Gotchas

  • Wrong Licensed Environment type: If you select “VCF Operations with license servers” instead of “License server and standalone hosts without VCF Operations (9.1+)”, the license won’t work for standalone hosts.
  • Forgot the API Key during OVA deployment: You can update it later via vApp Options on the License Server VM (must be powered off first).
  • Host loses license after 9.0 → 9.1 upgrade: This is by design. The host is not placed in evaluation mode. Complete the licensing workflow before or immediately after the upgrade.
  • Trying the old 9.0 direct-apply workflow: The esxcli licensing credential add + esxcli licensing entitlement add approach from 9.0 no longer works for portal-generated license files. You must go through the License Server.
  • Self-signed certs on the License Server: You may need -k / --insecure with curl, or Invoke-RestMethod -SkipCertificateCheck in PowerShell.

References