Platform setup
How to Deploy OpenClaw on Azure
Browse more in Platform setup.
All platform setup guides →This guide walks you through deploying OpenClaw on an Azure Linux VM using the Azure CLI, with a locked-down network and Bastion-only SSH access. You create the VNet, NSG, VM, and Bastion from the terminal, then run the OpenClaw installer script on the VM.
04 in your Azure subscription.
Prerequisites
- ✓An Azure subscription with permission to create compute and network resources.
- ✓Azure CLI installed on your machine (see Microsoft's Azure CLI install steps if you don't have it yet).
- ✓An SSH key pair available locally; this guide assumes `~/.ssh/id_ed25519` and shows how to generate it if needed.
- ✓20–30 minutes of uninterrupted time to create Azure resources and run the OpenClaw installer.
Steps
- 1
Sign in to Azure CLI and enable SSH extension
Authenticate the Azure CLI so all subsequent commands run against the right subscription, then add the `ssh` extension that Bastion tunneling depends on. Without this extension, the `az network bastion ssh` command you use later will fail.
bashaz login az extension add -n ssh - 2
Register Azure resource providers for compute and networking
Azure needs the Compute and Network resource providers registered before you can create VMs, VNets, NSGs, and Bastion. Run these once per subscription and wait until both show `Registered` before moving on, otherwise later `az` commands will error out.
bashaz provider register --namespace Microsoft.Compute az provider register --namespace Microsoft.Network az provider show --namespace Microsoft.Compute --query registrationState -o tsv az provider show --namespace Microsoft.Network --query registrationState -o tsv - 3
Set deployment variables for your Azure environment
Define all the names, locations, and CIDR ranges up front so you can reuse them across commands and keep your deployment consistent. You can tweak these values to match your conventions, but keep the Bastion subnet at least `/26` or Azure will reject it.
bashRG="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" - 4
Select or generate an SSH key for VM access
OpenClaw runs on a VM that you access over SSH via Bastion, so you need a public key to inject into the VM at creation time. Use your existing `id_ed25519` key if you have one, or generate a new ed25519 key and capture its public half into `SSH_PUB_KEY`.
bashSSH_PUB_KEY="$(cat ~/.ssh/id_ed25519.pub)" ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519 -C "you@example.com" SSH_PUB_KEY="$(cat ~/.ssh/id_ed25519.pub)" - 5
Choose VM size and OS disk size for OpenClaw
Pick a VM SKU and disk size that exist in your region and fit your workload, then verify quotas. The docs default to `Standard_B2as_v2` with a 64 GB disk, and you can list available SKUs and current usage to avoid quota or availability errors during creation.
bashVM_SIZE="Standard_B2as_v2" OS_DISK_SIZE_GB=64 az vm list-skus --location "${LOCATION}" --resource-type virtualMachines -o table az vm list-usage --location "${LOCATION}" -o table - 6
Create the resource group for all OpenClaw Azure resources
Group everything (VNet, NSG, VM, Bastion, public IP) into a single resource group so you can manage or delete it in one shot later. This also keeps your OpenClaw deployment isolated from other infrastructure.
bashaz group create -n "${RG}" -l "${LOCATION}" - 7
Create and harden the Network Security Group
Set up an NSG that only allows SSH from the Bastion subnet and explicitly denies SSH from the internet and other VNet sources. The rule priorities matter: the allow rule at 100 must come before the deny rules at 110 and 120 so Bastion traffic is permitted.
bashaz network nsg create \ -g "${RG}" -n "${NSG_NAME}" -l "${LOCATION}" # Allow SSH from the Bastion subnet only az 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 internet az 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 sources az 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 22 - 8
Create the virtual network and subnets for VM and Bastion
Provision a VNet with a VM subnet that has the NSG attached, then add the special `AzureBastionSubnet` that Bastion requires. Attaching the NSG at the subnet level keeps the VM NIC clean and centralizes your SSH rules.
bashaz 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 subnet az network vnet subnet update \ -g "${RG}" --vnet-name "${VNET_NAME}" \ -n "${VM_SUBNET_NAME}" --nsg "${NSG_NAME}" # AzureBastionSubnet — name is required by Azure az network vnet subnet create \ -g "${RG}" --vnet-name "${VNET_NAME}" \ -n AzureBastionSubnet \ --address-prefixes "${BASTION_SUBNET_PREFIX}" - 9
Create the Ubuntu VM without a public IP
04 LTS VM that will host OpenClaw, using your chosen size and disk. The command explicitly disables a public IP and per-NIC NSG so all SSH goes through Bastion and the subnet-level NSG, and you can later pin the image version instead of `latest` if you want reproducibility.
bashaz 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 "" az vm image list \ --publisher Canonical --offer ubuntu-24_04-lts \ --sku server --all -o table - 10
Create Azure Bastion for managed SSH access
Provision a Standard SKU Bastion host with tunneling enabled so you can SSH into the VM from your terminal without exposing a public IP. Bastion takes several minutes to come up, so expect a short wait before SSH works.
bashaz network public-ip create \ -g "${RG}" -n "${BASTION_PIP_NAME}" -l "${LOCATION}" \ --sku Standard --allocation-method Static az network bastion create \ -g "${RG}" -n "${BASTION_NAME}" -l "${LOCATION}" \ --vnet-name "${VNET_NAME}" \ --public-ip-address "${BASTION_PIP_NAME}" \ --sku Standard --enable-tunneling true - 11
SSH into the VM through Azure Bastion
Once Bastion is ready, use the CLI-based SSH tunneling to open a shell on the VM using your SSH key and admin username. This command looks up the VM resource ID and connects without ever assigning a public IP to the VM.
bashVM_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_ed25519 - 12
Install OpenClaw on the Azure VM
From the VM shell, download the official installer script, run it, and then clean up the temporary file. The installer handles Node LTS and dependencies, installs OpenClaw itself, and launches the onboarding wizard where you pick providers like GitHub Copilot.
bashcurl -fsSL https://openclaw.ai/install.sh -o /tmp/install.sh bash /tmp/install.sh rm -f /tmp/install.sh - 13
Verify the OpenClaw Gateway is running
After the onboarding wizard finishes, confirm that the Gateway service is up and healthy. This command gives you a quick status check so you know the deployment on Azure completed successfully.
bashopenclaw gateway status - 14
Manage costs and clean up Azure resources when done
Azure Bastion and the VM both incur ongoing charges, so deallocate or delete resources when you are not actively using OpenClaw. You can stop compute billing by deallocating the VM, or nuke everything by deleting the resource group.
bashaz vm deallocate -g "${RG}" -n "${VM_NAME}" az vm start -g "${RG}" -n "${VM_NAME}" # restart later az group delete -n "${RG}" --yes --no-wait
Troubleshooting
Azure Bastion creation is stuck in 'Creating' for a long time and SSH via `az network bastion ssh` fails.
Bastion provisioning often takes 5–10 minutes and can take up to 15–30 minutes in some regions. Wait until the Bastion resource shows as fully provisioned in the Azure Portal or via `az` before retrying the SSH command.
VM creation fails with an error about the Bastion subnet size or SSH access not working from Bastion.
Azure requires the Bastion subnet (`AzureBastionSubnet`) to be at least `/26`, and the NSG must allow SSH from that subnet CIDR. Ensure `BASTION_SUBNET_PREFIX` is `/26` or larger and that the NSG rule `AllowSshFromBastionSubnet` uses the same prefix.
BASTION_SUBNET_PREFIX="10.40.1.0/26"
az 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 22Frequently asked questions
Powered by Mem0
Add persistent memory to OpenClaw
Official Mem0 plugin for OpenClaw keeps context across chats and tools. Smaller prompts, lower cost, better continuity for your agents.