Qdrant is an open-source vector database written in Rust. It stores embeddings with JSON payloads, and runs fast similarity search with rich filtering. It’s a popular choice for RAG (retrieval-augmented generation), semantic search and recommendations. Self-hosting it on a VPS keeps your data private, with no per-vector pricing.

Requirements

  • Docker. See installing Docker on Ubuntu.
  • RAM: plan for your vectors plus overhead. One million 768-dimension float vectors take about 3 GB in memory. Qdrant can keep vectors on disk (on_disk) and use quantization to cut memory use substantially.
  • SSD storage. See how much RAM a VPS needs.

Docker Compose

# /opt/qdrant/compose.yaml
services:
  qdrant:
    image: qdrant/qdrant:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:6333:6333"     # REST API + web dashboard
      - "127.0.0.1:6334:6334"     # gRPC
    environment:
      QDRANT__SERVICE__API_KEY: ${QDRANT_API_KEY}
    volumes:
      - ./storage:/qdrant/storage
cd /opt/qdrant
echo "QDRANT_API_KEY=$(openssl rand -hex 32)" > .env
docker compose up -d
curl -H "api-key: $(grep -oP '(?<==).*' .env)" http://127.0.0.1:6333/

Ports are bound to localhost. Applications on the same server connect directly, and remote applications should go through a reverse proxy with HTTPS (or a private network), always with the API key. Pin a specific version tag in production instead of latest. See Docker Compose in production.

Expose it securely (optional)

server {
    server_name qdrant.example.com;
    client_max_body_size 64m;
    location / {
        proxy_pass http://127.0.0.1:6333;
        proxy_set_header Host $host;
    }
}

Add HTTPS with Certbot, and restrict access by IP if only your app servers need it. The web dashboard is at /dashboard. See reverse proxy on a VPS and Let’s Encrypt with Certbot on Nginx.

Create a collection

The vector size must match your embedding model. Choose the distance the model was trained for (usually Cosine for text):

curl -X PUT http://127.0.0.1:6333/collections/docs \
  -H "api-key: $QDRANT_API_KEY" -H "Content-Type: application/json" \
  -d '{"vectors": {"size": 768, "distance": "Cosine"}}'

Distances: Cosine, Dot, Euclid, Manhattan.

Insert points

A point has an ID, a vector, and an optional JSON payload (metadata used for filtering and returned with results):

curl -X PUT "http://127.0.0.1:6333/collections/docs/points?wait=true" \
  -H "api-key: $QDRANT_API_KEY" -H "Content-Type: application/json" \
  -d '{"points": [
        {"id": 1, "vector": [0.01, 0.02, …], "payload": {"source": "nginx.md", "lang": "en"}},
        {"id": 2, "vector": [0.03, -0.01, …], "payload": {"source": "docker.md", "lang": "en"}}
      ]}'

Search with the Python client

from qdrant_client import QdrantClient, models

client = QdrantClient(url="http://127.0.0.1:6333", api_key=QDRANT_API_KEY)

hits = client.query_points(
    collection_name="docs",
    query=embed("How do I enable HTTPS?"),          # your embedding function
    query_filter=models.Filter(must=[
        models.FieldCondition(key="lang", match=models.MatchValue(value="en"))
    ]),
    limit=5,
    with_payload=True,
).points

for h in hits:
    print(h.score, h.payload["source"])

(pip install qdrant-client.) For fields you filter on often, create a payload index, so filtered searches stay fast:

client.create_payload_index("docs", field_name="lang", field_schema="keyword")

Save memory

  • Quantization (scalar int8, binary, or product) shrinks vectors in RAM, with little recall loss. Original vectors can stay on disk for rescoring.
  • on_disk: true for vectors, and payload stored on disk, for large collections on smaller servers.
  • Tune the HNSW index (m, ef_construct) only if defaults don’t meet your recall or latency targets.

Backups

Qdrant has a built-in API to create a consistent copy of a collection (POST /collections/docs/snapshots), saved under the storage directory. Copy those files off the server regularly, or back up the storage volume with the container stopped. See Docker volume backups and restic backups.

Updates

docker compose pull && docker compose up -d

Read the release notes before major version jumps: Qdrant supports upgrading one minor version at a time for storage compatibility.

Qdrant vs pgvector

Qdrant pgvector
Setup Separate service Extension in PostgreSQL
Filtering Rich payload filters, payload indexes SQL WHERE
Memory tools Quantization, on-disk vectors halfvec, standard PG tuning
Joins and transactions No Yes
Best for Dedicated, large or filter-heavy vector search Apps already on PostgreSQL

See pgvector and vector databases.

Quick reference

Task How
Run qdrant/qdrant image, ports 6333/6334
Secure QDRANT__SERVICE__API_KEY, localhost bind, HTTPS proxy
Collection PUT /collections/{name} with size + distance
Insert PUT /collections/{name}/points
Search client.query_points(…)
Fast filters Payload indexes
Dashboard /dashboard

Related: VPS for AI workloads.

  • AI
  • Database
  • Docker