Azure
OpenClaw on Azure Linux VM
Section titled “OpenClaw on Azure Linux VM”This guide sets up an Azure Linux VM with the Azure CLI, applies Network Security Group (NSG) hardening, configures Azure Bastion for SSH access, and installs OpenClaw.
What you will do
Section titled “What you will do”- Create Azure networking (VNet, subnets, NSG) and compute resources with the Azure CLI
- Apply Network Security Group rules so VM SSH is allowed only from Azure Bastion
- Use Azure Bastion for SSH access (no public IP on the VM)
- Install OpenClaw with the installer script
- Verify the Gateway
What you need
Section titled “What you need”- An Azure subscription with permission to create compute and network resources
- Azure CLI installed (see Azure CLI install steps if needed)
- An SSH key pair (the guide covers generating one if needed)
- ~20-30 minutes
Configure deployment
Section titled “Configure deployment”Sign in to Azure CLI
Terminal window az loginaz extension add -n sshThe
sshextension is required for Azure Bastion native SSH tunneling.Register required resource providers (one-time)
Terminal window az provider register --namespace Microsoft.Computeaz provider register --namespace Microsoft.NetworkVerify registration. Wait until both show
Registered.Terminal window az provider show --namespace Microsoft.Compute --query registrationState -o tsvaz provider show --namespace Microsoft.Network --query registrationState -o tsvSet deployment variables
Terminal window RG="rg-openclaw"LOCATION="westus2"VNET_NAME="vnet-openclaw"VNET_PREFIX="10.40.0.0/16"VM_SUBNET_NAME="snet-openclaw-vm"VM_SUBNET_PREFIX="10.40.2.0/24"BASTION_SUBNET_PREFIX="10.40.1.0/26"NSG_NAME="nsg-openclaw-vm"VM_NAME="vm-openclaw"ADMIN_USERNAME="openclaw"BASTION_NAME="bas-openclaw"BASTION_PIP_NAME="pip-openclaw-bastion"Adjust names and CIDR ranges to fit your environment. The Bastion subnet must be at least
/26.Select SSH key
Use your existing public key if you have one:
Terminal window SSH_PUB_KEY="$(cat ~/.ssh/id_ed25519.pub)"If you don’t have an SSH key yet, generate one:
Terminal window SSH_PUB_KEY="$(cat ~/.ssh/id_ed25519.pub)"Select VM size and OS disk size
Terminal window VM_SIZE="Standard_B2as_v2"OS_DISK_SIZE_GB=64Choose a VM size and OS disk size available in your subscription and region:
- Start smaller for light usage and scale up later
- Use more vCPU/RAM/disk for heavier automation, more channels, or larger model/tool workloads
- If a VM size is unavailable in your region or subscription quota, pick the closest available SKU
List VM sizes available in your target region:
Terminal window az vm list-skus --location "${LOCATION}" --resource-type virtualMachines -o tableCheck your current vCPU and disk usage/quota:
Terminal window az vm list-usage --location "${LOCATION}" -o table
Deploy Azure resources
Section titled “Deploy Azure resources”Create the resource group
Terminal window az group create -n "${RG}" -l "${LOCATION}"Create the network security group
Create the NSG and add rules so only the Bastion subnet can SSH into the VM.
Terminal window az network nsg create \-g "${RG}" -n "${NSG_NAME}" -l "${LOCATION}"# Allow SSH from the Bastion subnet onlyaz network nsg rule create \-g "${RG}" --nsg-name "${NSG_NAME}" \-n AllowSshFromBastionSubnet --priority 100 \--access Allow --direction Inbound --protocol Tcp \--source-address-prefixes "${BASTION_SUBNET_PREFIX}" \--destination-port-ranges 22# Deny SSH from the public internetaz network nsg rule create \-g "${RG}" --nsg-name "${NSG_NAME}" \-n DenyInternetSsh --priority 110 \--access Deny --direction Inbound --protocol Tcp \--source-address-prefixes Internet \--destination-port-ranges 22# Deny SSH from other VNet sourcesaz network nsg rule create \-g "${RG}" --nsg-name "${NSG_NAME}" \-n DenyVnetSsh --priority 120 \--access Deny --direction Inbound --protocol Tcp \--source-address-prefixes VirtualNetwork \--destination-port-ranges 22The rules are evaluated by priority (lowest number first): Bastion traffic is allowed at 100, then all other SSH is blocked at 110 and 120.
Create the virtual network and subnets
Create the VNet with the VM subnet (NSG attached), then add the Bastion subnet.
Terminal window az network vnet create \-g "${RG}" -n "${VNET_NAME}" -l "${LOCATION}" \--address-prefixes "${VNET_PREFIX}" \--subnet-name "${VM_SUBNET_NAME}" \--subnet-prefixes "${VM_SUBNET_PREFIX}"# Attach the NSG to the VM subnetaz network vnet subnet update \-g "${RG}" --vnet-name "${VNET_NAME}" \-n "${VM_SUBNET_NAME}" --nsg "${NSG_NAME}"# AzureBastionSubnet — name is required by Azureaz network vnet subnet create \-g "${RG}" --vnet-name "${VNET_NAME}" \-n AzureBastionSubnet \--address-prefixes "${BASTION_SUBNET_PREFIX}"Create the VM
The VM has no public IP. SSH access is exclusively through Azure Bastion.
Terminal window az vm create \-g "${RG}" -n "${VM_NAME}" -l "${LOCATION}" \--image "Canonical:ubuntu-24_04-lts:server:latest" \--size "${VM_SIZE}" \--os-disk-size-gb "${OS_DISK_SIZE_GB}" \--storage-sku StandardSSD_LRS \--admin-username "${ADMIN_USERNAME}" \--ssh-key-values "${SSH_PUB_KEY}" \--vnet-name "${VNET_NAME}" \--subnet "${VM_SUBNET_NAME}" \--public-ip-address "" \--nsg ""--public-ip-address ""prevents a public IP from being assigned.--nsg ""skips creating a per-NIC NSG (the subnet-level NSG handles security).Reproducibility: The command above uses
latestfor the Ubuntu image. To pin a specific version, list available versions and replacelatest:Terminal window az vm image list \--publisher Canonical --offer ubuntu-24_04-lts \--sku server --all -o tableCreate Azure Bastion
Azure Bastion provides managed SSH access to the VM without exposing a public IP. Standard SKU with tunneling is required for CLI-based
az network bastion ssh.Terminal window az network public-ip create \-g "${RG}" -n "${BASTION_PIP_NAME}" -l "${LOCATION}" \--sku Standard --allocation-method Staticaz network bastion create \-g "${RG}" -n "${BASTION_NAME}" -l "${LOCATION}" \--vnet-name "${VNET_NAME}" \--public-ip-address "${BASTION_PIP_NAME}" \--sku Standard --enable-tunneling trueBastion provisioning typically takes 5-10 minutes but can take up to 15-30 minutes in some regions.
Install OpenClaw
Section titled “Install OpenClaw”SSH into the VM through Azure Bastion
Terminal window VM_ID="$(az vm show -g "${RG}" -n "${VM_NAME}" --query id -o tsv)"az network bastion ssh \--name "${BASTION_NAME}" \--resource-group "${RG}" \--target-resource-id "${VM_ID}" \--auth-type ssh-key \--username "${ADMIN_USERNAME}" \--ssh-key ~/.ssh/id_ed25519Install OpenClaw (in the VM shell)
Terminal window curl -fsSL https://openclaw.ai/install.sh -o /tmp/install.shbash /tmp/install.shrm -f /tmp/install.shThe installer installs Node LTS and dependencies if not already present, installs OpenClaw, and launches the onboarding wizard. See Install for details.
Verify the Gateway
After onboarding completes:
Terminal window openclaw gateway statusMost enterprise Azure teams already have GitHub Copilot licenses. If that is your case, we recommend choosing the GitHub Copilot provider in the OpenClaw onboarding wizard. See GitHub Copilot provider.
Cost considerations
Section titled “Cost considerations”Azure Bastion Standard SKU runs approximately $140/month and the VM (Standard_B2as_v2) runs approximately $55/month.
To reduce costs:
-
Deallocate the VM when not in use (stops compute billing; disk charges remain). The OpenClaw Gateway will not be reachable while the VM is deallocated — restart it when you need it live again:
Terminal window az vm deallocate -g "${RG}" -n "${VM_NAME}"az vm start -g "${RG}" -n "${VM_NAME}" # restart later -
Delete Bastion when not needed and recreate it when you need SSH access. Bastion is the largest cost component and takes only a few minutes to provision.
-
Use the Basic Bastion SKU (~$38/month) if you only need Portal-based SSH and don’t require CLI tunneling (
az network bastion ssh).
Cleanup
Section titled “Cleanup”To delete all resources created by this guide:
az group delete -n "${RG}" --yes --no-waitThis removes the resource group and everything inside it (VM, VNet, NSG, Bastion, public IP).
Next steps
Section titled “Next steps”- Set up messaging channels: Channels
- Pair local devices as nodes: Nodes
- Configure the Gateway: Gateway configuration
- For more details on OpenClaw Azure deployment with the GitHub Copilot model provider: OpenClaw on Azure with GitHub Copilot