Deploy HailBytes ASM on Azure via CLI
Programmatic deployment in one shell session. No portal clicks. Works on Azure commercial and Azure Government.
What you’ll do
- Accept the marketplace plan terms (one-time, per subscription).
- Resolve the latest HailBytes ASM URN for your region.
- Launch a hardened VM via
az vm create— or use ARM/Bicep if your shop standardizes on IaC. - Bootstrap admin credentials and generate an API key for REST + MCP access.
- Connect an MCP-aware client (Claude, Cursor, Windsurf) to the new instance.
Estimated time: 5–8 minutes including image acceptance and the cloud-init bootstrap. Estimated infrastructure cost: ~$175/month for a Standard_D4s_v5 in East US (your mileage will vary by region and SKU).
Prerequisites
- Azure CLI, signed in with
az loginand a subscription that allows VM creation and marketplace deployments. - SSH public key; the CLI examples use
~/.ssh/id_ed25519.pub. - An office IP or VPN CIDR to lock the NSG down to. The CLI examples assume
$ALLOW_CIDR.
export RG=hailbytes-asm-rg
export LOCATION=eastus
export VM_NAME=hailbytes-asm
export ALLOW_CIDR=203.0.113.4/32 # your office or VPN
export SSH_KEY=~/.ssh/id_ed25519.pub
az group create --name "$RG" --location "$LOCATION"Step 1 — Accept marketplace terms
Azure requires explicit per-subscription acceptance of marketplace plan terms before az vm create will pull the image. This is the gotcha that breaks first-time CLI deployments.
# Replace these with the published values when prompted.
export PUBLISHER=hailbytes
export OFFER=hailbytes-asm
export SKU=byol
# View current terms
az vm image terms show \
--publisher "$PUBLISHER" --offer "$OFFER" --plan "$SKU"
# Accept once per subscription
az vm image terms accept \
--publisher "$PUBLISHER" --offer "$OFFER" --plan "$SKU"Acceptance persists at the subscription level, not the resource group, so subsequent VMs in any region under the same subscription will deploy without prompting.
Step 2 — Resolve the latest URN
URN=$(az vm image list \
--publisher "$PUBLISHER" --offer "$OFFER" --sku "$SKU" \
--location "$LOCATION" --all \
--query 'sort_by([], &version)[-1].urn' -o tsv)
echo "Resolved URN: $URN"
# e.g. hailbytes:hailbytes-asm:byol:1.4.0Pinning to a specific version (e.g. hailbytes:hailbytes-asm:byol:1.4.0) keeps redeploys deterministic. Using :latest always pulls the newest published image.
Step 3 — Launch via az vm create
az vm create \
--resource-group "$RG" \
--name "$VM_NAME" \
--location "$LOCATION" \
--image "$URN" \
--size Standard_D4s_v5 \
--admin-username hailbytes \
--ssh-key-values "$SSH_KEY" \
--os-disk-size-gb 100 \
--os-disk-encryption-set "" \
--public-ip-sku Standard \
--nsg-rule SSH \
--tags product=hailbytes-asm
# Lock the NSG to your CIDR for both 22 and 443
NSG=$(az network nsg list -g "$RG" \
--query "[?contains(name,'$VM_NAME')].name" -o tsv)
az network nsg rule create -g "$RG" --nsg-name "$NSG" \
--name allow-ssh --priority 100 \
--access Allow --direction Inbound --protocol Tcp \
--source-address-prefixes "$ALLOW_CIDR" \
--destination-port-ranges 22
az network nsg rule create -g "$RG" --nsg-name "$NSG" \
--name allow-https --priority 110 \
--access Allow --direction Inbound --protocol Tcp \
--source-address-prefixes "$ALLOW_CIDR" \
--destination-port-ranges 443
# Capture the public IP for later steps
PUBLIC_IP=$(az vm show -d -g "$RG" -n "$VM_NAME" \
--query publicIps -o tsv)
echo "ASM is bootstrapping at https://$PUBLIC_IP/"Cloud-init runs the docker-compose stack on first boot; that takes 3–5 minutes. Until you point a domain at the VM and run the included certbot helper, the web UI / MCP endpoint is reachable on a self-signed cert.
Alternative — ARM / Bicep
Same outcome via IaC, parameterized for repeat deployments.
az deployment group create \
--resource-group "$RG" \
--template-uri https://hailbytes-marketplace.blob.core.windows.net/asm/azuredeploy.json \
--parameters \
vmName="$VM_NAME" \
adminUsername=hailbytes \
sshPublicKey="$(cat $SSH_KEY)" \
vmSize=Standard_D4s_v5 \
allowedCidr="$ALLOW_CIDR" \
imageUrn="$URN"
az deployment group show \
-g "$RG" -n hailbytes-asm \
--query 'properties.outputs'The published template uses the same Packer-built image; pinning imageUrn to a known good version keeps redeploys deterministic. For multi-region rollouts, parameterize on $LOCATION and let your CI loop the call.
Step 4 — Bootstrap credentials
ssh hailbytes@$PUBLIC_IP
# Inside the VM:
sudo /opt/hailbytes/bin/hailbytes-asm reset-admin --email admin@example.com
# → prints a one-time login URL
sudo /opt/hailbytes/bin/hailbytes-asm api-key create \
--name "ci-bootstrap" \
--description "First key for REST + MCP"
# → prints HAILBYTES_ASM_KEY=... (save it; shown only once)The API key works for both the REST API (X-API-Key header) and the MCP server. Keys are SHA-256 hashed at rest; the plaintext is never stored.
Step 5 — Connect MCP
{
"mcpServers": {
"hailbytes-asm": {
"type": "streamable-http",
"url": "https://<your-asm-host>/mcp/",
"headers": { "X-API-Key": "<HAILBYTES_ASM_KEY>" }
}
}
}Confirm the agent can see HailBytes by asking it to “list targets in HailBytes ASM”. Full tool reference: /mcp/.
Azure Government
Same flow on Azure Government. Set the cloud first, then re-run from Step 1.
az cloud set --name AzureUSGovernment
az login
export LOCATION=usgovvirginia # or usgovtexas, usgovarizonaImage acceptance and URN resolution work identically; the URN is published in the Azure Government marketplace separately. See the security overview for the FedRAMP-aligned posture statement.
Smoke test
# REST
curl -k https://$PUBLIC_IP/api/listTargets/ \
-H "X-API-Key: $HAILBYTES_ASM_KEY" | jq '.recordsTotal'
# MCP
curl -k -I https://$PUBLIC_IP/mcp/ \
-H "X-API-Key: $HAILBYTES_ASM_KEY"Tear-down
# Whole resource group
az group delete --name "$RG" --yes --no-wait
# Or just the deployment created by the ARM/Bicep path
az deployment group delete -g "$RG" -n hailbytes-asmGet the Free HailBytes ASM Getting Started Guide
A 7-part email series covering everything from your first deployment to advanced configuration and real-world workflows. One email per day, no spam.