Qdrant 1.19.2
Overview
This guide shows how to launch and use the Qdrant 1.19.2 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud Vector Databases and RAG listing on AWS Marketplace. You pick it as the software version when you subscribe and launch.
Qdrant is an open-source vector similarity search engine and vector database written in Rust. It stores points (a vector plus a JSON payload), indexes them with HNSW, and answers nearest-neighbor, filtered and hybrid searches through a REST API and a gRPC API. It is a common foundation for semantic search, recommendations and retrieval-augmented generation (RAG). Qdrant also ships a web dashboard for browsing collections and running requests.
Out of the box, Qdrant serves an open API that anyone who can reach it may read and write. This image never does that.
What you get:
- Two keys unique to your instance, required on every data call. An API key (full access) and a read-only API key (list, read and search only) are generated on your instance's first boot. They are written to Qdrant's configuration and to
/root/qdrant-info.txt, readable by root only. They never appear on a command line, in a process environment or in a log. Qdrant refuses to start if either key is missing, so it can never come up open. - HTTPS and gRPC over TLS, with a certificate made on your instance. Qdrant listens on loopback only (
127.0.0.1:6333REST and127.0.0.1:6336gRPC). nginx serves the REST API and dashboard on 443 and the gRPC API on 6334, with TLS 1.2 and 1.3 only and a certificate and key generated on first boot. Port 80 only redirects to HTTPS (plus a/healthzcheck). - The host name comes from configuration, never from a request. nginx answers only to your instance's own names and addresses (public IP and DNS name, private IP and DNS name, or the name you set with
qdrant-set-host). It closes the connection for any otherHost. - The client address comes from the connection. nginx overwrites
X-Forwarded-ForandX-Real-IPwith the real peer address and dropsForwarded, so a client cannot pose as another address in the logs. - Instance metadata is blocked for Qdrant and nginx. Qdrant can fetch a snapshot from a URL that you give it, but it cannot reach the EC2 instance metadata service at 169.254.169.254. The instance requires IMDSv2.
- Telemetry off and a single node. Usage reporting to Qdrant is disabled, and clustering (with its peer API on 6335) is off.
- Exactly four public ports: 22 (SSH), 80 (redirect), 443 (REST and dashboard) and 6334 (gRPC).
- Qdrant 1.19.2 (the official release binary and dashboard, checksum verified), nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent
- Your vector data (collections and snapshots) on its own 30 GiB EBS volume at
/var/lib/qdrant - The Apache 2.0 license at
/usr/share/doc/sac/qdrant/LICENSE - Default user
ubuntu, x86_64 architecture and a recommended instance type of m5.large
Prerequisites
- An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet
- A security group that allows TCP 443 (REST API and dashboard) and TCP 6334 (gRPC) from the applications and people that use Qdrant, TCP 22 (SSH) from your management network, and optionally TCP 80 (it only redirects). Keep these rules to your own networks rather than
0.0.0.0/0where you can.
Qdrant keeps its indexes in memory where it can, so size the instance for your data. m5.large (8 GiB) suits evaluation and up to a few million small vectors. Choose a memory-optimized type for larger collections, and grow the data volume as your collections grow.
Launch the instance
In the AWS Marketplace listing, choose Continue to Subscribe, and then choose Continue to Configuration. Pick Qdrant 1.19.2 on Ubuntu 24.04 as the software version and your Region, and then choose Launch through EC2.
Choose m5.large (or larger), your key pair and a security group as described in Prerequisites. Keep the second EBS volume, because it holds your collections.
To launch with the AWS CLI instead, replace the values in angle brackets:
aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
--instance-type m5.large --key-name <your-key-pair> \
--security-group-ids <your-security-group> --subnet-id <your-subnet> \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=qdrant}]'Connect to your instance
Connect over SSH as the ubuntu user, which is the default user for Qdrant 1.19.2 on Ubuntu 24.04:
ssh -i <your-key.pem> ubuntu@<public-ip>Check the services, ports and data volume
First boot takes a few seconds. After that, Qdrant, nginx and the two SecureAnyCloud first-boot units are active:
systemctl is-active qdrant nginx qdrant-firstboot qdrant-set-hostactive active active activeQdrant listens on loopback only. nginx listens on 80, 443 and 6334, and SSH listens on 22:
sudo ss -tlnp | awk 'NR==1 || /nginx|sshd|qdrant/' | awk '{print $1, $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g'State Local Peer LISTEN 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx")) LISTEN 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx")) LISTEN 0.0.0.0:22 users:(("sshd"),("systemd")) LISTEN 0.0.0.0:6334 users:(("nginx"),("nginx"),("nginx")) LISTEN 127.0.0.1:6333 users:(("qdrant")) LISTEN 127.0.0.1:6336 users:(("qdrant")) LISTEN [::]:443 users:(("nginx"),("nginx"),("nginx")) LISTEN [::]:80 users:(("nginx"),("nginx"),("nginx")) LISTEN [::]:22 users:(("sshd"),("systemd")) LISTEN [::]:6334 users:(("nginx"),("nginx"),("nginx"))Check the version, as reported by the binary and by the running server:
/opt/qdrant/bin/qdrant --version curl -ks https://127.0.0.1/ | jq -c .qdrant 1.19.2 {"title":"qdrant - vector search engine","version":"1.19.2","commit":"016542aa5deb6c66380bb137badf73d54f742bde"}Confirm that your collections are on the separate data volume:
findmnt -no SOURCE,TARGET,FSTYPE /var/lib/qdrant df -h --output=size,avail,target /var/lib/qdrant/dev/nvme1n1 /var/lib/qdrant ext4 Size Avail Mounted on 30G 28G /var/lib/qdrantGet your API keys and URLs
Read the credentials file as root:
sudo cat /root/qdrant-info.txt# Qdrant 1.19.2 - generated on this instance. Unique to this instance: keep it secret.
# Send a key in the 'api-key' header (REST) or the 'api-key' metadata (gRPC). The read-only key can list,
# read and search but cannot create, change or delete anything (snapshots included). QDRANT_API_KEY=<your-api-key> QDRANT_READ_ONLY_API_KEY=<your-read-only-api-key> QDRANT_URL=https://<public-ip>/ QDRANT_DASHBOARD_URL=https://<public-ip>/dashboard QDRANT_GRPC_URL=<public-ip>:6334
# TLS certificate (self-signed, per instance): /etc/nginx/tls/qdrant.crt
# Serve under a DNS name:
sudo qdrant-set-host <name> Rotate both keys:
sudo qdrant-set-keys
# Guide: https://secureanycloud.com/stacks/qdrant-1-19-2/Give applications that only search the read-only key. Keep the full API key for the applications and people that load and manage data.
Confirm the REST API requires your key
Requests without a key, or with a wrong one, are refused. Your key is accepted:
QDRANT_API_KEY=$(sudo sed -n 's/^QDRANT_API_KEY=//p' /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)"
echo "correct key -> HTTP $(curl -ks -o /dev/null -w '%{http_code}' -H "api-key: $QDRANT_API_KEY" https://127.0.0.1/collections)"no key -> HTTP 401 wrong key -> HTTP 401 correct key -> HTTP 200Confirm the gRPC API requires your key
The gRPC API on port 6334 is TLS-only and checks the same key, sent as api-key metadata. This command lists collections over gRPC with curl and prints the gRPC status, where 16 is UNAUTHENTICATED and 0 is OK.
QDRANT_API_KEY=$(sudo sed -n 's/^QDRANT_API_KEY=//p' /root/qdrant-info.txt) grpc_list() { printf '\0\0\0\0\0' | curl -sk --http2 -o /dev/null -D - -H 'content-type: application/grpc' -H 'te: trailers' "$@" --data-binary @- https://127.0.0.1:6334/qdrant.Collections/List | tr -d '\r' | grep -i '^grpc-status'; } echo "gRPC, no key: $(grpc_list)" echo "gRPC, wrong key: $(grpc_list -H 'api-key: wrong')" echo "gRPC, with key: $(grpc_list -H "api-key: $QDRANT_API_KEY")"gRPC, no key: grpc-status: 16 gRPC, wrong key: grpc-status: 16 gRPC, with key: grpc-status: 0From your own code, use any Qdrant client with TLS and the key. The following example uses the Python client (pip install qdrant-client), with REST on 443 or gRPC on 6334:
from qdrant_client import QdrantClient rest = QdrantClient(url="https://<public-ip>:443", api_key="<your-api-key>") grpc = QdrantClient(host="<public-ip>", port=443, grpc_port=6334, https=True, prefer_grpc=True, api_key="<your-api-key>") print(rest.get_collections())The certificate is self-signed. Either install a certificate that your clients already trust (Step 12), or give your clients a copy of /etc/nginx/tls/qdrant.crt to trust. The certificate covers the instance's IP addresses and DNS names.
Create a collection and run your first vector search
Create a movies collection with 4-dimensional cosine vectors, and add a few points with payloads (wait=true makes the write visible before you search). Then ask for the two nearest neighbors of a query vector:
QDRANT_API_KEY=$(sudo sed -n 's/^QDRANT_API_KEY=//p' /root/qdrant-info.txt) H="api-key: $QDRANT_API_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 -c '.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":"Notting Hill","genre":"romance"}}, {"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":"Paddington","genre":"family"}} ]}' | jq -c '.status' curl -ks -X POST https://127.0.0.1/collections/movies/points/query -H "$H" -H 'Content-Type: application/json' \
--data '{"query":[0.85,0.15,0.1,0.1],"limit":2,"with_payload":true}' \
| jq -r '.result.points[] | "\(.payload.title) score=\(.score)"'"ok" "ok" Interstellar score=0.99797505 Notting Hill score=0.2993925Searches use Qdrant's Query API (POST /collections/<name>/points/query). The older points/search endpoint is deprecated.
Use the read-only key
The read-only key can search, but it cannot write:
QDRANT_RO_KEY=$(sudo sed -n 's/^QDRANT_READ_ONLY_API_KEY=//p' /root/qdrant-info.txt) R="api-key: $QDRANT_RO_KEY" curl -ks -X POST https://127.0.0.1/collections/movies/points/query -H "$R" -H 'Content-Type: application/json' \
--data '{"query":[0.1,0.1,0.85,0.2],"limit":1,"with_payload":true}' | jq -r '.result.points[0].payload.title' echo "read-only upsert -> HTTP $(curl -ks -o /dev/null -w '%{http_code}' -X PUT 'https://127.0.0.1/collections/movies/points?wait=true' \
-H "$R" -H 'Content-Type: application/json' --data '{"points":[{"id":9,"vector":[0.5,0.5,0.5,0.5]}]}')"The Matrix read-only upsert -> HTTP 403Filter by payload
Index the genre payload field, then combine vector similarity with a filter so only science fiction titles come back:
QDRANT_API_KEY=$(sudo sed -n 's/^QDRANT_API_KEY=//p' /root/qdrant-info.txt) H="api-key: $QDRANT_API_KEY" curl -ks -X PUT 'https://127.0.0.1/collections/movies/index?wait=true' -H "$H" -H 'Content-Type: application/json' \
--data '{"field_name":"genre","field_schema":"keyword"}' | jq -c '.status' curl -ks -X POST https://127.0.0.1/collections/movies/points/query -H "$H" -H 'Content-Type: application/json' \
--data '{"query":[0.2,0.1,0.9,0.7],"filter":{"must":[{"key":"genre","match":{"value":"scifi"}}]},"limit":4,"with_payload":true}' \
| jq -r '.result.points[] | "\(.payload.title) score=\(.score)"'"ok" The Matrix score=0.8545449 Interstellar score=0.32867116Open the dashboard
Open the QDRANT_DASHBOARD_URL from the credentials file, for example https://<public-ip>/dashboard. The certificate is self-signed, so your browser shows a warning the first time. Check that the address is your instance's, and then continue.
The dashboard asks for an API key. Paste your QDRANT_API_KEY (or the read-only key to browse without being able to change anything), and choose Apply. The key is kept in your browser's local storage for this site.
- Collections lists every collection with its status, point count, segments and vector configuration. Open a collection to browse its points and payloads, find similar points or visualize the vectors.
- The Info tab shows the collection's configuration and status.
- The Console runs REST requests from the browser with your key and shows the response alongside.
The dashboard may show Update Available when a newer Qdrant release exists. See "Configuration, first boot and updates" below.
Take snapshots for backup and restore
A snapshot of a collection is written to /var/lib/qdrant/snapshots on the data volume, and you can download it with the API key. Creating, uploading and restoring snapshots needs the full API key. The read-only key is refused:
QDRANT_API_KEY=$(sudo sed -n 's/^QDRANT_API_KEY=//p' /root/qdrant-info.txt)
QDRANT_RO_KEY=$(sudo sed -n 's/^QDRANT_READ_ONLY_API_KEY=//p' /root/qdrant-info.txt)
curl -ks -X POST 'https://127.0.0.1/collections/movies/snapshots?wait=true' -H "api-key: $QDRANT_API_KEY" | jq -r '.result.name'
curl -ks https://127.0.0.1/collections/movies/snapshots -H "api-key: $QDRANT_API_KEY" | jq -r '.result[] | "\(.name) \(.size) bytes"' echo "read-only snapshot -> HTTP $(curl -ks -o /dev/null -w '%{http_code}' -X POST https://127.0.0.1/collections/movies/snapshots -H "api-key: $QDRANT_RO_KEY")"movies-4066997741393682-2026-10-20-01-10-05.snapshot movies-4066997741393682-2026-10-20-01-10-05.snapshot 103936 bytes read-only snapshot -> HTTP 403To restore a collection from a snapshot hosted elsewhere, call PUT /collections/<name>/snapshots/recover with {"location": "https://..."} and the full API key. Qdrant downloads the file itself. It cannot reach the instance metadata service, so this call cannot be used to read the instance's role credentials.
Serve Qdrant under your own DNS name and certificate
Point a DNS record at the instance, and then tell the instance its name. qdrant-set-host saves the name to /etc/sac/qdrant-hostname, makes a new self-signed certificate for it, and updates nginx and the URLs in the credentials file:
sudo qdrant-set-host <your-domain>To use a certificate from a public CA instead (for example from Let's Encrypt, with port 80 open to the internet while you request it), copy the certificate and key over the instance's own, and restart nginx:
sudo apt-get install -y certbot
sudo systemctl stop nginx
sudo certbot certonly --standalone -d <your-domain>
sudo install -m 0644 /etc/letsencrypt/live/<your-domain>/fullchain.pem /etc/nginx/tls/qdrant.crt
sudo install -m 0600 /etc/letsencrypt/live/<your-domain>/privkey.pem /etc/nginx/tls/qdrant.key
sudo systemctl start nginxqdrant-set-host replaces the certificate when it runs. Run it before you install your own certificate, and set the host name file first so that the boot-time check keeps your name.
Rotate the keys
To replace both keys, for example after a key was shared too widely, run:
sudo qdrant-set-keysqdrant-set-keys: keys written to /root/qdrant-info.txt (root only)The command writes the new keys to /root/qdrant-info.txt and restarts Qdrant with them. The old keys stop working at once. Update your applications and the dashboard with the new keys.
Configuration, first boot and updates
- Settings: Qdrant's settings live in
/etc/qdrant/config.base.yaml. After editing the file, runsudo qdrant-set-keys --keepto render/etc/qdrant/config.yamlwith your current keys, and then runsudo systemctl restart qdrant. Keepservice:as a section in the file, because the keys are added under it. - First boot: The first-boot unit (
qdrant-firstboot) runs once.qdrant-set-hostruns at every boot and keeps the names and certificate in step with the instance's addresses (a stop and start can change the public IP), unless you set a fixed name. - Updates: Ubuntu security updates are applied automatically by unattended-upgrades. Update Qdrant itself by replacing
/opt/qdrant/bin/qdrantwith a newer official release binary and restarting the service. Take a snapshot first, and read the Qdrant release notes before you upgrade across minor versions. - Security fix: This image ships Qdrant 1.19.2, which includes the fix for GHSA-3gph-6c29-p29v (a read-only key or JWT accepted on the inter-node cluster API when
enforce_internal_authis enabled, affecting 1.18.0 to 1.19.1). The image runs a single node with clustering off. - Snapshots in Amazon S3: In
config.base.yaml, setsnapshots_storage: s3and ans3_configsection (bucket, region,access_key,secret_key) understorage.snapshots_config. Give Qdrant an access key for that bucket, because Qdrant cannot reach the instance metadata service and so cannot use the instance's IAM role.
Support
SecureAnyCloud provides 24/7 technical support for this image by email and live chat: deployment, first login, HTTPS setup, upgrades, performance tuning and troubleshooting. Contact sales@secureanycloud.com.
Qdrant is a trademark of its respective owner. SecureAnyCloud is not affiliated with or endorsed by the Qdrant project or its owner. All other product and company names are trademarks or registered trademarks of their respective holders.
Deploy on AWS
Launch Qdrant 1.19.2 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com