Deploy self-hosted, always-on OpenClaw AI agents on Azure with NSG hardening and Bastion-secured access
Many teams want an enterprise-ready personal AI assistant, but they need it on infrastructure they control, with security boundaries they can explain to IT. That is exactly where OpenClaw fits on Azure.
OpenClaw is a self-hosted, always-on personal agent runtime you run in your enterprise environment and Azure infrastructure. Instead of relying only on a hosted chat app from a third-party provider, you can deploy, operate, and experiment with an agent on an Azure Linux VM you control — using your existing GitHub Copilot licenses, Azure OpenAI deployments, or API plans from OpenAI, Anthropic Claude, Google Gemini, and other model providers you already subscribe to. Once deployed on Azure, you can interact with an OpenClaw agent through familiar channels like Microsoft Teams, Slack, Telegram, WhatsApp, and many more!
For Azure users, this gives you a practical middle ground: modern personal-agent workflows on familiar Azure infrastructure.
What is OpenClaw, and how is it different from ChatGPT/Claude/chat apps?
OpenClaw is a self-hosted personal agent runtime that can be hosted on Azure compute infrastructure.
How it differs:
- ChatGPT/Claude apps are primarily hosted chat experiences tied to one provider's models
- OpenClaw is an always-on runtime you operate yourself, backed by your choice of model provider — GitHub Copilot, Azure OpenAI, OpenAI, Anthropic Claude, Google Gemini, and others
- OpenClaw lets you keep the runtime boundary in your own Azure VM environment within your Azure enterprise subscription
In practice, OpenClaw is useful when you want a persistent assistant for operational and workflow tasks, with your own infrastructure as the control point. You bring whatever model provider and API plan you already have — OpenClaw connects to it.
Why Azure Linux VMs?
Azure Linux VMs are a strong fit because they provide:
- A suitable host machine for the OpenClaw agent to run on
- Enterprise-friendly infrastructure and identity workflows
- Repeatable provisioning via the Azure CLI
- Network hardening with NSG rules
- Managed SSH access through Azure Bastion instead of public SSH exposure
How to Set Up OpenClaw on an Azure Linux VM
This guide sets up an Azure Linux VM, applies NSG (Network Security Group) hardening, configures Azure Bastion for managed SSH access, and installs an always-on OpenClaw agent within the VM that you can interact with through various messaging channels.
What you'll 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 on the Azure VM
- Verify OpenClaw installation and configuration on the VM
What you need
- An Azure subscription with permission to create compute and network resources
- Azure CLI installed (install steps)
- An SSH key pair (the guide covers generating one if needed)
- ~20–30 minutes
Configure deployment
Step 1: Sign in to Azure CLI
az login # Select a suitable Azure subscription during Azure login
az extension add -n ssh # SSH extension is required for Azure Bastion SSH
The ssh extension is required for Azure Bastion native SSH tunneling.
Step 2: Register required resource providers (one-time)
Register required Azure Resource Providers (one time registration):
az provider register --namespace Microsoft.Compute
az provider register --namespace Microsoft.Network
Verify registration. Wait until both show Registered.
az provider show --namespace Microsoft.Compute --query registrationState -o tsv
az provider show --namespace Microsoft.Network --query registrationState -o tsv
Step 3: Set deployment variables
Set the deployment environment variables that will be needed throughout this guide.
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.
Step 4: Select SSH key
Use your existing public key if you have one:
SSH_PUB_KEY="$(cat ~/.ssh/id_ed25519.pub)"
If you don't have an SSH key yet, generate one:
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519 -C "you@example.com"
SSH_PUB_KEY="$(cat ~/.ssh/id_ed25519.pub)"
Step 5: Select VM size and OS disk size
VM_SIZE="Standard_B2as_v2"
OS_DISK_SIZE_GB=64
Choose 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:
az vm list-skus --location "${LOCATION}" --resource-type virtualMachines -o table
Check your current vCPU and disk usage/quota:
az vm list-usage --location "${LOCATION}" -o table
Deploy Azure resources
Step 1: Create the resource group
The Azure resource group will contain all of the Azure resources that the OpenClaw agent needs.
az group create -n "${RG}" -l "${LOCATION}"
Step 2: Create the network security group
Create the NSG and add rules so only the Bastion subnet can SSH into the VM.
az 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
The rules are evaluated by priority (lowest number first): Bastion traffic is allowed at 100, then all other SSH is blocked at 110 and 120.
Step 3: Create the virtual network and subnets
Create the VNet with the VM subnet (NSG attached), then add the Bastion subnet.
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 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}"
Step 4: Create the Virtual Machine
Create the VM with no public IP. SSH access for OpenClaw configuration will be exclusively through Azure Bastion.
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 created earlier handles security).
Reproducibility: The command above uses latest for the Ubuntu image. To pin a specific version, list available versions and replace latest:
az vm image list \
--publisher Canonical --offer ubuntu-24_04-lts \
--sku server --all -o table
Step 5: Create Azure Bastion
Azure Bastion provides secure-managed SSH access to the VM without exposing a public IP.
Bastion Standard SKU with tunneling is required for CLI-based "az network bastion ssh" command.
az 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
Bastion provisioning typically takes 5–10 minutes but can take up to 15–30 minutes in some regions.
Step 6: Verify Deployments
After all resources are deployed, your resource group should look like the following:
Install OpenClaw
Step 1: SSH into the VM through Azure Bastion
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_ed25519
Step 2: Install OpenClaw (in the Bastion SSH shell)
curl -fsSL https://openclaw.ai/install.sh | bash
The installer installs Node LTS and dependencies if not already present, installs OpenClaw, and launches the OpenClaw onboarding wizard. For more information, see the open source OpenClaw install docs.
OpenClaw Onboarding: Choosing an AI Model Provider
During OpenClaw onboarding, you'll choose the AI model provider for the OpenClaw agent. This can be GitHub Copilot, Azure OpenAI, OpenAI, Anthropic Claude, Google Gemini, or another supported provider. See the open source OpenClaw install docs for details on choosing an AI model provider when going through the onboarding wizard.
Most 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 the open source OpenClaw docs on configuring GitHub Copilot as the AI model provider.
OpenClaw Onboarding: Setting up Messaging Channels
During OpenClaw onboarding, there will be an optional step where you can set up various messaging channels to interact with your OpenClaw agent.
For first time users, we recommend setting up Telegram due to ease of setup. Other messaging channels such as Microsoft Teams, Slack, WhatsApp, and others can also be set up.
To configure OpenClaw for messaging through chat channels, see the open source OpenClaw chat channels docs.
Step 3: Verify OpenClaw Configuration
To validate that everything was set up correctly, run the following commands within the same Bastion SSH session:
openclaw status
openclaw gateway status
If there are any issues reported, you can run the onboarding wizard again with the steps above. Alternatively, you can run the following command:
openclaw doctor
Message OpenClaw
Once you have configured the OpenClaw agent to be reachable via various messaging channels, you can verify that it is responsive by messaging it.
Enhancing OpenClaw for Use Cases
There you go! You now have a 24/7, always-on personal AI agent, living on its own Azure VM environment.
- For awesome OpenClaw use cases, check out the awesome-openclaw-usecases repository.
- To enhance your OpenClaw agent with additional AI skills so that it can autonomously perform multi-step operations on any domain, check out the awesome-openclaw-skills repository.
- You can also check out ClawHub and ClawSkills, two popular open source skills directories that can enhance your OpenClaw agent.
Cleanup
To delete all resources created by this guide:
az group delete -n "${RG}" --yes --no-wait
This removes the resource group and everything inside it (VM, VNet, NSG, Bastion, public IP). This also deletes the OpenClaw agent running within the VM.
If you'd like to dive deeper about deploying OpenClaw on Azure, please check out the open source OpenClaw on Azure docs.