Skip to main content

Deploy on Azure

One Cloud Shell script provisions an AKS cluster and installs the whole stack.

The script registers the resource providers, provisions the cluster, installs the bundled Helm chart (gateway, optimizer, console, Postgres), and exposes the gateway API (:8787) and console (:3000) as load balancers scoped to the CIDR you choose. Already run your own cluster? Use Kubernetes (Helm) instead: AKS is an ordinary conformant cluster, and The two files you author install the same chart with nothing Azure-specific in them. The only AKS-specific part:

Create the cluster, then install the chart yourself
az group create --name anyray-rg --location eastus
az aks create --resource-group anyray-rg --name anyray \
--node-count 2 --enable-managed-identity --generate-ssh-keys
az aks get-credentials --resource-group anyray-rg --name anyray

helm install anyray oci://public.ecr.aws/anyray/anyray \
-f my-values.yaml --namespace anyray --create-namespace

AKS ships a default-annotated default StorageClass (Azure Disk CSI), so the chart's volumes bind with nothing to pre-create.

Prerequisites

  • An Azure subscription with billing enabled and permission to create AKS, Virtual Network, public IP, load balancer, and managed-disk resources. The script registers the Microsoft.ContainerService and Microsoft.Network resource providers for you.
  • A narrow ALLOWED_CIDR: your office or VPN range. For a single workstation: curl -fsS https://api.ipify.org, then <that-ip>/32. The script rejects 0.0.0.0/0; the console and gateway carry your org's spend data and admin access.
  • An Anyray deployment token (adt_…) from app.anyray.ai (setup wizard, or Settings → Deployments → New deployment).

Azure Cloud Shell already has az, kubectl, and helm; nothing to install locally.

Install

1
Open Azure Cloud Shell
Open Azure Cloud Shell

Any machine with the Azure CLI (az), kubectl, and helm works too; see Install from your own terminal below.

2
Set your inputs and run the script
Cloud Shell
git clone https://github.com/anyrayHQ/install anyray && cd anyray

export ALLOWED_CIDR="203.0.113.0/24" # your office / VPN range
export DEPLOYMENT_TOKEN="adt_..." # from app.anyray.ai
# Optional overrides:
# export LOCATION="eastus"
# export RESOURCE_GROUP="anyray"
# export CLUSTER="anyray"
# export NAMESPACE="anyray"
# export IMAGE_TAG="latest" # or pin vX.Y.Z

./azure/deploy.sh

The script registers the resource providers, creates the resource group and AKS cluster, generates the secrets (ANYRAY_ADMIN_TOKEN, ANYRAY_CONTENT_KEY, the pseudonym salt, stored as the anyray-secrets Kubernetes Secret, never printed), installs the chart, waits for the load balancer IPs, and prints your URLs and admin key.

3
Wait for first boot

The AKS cluster is the long pole (~5–8 min), then the load balancers take ~1–3 min to get public IPs. The gateway restarts until Postgres is reachable, then goes healthy.

4
Open the console

Open the printed Console URL and sign in with the printed admin key. Read the key again any time:

kubectl get secret anyray-secrets -n anyray \
-o jsonpath='{.data.ANYRAY_ADMIN_TOKEN}' | base64 --decode; echo
5
Verify the deployment
export GATEWAY_URL="http://your-gateway-lb-ip:8787"
export ADMIN_TOKEN="..." # from the deploy output

curl -fsS "$GATEWAY_URL/" && echo "gateway ok"
# Deployment health: gateway / observability / spend / optimizer / portal:
curl -fsS "$GATEWAY_URL/admin/health" -H "Authorization: Bearer ${ADMIN_TOKEN}"

/admin/health returns 503 and names the failing leg if any required service is down; a healthy stack returns "ok": true with every leg green.

Everything above runs in your Azure subscription. Point your local coding tools at the gateway with npx anyray-connect@latest --gateway <GatewayURL> (developer FAQ).

Install from your own terminal

From any machine with the Azure CLI (az), kubectl, and helm authenticated to your subscription (az login):

git clone https://github.com/anyrayHQ/install anyray && cd anyray

export SUBSCRIPTION_ID="00000000-0000-0000-0000-000000000000"
export ALLOWED_CIDR="203.0.113.0/24" # your office / VPN range
export DEPLOYMENT_TOKEN="adt_..." # from app.anyray.ai

./azure/deploy.sh

The script is idempotent: re-running it reuses an existing cluster and keeps the existing anyray-secrets rather than rotating the content key. The inputs:

VariableRequiredDefaultWhat it is
SUBSCRIPTION_IDnoaz's active subscriptionAzure subscription to deploy into.
ALLOWED_CIDRyesn/aCIDR allowed to reach the console/gateway LBs; 0.0.0.0/0 is rejected.
DEPLOYMENT_TOKENyesn/aAnyray Billing app deployment token (adt_…).
LOCATIONnoeastusAzure region.
RESOURCE_GROUPnoanyrayResource group (created if missing, reused if present).
CLUSTERnoanyrayAKS cluster name (reused if present).
NAMESPACEnoanyrayKubernetes namespace.
NODE_VM_SIZEnoStandard_D2s_v5Node pool VM size.
NODE_COUNTno2Node pool size.
IMAGE_TAGnolatestAnyray image tag; pin vX.Y.Z for a reproducible deploy.
DEFAULT_MODELnoanthropic/claude-sonnet-4-5Target for the anyray-default model alias.

Configuration

Gateway hardening and optimizer tuning are ordinary Helm values; set them in my-values.yaml or pass --set on a helm upgrade and the gateway rolls with the new value. The values and their defaults: gateway hardening. To re-scope the load balancers to a different CIDR later, see Troubleshoot below.

Troubleshoot

A LoadBalancer Service has no external IP

AKS provisions the public IP in ~1–3 min:

kubectl get svc gateway anyray-proxy -n anyray

If EXTERNAL-IP stays <pending> for several minutes, confirm the subscription has public-IP quota in the region and that the cluster's managed identity has the Network Contributor role on the AKS-managed node resource group (MC_<resource-group>_<cluster>_<location>).

The console or gateway is unreachable from your network

The load balancers only admit traffic from ALLOWED_CIDR. Confirm your current public IP is inside that range (curl -fsS https://api.ipify.org), and re-scope if needed:

helm upgrade anyray ./helm -f my-values.yaml --namespace anyray --reuse-values \
--set gateway.service.loadBalancerSourceRanges[0]=<your-cidr> \
--set proxy.service.loadBalancerSourceRanges[0]=<your-cidr>
A pod is stuck Pending or CrashLooping
kubectl get pods -n anyray
kubectl describe pod -n anyray <pod>
kubectl logs -n anyray deployment/anyray-gateway

A Pending Postgres or *-data PVC usually means no default StorageClass. AKS ships a default-annotated default class (Azure Disk CSI); confirm with kubectl get storageclass. A gateway that keeps restarting is most often still waiting on Postgres.

Upgrade

IMAGE_TAG=latest follows the moving release channel. Re-run ./azure/deploy.sh to converge, or pin a version and roll the chart directly; a pinned :vX.Y.Z keeps rollbacks reproducible and auditable:

helm upgrade anyray ./helm -f my-values.yaml \
--namespace anyray --reuse-values --set image.tag=vX.Y.Z