Por qué autoalojar Qdrant en un VPS
Qdrant almacena y consulta vectores de embeddings para encontrar los elementos semánticamente más cercanos: es la pieza de búsqueda en el corazón de los chatbots RAG, de los motores de recomendación y de la búsqueda en lenguaje natural. Escrita en Rust, es rápida y frugal en recursos, lo que la hace ideal para alojar en un VPS en lugar de pagar un servicio vectorial gestionado facturado por vector almacenado.
El autoalojamiento es esencial para las aplicaciones de IA que tratan datos sensibles: sus embeddings, a menudo derivados de documentos internos confidenciales, nunca salen de su infraestructura. También domina la latencia, determinante cuando cada consulta de usuario dispara una búsqueda vectorial, y evita los límites de tasa de las API de terceros en los picos de carga.
Requisitos previos y recursos VPS recomendados
- RAM: mínimo 1 GB para pruebas, 2 GB para unos cientos de miles de vectores, 4–8 GB por encima del millón de vectores en alta dimensión (el índice HNSW vive en memoria).
- Almacenamiento: 20–50 GB de SSD NVMe para persistir colecciones y snapshots.
- CPU: 1–2 vCPU son suficientes para tráfico moderado; añada núcleos si indexa continuamente.
- Docker y Docker Compose instalados en el VPS.
- Puertos 6333 (REST) y 6334 (gRPC) accesibles desde su aplicación; 80/443 para el reverse proxy público.
- Un registro DNS A (p. ej.
vectors.midominio.com) si expone la API en HTTPS.
Instalar Qdrant con Docker Compose
Crear el directorio y el compose.yml
En el VPS, cree una carpeta dedicada:
mkdir -p /opt/qdrant && cd /opt/qdrant. Cree el siguientecompose.yml:services: qdrant: image: qdrant/qdrant:latest restart: unless-stopped ports: - "127.0.0.1:6333:6333" - "127.0.0.1:6334:6334" volumes: - ./qdrant_storage:/qdrant/storage environment: - QDRANT__SERVICE__API_KEY=${QDRANT_API_KEY}Enlazar los puertos a
127.0.0.1impide cualquier exposición directa en Internet; solo el reverse proxy puede acceder a ellos.Generar la clave API e iniciar el contenedor
Cree el archivo
.envcon su clave:echo "QDRANT_API_KEY=$(openssl rand -hex 32)" > .envInicie Qdrant:
docker compose up -dComprobar la salud de la instancia
Espere unos segundos y verifique el endpoint de salud:
curl -s http://localhost:6333/healthz # Esperado: {"title":"qdrant - vector search engine","version":"..."}Crear su primera colección
Cree una colección de prueba con vectores de dimensión 384:
curl -s -X PUT http://localhost:6333/collections/test \ -H 'Content-Type: application/json' \ -H "api-key: $(grep QDRANT_API_KEY .env | cut -d= -f2)" \ -d '{"vectors":{"size":384,"distance":"Cosine"}}'
Segurizar el acceso: clave API y TLS
Qdrant no activa ninguna autenticación por defecto: una instancia expuesta sin clave API permitiría a cualquiera leer, modificar o borrar todas sus colecciones. La variable de entorno QDRANT__SERVICE__API_KEY es la primera línea de defensa; el reverse proxy con TLS es la segunda.
Para Caddy, la configuración mínima es:
vectors.midominio.com {
reverse_proxy localhost:6333
}Caddy obtiene y renueva automáticamente el certificado Let's Encrypt. Para nginx, añada dentro de su bloque server:
location / {
proxy_pass http://127.0.0.1:6333;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}Active TLS con Certbot: certbot --nginx -d vectors.midominio.com.
Probar la autenticación y el reverse proxy
Verificar que el acceso sin clave es rechazado
curl -s https://vectors.midominio.com/collections # Esperado: {"status":{"error":"Unauthorized",...}}Llamada autenticada con la clave API
curl -s https://vectors.midominio.com/collections \ -H "api-key: YOUR_KEY" # Esperado: {"result":{"collections":[]},"status":"ok",...}Verificar el certificado TLS
curl -sv https://vectors.midominio.com/healthz 2>&1 | grep 'SSL connection\|issuer' # Esperado: líneas confirmando Let's Encrypt y TLS 1.3
Crear una colección e insertar vectores con el cliente Python v1
Instalar el cliente oficial
pip install qdrant-client>=1.7Conectar con la clave API
from qdrant_client import QdrantClient client = QdrantClient( url="https://vectors.midominio.com", api_key="YOUR_KEY", )Crear una colección con VectorParams
from qdrant_client.models import Distance, VectorParams client.recreate_collection( collection_name="documentos", vectors_config=VectorParams(size=384, distance=Distance.COSINE), )Insertar puntos con payload y consultar
from qdrant_client.models import PointStruct client.upsert( collection_name="documentos", points=[ PointStruct( id=1, vector=[0.1, 0.2, ...], payload={"titulo": "Guía Qdrant", "lang": "es"}, ), ], ) resultados = client.search( collection_name="documentos", query_vector=[0.1, 0.21, ...], limit=5, with_payload=True, ) for r in resultados: print(r.score, r.payload)
Optimizar el rendimiento: ajuste de HNSW
El algoritmo HNSW (Hierarchical Navigable Small World) es el núcleo de la búsqueda rápida en Qdrant. Tres parámetros gobiernan el equilibrio velocidad/precisión/memoria.
Parámetros HNSW clave
Desplace la tabla
| Parámetro | Valor por defecto | Rango recomendado | Impacto |
|---|---|---|---|
| m | 16 | 16–64 | Conexiones por nodo — mayor = mejor recall, más RAM |
| ef_construct | 100 | 100–400 | Calidad de construcción del índice — mayor = mejor índice, construcción más lenta |
| ef | 128 (en consulta) | 64–512 | Calidad de búsqueda — mayor = mejor recall, consulta más lenta |
Configurar HNSW al crear la colección
Pase los parámetros HNSW directamente en recreate_collection:
from qdrant_client.models import HnswConfigDiff
client.recreate_collection(
collection_name="documentos",
vectors_config=VectorParams(size=384, distance=Distance.COSINE),
hnsw_config=HnswConfigDiff(m=32, ef_construct=200),
)Para una búsqueda equilibrada en un corpus de 500 000 vectores, m=32 y ef_construct=200 ofrecen un buen recall (>0,97) sin sobrecargar la RAM. Aumente ef en la consulta cuando la precisión sea más importante que la latencia.
Reducir la huella de memoria: cuantificación escalar y binaria
- Cuantificación escalar (uint8): comprime cada coordenada float32 (4 bytes) a uint8 (1 byte), una reducción de RAM de ~4×. Ligera pérdida de precisión compensada por el sobremuestreo (oversampling).
- Cuantificación binaria: reducción de hasta 32× binarizando cada dimensión. Ideal para modelos entrenados para cuantificación binaria.
- Parámetro
on_disk: almacena los vectores originales en disco y mantiene en RAM solo el índice cuantificado. Indispensable en un VPS con memoria limitada. - Oversampling: con
oversampling=2.0en la consulta, Qdrant recupera el doble de candidatos del índice cuantificado y los reordena con los vectores originales.
Hacer copias de seguridad y restaurar con snapshots de Qdrant
Crear un snapshot de una colección
curl -s -X POST https://vectors.midominio.com/collections/documentos/snapshots \ -H "api-key: YOUR_KEY"Listar los snapshots disponibles
curl -s https://vectors.midominio.com/collections/documentos/snapshots \ -H "api-key: YOUR_KEY"Descargar el snapshot
curl -O https://vectors.midominio.com/collections/documentos/snapshots/NOMBRE_SNAPSHOT \ -H "api-key: YOUR_KEY"Copie el archivo
.snapshota un almacenamiento de objetos externo para una copia de seguridad fuera del sitio.Restaurar desde un snapshot
curl -s -X PUT https://vectors.midominio.com/collections/documentos/snapshots/upload \ -H "api-key: YOUR_KEY" \ -H 'Content-Type: multipart/form-data' \ -F [email protected]
Monitoreo con Prometheus y Grafana
Qdrant expone un endpoint /metrics en formato Prometheus en el puerto 6333. Añada el objetivo en su prometheus.yml:
scrape_configs:
- job_name: qdrant
static_configs:
- targets: ['localhost:6333']
metrics_path: /metrics
bearer_token: YOUR_KEYEn Grafana, importe el dashboard comunitario de Qdrant (ID 18278) para visualizar la latencia p99 y la tasa de errores en tiempo real.
Resolución de problemas habituales
- Connection refused en el puerto 6333: compruebe que el contenedor está en marcha (
docker compose ps) y que el puerto no está bloqueado porufw. - Error OOM / contenedor eliminado: reduzca
ef_constructo active la cuantificación escalar para bajar la huella de RAM del índice. - Lentitud en el arranque o la primera carga: el índice HNSW se carga desde el disco en el primer acceso; use SSD NVMe y realice una búsqueda de calentamiento tras el inicio.
- Unauthorized 403: la clave en la cabecera
api-keyno coincide conQDRANT__SERVICE__API_KEY; compruebe que no hay espacios ni saltos de línea en la variable de entorno. - Recall degradado tras activar la cuantificación binaria: aumente
oversamplinga 3.0 o 4.0 y activerescore=Truepara reordenar los candidatos con los vectores originales.
Asociar Qdrant con Ollama para un stack RAG totalmente autónomo
Ejecute Ollama en el mismo VPS para la generación de embeddings (ollama pull mxbai-embed-large) y la inferencia (ollama pull llama3.1:8b). Su pipeline RAG funciona entonces de extremo a extremo sin ninguna llamada a una API externa: pregunta del usuario → embedding Ollama → búsqueda Qdrant → fragmentos top-k → generación Ollama → respuesta fundamentada.
Añada LiteLLM por delante para exponer un endpoint unificado compatible con OpenAI a su aplicación, y cambie de modelo sin modificar una línea de código. Un VPS con 8 GB de RAM aloja cómodamente Qdrant + Ollama (modelo 7B cuantificado) + LiteLLM para un corpus de unos cientos de miles de vectores.