Azure virtual machines

Run polign_db on a plain Azure Linux VM in front of a Blob Storage container in your own subscription. You need the Azure CLI and about ten minutes. You pay Azure for the VM and the storage. The software is free.

What you get

One VM running polign-server as a systemd service, and one Blob Storage container that holds everything: vectors, indexes, and the write log. The VM is a serving tier in front of the container. Replacing the VM loses nothing.

The VM reaches the container through its managed identity. No storage account key or connection string is written anywhere, and the VM has no public IP address.

Step 1: Create the storage and the VM

Run these from your own machine after az login. Change the names at the top. A storage account name has to be globally unique, lowercase, and 3 to 24 letters or digits.

RG=polign
LOC=westus2
SA=mypolignstore        # your storage account name
VM=polign-1

az group create -n $RG -l $LOC

az storage account create -n $SA -g $RG -l $LOC \
  --sku Standard_LRS --allow-blob-public-access false
az storage container create --account-name $SA -n polign --auth-mode login

az vm create -g $RG -n $VM \
  --image Debian:debian-12:12-gen2:latest --size Standard_D4s_v5 \
  --assign-identity --public-ip-address "" \
  --admin-username azureuser --generate-ssh-keys

polign_db never creates its own container, so the container has to exist before the server starts. If az storage container create says you lack permission, give your own account the Storage Blob Data Contributor role on the storage account and try again.

For the VM size, serving from the container is bound by network bandwidth and by how much of the working set fits in memory, so prefer memory over vCPUs.

Step 2: Let the VM read and write the container

Give the VM's identity the Storage Blob Data Contributor role on that one container and nothing else:

PID=$(az vm show -g $RG -n $VM --query identity.principalId -o tsv)
SCOPE=$(az storage account show -n $SA -g $RG --query id -o tsv)/blobServices/default/containers/polign

az role assignment create --assignee $PID \
  --role "Storage Blob Data Contributor" --scope $SCOPE

Role assignments can take a minute or two to take effect. Until then the server restarts every few seconds and logs a permission error. That is expected, and it settles on its own.

Step 3: Install and start the server

Save this as polign-setup.sh. It installs the release binaries, creates a service account, and starts polign-server under systemd. Change STORE to match your storage account.

#!/bin/sh
set -eu
STORE=az://mypolignstore/polign/db   # az://account/container/prefix

curl -fsSL https://get.polign.com | sh

id polign >/dev/null 2>&1 || useradd --system --create-home \
  --home-dir /var/lib/polign --shell /usr/sbin/nologin polign
install -d -o polign -g polign /var/cache/polign
install -d /etc/polign
printf 'POLIGN_STORE=%s\n' "$STORE" > /etc/polign/server.env

cat > /etc/systemd/system/polign-server.service <<'EOF'
[Unit]
Description=polign_db server
After=network-online.target
Wants=network-online.target

[Service]
User=polign
Group=polign
EnvironmentFile=/etc/polign/server.env
Environment=HOME=/var/lib/polign
ExecStart=/usr/local/bin/polign-server -store ${POLIGN_STORE} \
  -http 0.0.0.0:23000 -grpc 0.0.0.0:23001 \
  -disk-cache-dir /var/cache/polign -disk-cache-bytes 10737418240
Restart=on-failure
RestartSec=2
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now polign-server

The VM has no public IP, so run the script through Azure instead of over SSH:

az vm run-command invoke -g $RG -n $VM \
  --command-id RunShellScript --scripts @polign-setup.sh

The disk cache is set to 10 GB. Keep it below the size of the VM's OS disk, or attach a data disk and point -disk-cache-dir at it.

Step 4: Check that it works

From a machine inside the same virtual network, with IP set to the VM's private address (az vm list-ip-addresses -g $RG -n $VM shows it):

curl "http://$IP:23000/healthz"

curl -X PUT "http://$IP:23000/v1/collections/docs/vectors/a" \
  -d '{"values":[1,0,0],"metadata":{"label":"first"}}'

curl -X POST "http://$IP:23000/v1/collections/docs/query" \
  -d '{"values":[0.9,0.1,0],"k":5}'

A collection is created by the first write and takes its size from the first vector. The Python SDK and the HTTP API work against this address the same way they work anywhere else.

Security

Azure encrypts the storage account at rest, but it does so on its side and sees your data in the clear on every request. To keep the container from ever holding readable data, put a keyring file on the VM and name it in /etc/polign/server.env before the first write:

umask 077
printf '1=%s\n' "$(openssl rand -base64 32)" > /etc/polign/store.keys
chown root:polign /etc/polign/store.keys
chmod 0640 /etc/polign/store.keys
echo 'POLIGN_STORE_ENCRYPTION_KEY_FILE=/etc/polign/store.keys' >> /etc/polign/server.env
systemctl restart polign-server

Every object is then encrypted inside the server process, and the disk cache is sealed under the same keys. A store is marked encrypted on its first write and cannot be converted later, so decide this up front. Back up the key file: without it the data cannot be read. The security page covers how this works.

Other ways to sign in to storage

The managed identity above is the recommended path. The server looks for storage credentials in this order, and uses the first one it finds:

  1. AZURE_STORAGE_CONNECTION_STRING
  2. AZURE_STORAGE_KEY, a shared key for the account in the store address
  3. the standard Azure identity chain: service principal variables, workload or managed identity, then your az login

If the VM has a user-assigned identity instead of a system-assigned one, add AZURE_CLIENT_ID=<the identity's client id> to /etc/polign/server.env. Leave that line out entirely for a system-assigned identity: if it is present but empty, the server refuses to start.

A storage account in another subscription works the same way as long as it is in the same Entra tenant. Assign the role to the VM's identity on that account.

Operate

Operate in production covers tuning, scaling out, and controlling the bill. On AKS, use the Helm chart with Azure Workload Identity instead of a VM.

Upgrade

Run the install line again and restart:

curl -fsSL https://get.polign.com | sudo sh
sudo systemctl restart polign-server

To install a specific release instead of the latest, end the first line with sudo POLIGN_VERSION=vX.Y.Z sh. The container carries the data, so you can also replace the VM outright with a fresh one that has the same role. Copy the container first if you want a way back.

Remove

Delete the VM with az vm delete -g $RG -n $VM. The storage account and container are not touched, so delete them yourself once you are sure you no longer need the data. az group delete -n $RG removes everything at once, data included.

Help

Contact us with the VM name, the region, and the output of polign-server -version from the VM.