Qdrant on Ubuntu 24.04 on Azure User Guide
Overview
Qdrant is a high performance open source vector similarity search engine and vector database, written in Rust for speed and reliability under heavy load. It stores points made of a vector and a JSON payload, indexes them with HNSW, and answers nearest neighbour, filtered and hybrid search queries in milliseconds through a clean REST and gRPC API. It ships a built in web dashboard for browsing collections, running interactive API requests and exploring search results, and it is a strong foundation for semantic search, recommendations, retrieval augmented generation and anomaly detection.
The cloudimg image installs the official prebuilt Qdrant server binary at /opt/qdrant/bin/qdrant, running as the qdrant service bound to loopback 127.0.0.1:6333 (REST and dashboard) and 127.0.0.1:6335 (gRPC), behind nginx which terminates TLS. nginx serves the REST API and dashboard on port 443 and reverse proxies gRPC over TLS on port 6334, so the API key never crosses the wire in plaintext.
Secure by default, no open API: Qdrant serves an open, unauthenticated API when no key is set. This image never ships that. A qdrant-firstboot.service oneshot generates a unique API key on each VM's first boot, writes it to a root only file and the service environment, regenerates a per VM TLS certificate, resolves the instance URL and writes a root only info note, then disables itself. The qdrant service requires the first boot unit, so it can never start open before a key is set. No two VMs share a key and none is baked into the image.
Dedicated data disk: vector data (the storage and snapshots directories) lives on a dedicated data disk mounted at /var/lib/qdrant, captured into the image so every VM is provisioned with it. The server binary and dashboard assets stay on the OS disk.
What is included:
- Qdrant (verified at 1.18.3) as the official prebuilt Rust server binary
- The built in Qdrant web dashboard, served over TLS
qdrant.servicebound to loopback127.0.0.1:6333(REST + dashboard) and127.0.0.1:6335(gRPC)- nginx terminating TLS: REST + dashboard on
443, gRPC on6334,80redirects to HTTPS qdrant-firstboot.servicefor the first boot API key, per VM TLS certificate and info note- A unique per VM API key generated on first boot, in a root only
0600file - A dedicated data disk mounted at
/var/lib/qdrantfor storage and snapshots - Ubuntu 24.04 LTS base, fully patched
- 24/7 cloudimg support, 24h response SLA
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet with a subnet. Qdrant performance and index capacity scale with memory. Recommended VM size: Standard_B2s (2 vCPU, 4 GB RAM) for evaluation and small collections, or a Standard_D4s_v5 or larger for production workloads with millions of vectors. The dedicated data disk holds your collections, so resize it to suit your dataset.
Step 1: Deploy from the Azure Portal
Search the Marketplace for Qdrant on Ubuntu 24.04, choose your VM size, and attach an NSG that allows TCP 22 (SSH) from your management network and TCP 443 (REST + dashboard) and 6334 (gRPC) from the networks and applications that need to query it. Port 80 only issues an HTTPS redirect.
Step 2: Deploy from the Azure CLI
RG="qdrant-prod"; LOCATION="eastus"; VM_NAME="qdrant-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/qdrant-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create -g "$RG" --name qdrant-vnet --address-prefix 10.90.0.0/16 --subnet-name qdrant-subnet --subnet-prefix 10.90.1.0/24
az network nsg create -g "$RG" --name qdrant-nsg
az network nsg rule create -g "$RG" --nsg-name qdrant-nsg --name allow-ssh --priority 100 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp
az network nsg rule create -g "$RG" --nsg-name qdrant-nsg --name allow-api --priority 110 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 443 6334 --access Allow --protocol Tcp
az vm create -g "$RG" --name "$VM_NAME" --image "$GALLERY_IMAGE_ID" \
--size Standard_B2s --storage-sku StandardSSD_LRS \
--admin-username azureuser --ssh-key-values "$SSH_KEY" \
--vnet-name qdrant-vnet --subnet qdrant-subnet --nsg qdrant-nsg --public-ip-sku Standard
Step 3: Connect via SSH
ssh azureuser@<vm-ip>
Step 4: Verify the services are running
Qdrant listens on loopback 127.0.0.1:6333 (REST + dashboard) and 127.0.0.1:6335 (gRPC); nginx fronts them with TLS on ports 443 and 6334. The health endpoint is public; the data API requires your key.
sudo systemctl is-active qdrant nginx
ss -tln | grep -E '127.0.0.1:6333|:443 '
curl -ks https://127.0.0.1/healthz
cat /opt/qdrant/VERSION
You should see both services active, the listening sockets, healthz check passed, and the installed Qdrant version.

The built in dashboard is served over TLS at https://<your-vm-ip>/dashboard. Because the certificate is self signed per VM, your browser will warn on first visit; accept the exception (or trust /etc/nginx/tls/qdrant.crt) to reach it.

Step 5: Read your per VM API key and confirm auth is enforced
The API key was generated on this VM's first boot and stored in a root only file. Read it and keep it secret: it authenticates every data request. Confirm that unauthenticated and wrong key requests are rejected while the correct key is accepted.
sudo cat /root/qdrant-info.txt
echo "no key -> HTTP $(curl -ks -o /dev/null -w '%{http_code}' https://127.0.0.1/collections)"
echo "wrong key -> HTTP $(curl -ks -o /dev/null -w '%{http_code}' -H 'api-key: wrong' https://127.0.0.1/collections)"
QDRANT_KEY=$(sudo grep '^QDRANT_API_KEY=' /root/qdrant-info.txt | cut -d= -f2-)
echo "correct key -> HTTP $(curl -ks -o /dev/null -w '%{http_code}' -H "api-key: $QDRANT_KEY" https://127.0.0.1/collections)"
The info note holds QDRANT_API_KEY and the instance URLs, is owned root:root with mode 0600. Unauthenticated and wrong key calls return 401; only the per VM key returns 200.

Step 6: Create a collection and run your first vector search
Load the API key into a shell variable, create a movies collection with 4 dimensional cosine vectors, upsert a few points with payloads, then run a nearest neighbour search. Use wait=true so the upsert is indexed before you search.
QDRANT_KEY=$(sudo grep '^QDRANT_API_KEY=' /root/qdrant-info.txt | cut -d= -f2-)
H="api-key: $QDRANT_KEY"
curl -ks -X PUT https://127.0.0.1/collections/movies -H "$H" -H 'Content-Type: application/json' \
--data '{"vectors":{"size":4,"distance":"Cosine"}}' | jq -r '.status'
curl -ks -X PUT 'https://127.0.0.1/collections/movies/points?wait=true' -H "$H" -H 'Content-Type: application/json' \
--data '{"points":[
{"id":1,"vector":[0.9,0.1,0.1,0.1],"payload":{"title":"Interstellar","genre":"scifi"}},
{"id":2,"vector":[0.1,0.9,0.1,0.1],"payload":{"title":"Inception","genre":"scifi"}},
{"id":3,"vector":[0.1,0.1,0.9,0.1],"payload":{"title":"The Matrix","genre":"scifi"}},
{"id":4,"vector":[0.1,0.1,0.1,0.9],"payload":{"title":"Dune","genre":"scifi"}}
]}' | jq -r '.status'
curl -ks -X POST https://127.0.0.1/collections/movies/points/search -H "$H" -H 'Content-Type: application/json' \
--data '{"vector":[0.85,0.15,0.1,0.1],"limit":3,"with_payload":true}' \
| jq -r '.result[] | "\(.payload.title) score=\(.score)"'
The search returns the nearest points to your query vector, each with its cosine similarity score and payload, in a fraction of a millisecond.

You can see every collection and its status in the dashboard.

Step 7: Filter by payload
Add a payload index so you can filter searches by metadata, then combine vector similarity with a payload filter. This returns the nearest scifi titles only.
QDRANT_KEY=$(sudo grep '^QDRANT_API_KEY=' /root/qdrant-info.txt | cut -d= -f2-)
H="api-key: $QDRANT_KEY"
curl -ks -X PUT https://127.0.0.1/collections/movies/index -H "$H" -H 'Content-Type: application/json' \
--data '{"field_name":"genre","field_schema":"keyword"}' | jq -r '.status'
curl -ks -X POST https://127.0.0.1/collections/movies/points/search -H "$H" -H 'Content-Type: application/json' \
--data '{"vector":[0.2,0.1,0.9,0.7],"filter":{"must":[{"key":"genre","match":{"value":"scifi"}}]},"limit":4,"with_payload":true}' \
| jq -r '.result[] | "\(.payload.title) score=\(.score)"'
The same interactive requests can be run from the dashboard's built in Console, which shows the request and the live scored results side by side.

Step 8: Explore collections in the dashboard
Open a collection in the dashboard to browse its points, inspect payloads and vectors, run "find similar" from any point, and visualise the vector space. This is the fastest way to sanity check your data.

Step 9: Snapshots for backup and restore
Qdrant can snapshot a collection to the snapshots directory on the data disk, which you can download and restore elsewhere.
QDRANT_KEY=$(sudo grep '^QDRANT_API_KEY=' /root/qdrant-info.txt | cut -d= -f2-)
H="api-key: $QDRANT_KEY"
curl -ks -X POST https://127.0.0.1/collections/movies/snapshots -H "$H" | jq -r '.result.name'
curl -ks https://127.0.0.1/collections/movies/snapshots -H "$H" | jq -r '.result[].name'
Snapshots are written under /var/lib/qdrant/snapshots on the dedicated data disk.
Step 10: Enable a real TLS certificate
The appliance ships with a self signed certificate generated per VM. For production, point a DNS record at the VM and replace it with a CA signed certificate. With certbot you can obtain one and drop it into the nginx TLS paths.
sudo apt-get update && sudo apt-get install -y certbot
sudo certbot certonly --standalone -d your-domain.example.com
sudo cp /etc/letsencrypt/live/your-domain.example.com/fullchain.pem /etc/nginx/tls/qdrant.crt
sudo cp /etc/letsencrypt/live/your-domain.example.com/privkey.pem /etc/nginx/tls/qdrant.key
sudo systemctl reload nginx
Clients can then verify the certificate normally instead of using -k.
Persistence, first boot and updates
Vector data lives on the dedicated data disk mounted at /var/lib/qdrant (the storage and snapshots directories) and is captured into the image, so a VM launched from this image is ready immediately. The first boot service generates the per VM API key, regenerates the per VM TLS certificate and writes a root only info note, then disables itself so subsequent reboots are unaffected. The OS ships fully patched with unattended security upgrades enabled.

Support
Every cloudimg deployment includes 24/7 support with a 24 hour response SLA. Contact support@cloudimg.co.uk for help with deployment, configuration or scaling.
This is a repackaged open source software product with additional charges for cloudimg support services. Qdrant is a trademark of its respective owner. All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.