Deploy Chroma or VecturaDB on Azure
Disclaimer. This template and its scripts are provided as is, without warranty of any kind, as stated in the Apache License 2.0. The numbers on this page are what we measured on 25 and 26 October 2026 in westeurope: your region, sizes, data and versions may behave differently. You are responsible for your data: back it up, and test a restore on a copy before you rely on it.
Not sure about your case? Open an issue in the VecturaDB repository, describe your data and your setup, and we will take a look on a best-effort basis.
One server in your own Azure subscription, with its data on a managed disk, HTTPS, allowed IP addresses and backups.
The button opens the form of the Azure portal with the template of the tag azure-v1.0.2. The template, its scripts and its README are in the VecturaDB.Deploy repository, under azure/vm.
When the portal shows “Your deployment is complete”, open Outputs in the menu on the left: url is the address of the server, for the clients.
The template runs one of two servers:
- Chroma 1.5.9, the open-source single-node server;
- VecturaDB 1.0.0-preview.3.post1, built from Chroma, with sparse vectors, BM25, hybrid search, collection fork and API keys.
Both keep the Chroma API: the Chroma clients connect with the URL of the deployment. In our tests the Python (chromadb 1.5.9) and JavaScript (chromadb 3.5.0) clients and a .NET client gave the same results on the two servers.
What it creates
- an Ubuntu 24.04 VM, where Docker runs the server and Caddy serves HTTPS in front of it;
- a Standard SSD data disk, 16 GiB by default, mounted at
/var/lib/chroma; - a network security group that opens only what the access mode needs, a virtual network and a public IP (only with HTTPS access);
- a backup vault, when backups are on.
In our tests a deployment from zero took 157-220 seconds, and a new deployment of an existing VM 36-68 seconds.
Sizes and cost
The sizes we tested, with the list prices of westeurope in USD for 730 hours a month, on 26 October 2026:
| Size | CPU, memory | VM | Disks (OS E4, data E3) | Public IP | Total a month |
|---|---|---|---|---|---|
| Standard_B2pts_v2 (default, Arm) | 2, 1 GiB | 7.01 | 3.60 | 3.65 | 14.26 |
| Standard_B1s | 1, 1 GiB | 8.76 | 3.60 | 3.65 | 16.01 |
| Standard_B1ms | 1, 2 GiB | 17.52 | 3.60 | 3.65 | 24.77 |
- With internal access there is no public IP: 3.65 less. Not in the table: disk transactions, outbound traffic and the snapshots of the backups.
- Standard_B1ls does not work: in our tests it ran out of memory at the first boot.
- B1s and B1ms belong to the Bv1 series, which Azure lists as End of Life. That is why the default is B2pts_v2.
- B-series sizes stay at a baseline CPU once their credits run out: 20% for B2pts_v2 (Bpsv2 series). A server that is busy all the time needs another size.
- A new Azure free account includes, for 12 months, "750 hours each of B1s, B2pts v2 (Arm-based), and B2ats v2 (AMD-based) burstable VMs" (details).
With 1 GiB of memory, Chroma used 54-61 MiB at rest. We measured only small collections: Chroma keeps its vector index in memory, so a large collection needs a larger size.
Access and HTTPS
| Access | What is open | Address |
|---|---|---|
| Allowed IP addresses | 443 from your IP ranges; 80 for the certificate only | https://, with the Azure name of the public IP or your domain |
| Public | 443 and 80 from anywhere; VecturaDB with an API key only | https:// |
| Internal | nothing from the internet; port 8000 inside the virtual network | http://, on the private address |
- Caddy gets a Let's Encrypt certificate and forwards to the server on 127.0.0.1. Port 80 answers only the challenge of the certificate.
- Ports 22 and 8000 stay closed.
- The deployment ends only when Caddy holds the certificate.
- Chroma 1.5.9 has no API keys, so public access needs VecturaDB with a key, sent in the
x-chroma-tokenheader.
In our tests, from a VM in the same region over HTTPS, a heartbeat took 1.1 ms and a query 2.6 ms (median, Standard_B2pts_v2).
Backups and restore
With backups on, Azure Disk Backup takes incremental snapshots of the data disk, every 24 hours by default, and keeps them 7 days. Soft delete is on: deleted backups stay 14 days. The snapshots are billed at the price of standard storage, 0.05 USD per GB a month in westeurope: the first one for the used part of the disk, the next ones for the changes.
To restore, the backup vault restores a recovery point to a new disk. You attach it at LUN 1 and run restore.sh, which copies its data over the data disk and starts the server again. Then you detach and delete the new disk:
az vm disk attach -g my-chroma --vm-name chroma --name <restored disk> --lun 1
az vm run-command invoke -g my-chroma -n chroma --command-id RunShellScript --scripts @restore.sh
az vm disk detach -g my-chroma --vm-name chroma --name <restored disk>
az disk delete -g my-chroma -n <restored disk>
The data disk stays the same, so the backups go on. The data written after the backup is lost: take an on-demand backup first if you may want it back.
In our tests an on-demand backup took 175-179 seconds, the restore to a new disk 50 seconds, and restore.sh 32-33 seconds. After the restore the server held the data of the backup, and not the data written after it.
Updates
- To change the server, its image or the access, you deploy the template again. Every deployment stops the old container and starts the new one, with the data on the data disk. In our tests a switch from Chroma 1.5.9 to VecturaDB took 67-68 seconds, and VecturaDB read the collections written by Chroma.
- Docker starts only once the data disk is mounted: a VM that boots without it serves nothing, rather than an empty database.
- Ubuntu installs its security updates by itself. Caddy comes from its own repository: you update it.
Delete everything
Deleting the resource group deletes the deployment, the snapshots of the backups included. With backups on, two things stop it first: the backup instance of the data disk, and the soft delete of the vault, on by default. So turn soft delete off, delete the backup instance, then delete the group. Without backups, delete the group.
In the portal:
- open the backup vault,
<name>-backup, and turn soft delete off in its security settings; - in the vault, open Backup instances, select
<name>-data, and delete it, with its backup data; - delete the resource group.
With the Azure CLI:
SUB=$(az account show --query id -o tsv); RG=my-chroma; NAME=chroma
VAULT="https://management.azure.com/subscriptions/$SUB/resourceGroups/$RG/providers/Microsoft.DataProtection/backupVaults/$NAME-backup"
az rest --method patch --url "$VAULT?api-version=2024-04-01" --body '{"properties":{"securitySettings":{"softDeleteSettings":{"state":"Off","retentionDurationInDays":14}}}}'
az rest --method delete --url "$VAULT/backupInstances/$NAME-data?api-version=2024-04-01"
# The deletion goes on in the background: wait until the backup instance is gone.
while az rest --method get --url "$VAULT/backupInstances/$NAME-data?api-version=2024-04-01" -o none 2>/dev/null; do sleep 10; done
az group delete -n $RG --yes
In our tests soft delete went off at once, the backup instance was gone after 80-103 seconds and the group after 126-143 seconds. Then nothing was left: no resource, no snapshot, no deleted vault.
- With the backup instance still there, the deletion of the group failed after 438 seconds. Everything else was gone, and the group and the vault stayed.
- With the backup instance deleted and soft delete still on, the instance stayed soft deleted for 14 days, and so did the vault and the group. Microsoft says that snapshots still there during those days are billed (soft delete for Azure Backup).
The README of the template also says how to get out of the soft-deleted state before the 14 days.
Limits
- One VM and one disk: no high availability. While the VM restarts or a deployment switches the container, the server does not answer.
- The backups are snapshots in the same region.
Why not Container Apps
We measured Azure Container Apps with the data on Azure Files, as a cheaper option with scale to zero, and set it aside for data that must persist:
- during a change of revision, the old and the new revision run at the same time on the same files, and Chroma does not lock its files;
- Chroma 1.5.9 did not start on an SMB share mounted as Container Apps mounts it;
- on an NFS share, the same operations took 15 to 230 times longer than on the VM, measured from the same client: 309 ms for a query against 2.6 ms.
VecturaDB is an independent fork of Chroma, under the Apache License 2.0. The original code is copyright Chroma Inc. and its contributors.
Not affiliated with, endorsed by or sponsored by Chroma Inc. CHROMA is a registered trademark of Chroma Inc., used here only to describe compatibility.