Self-hosted • Privacy-first • No tracking
Home / Self-Hosted AI / Deploy Qdrant v1.19.0 in Your Homelab: A Step-by-Step Docker Compose Guide
Self-Hosted AI #homelab#docker-compose#self-hosted-ai#qdrant#vector-database ⏱ 10 min • 👁 4 • Sep 01, 2026

Deploy Qdrant v1.19.0 in Your Homelab: A Step-by-Step Docker Compose Guide

Learn to self-host Qdrant v1.19.0 with Docker Compose: prerequisites, full config, security hardening, and troubleshooting for production-grade vector search.

AdSense — Top (970x90) • Responsive
Deploy Qdrant v1.19.0 in Your Homelab: A Step-by-Step Docker Compose Guide

Introduction

Vector databases have become the backbone of modern AI applications—from semantic search and recommendation engines to Retrieval-Augmented Generation (RAG) pipelines. When you self-host these workloads, you retain full control over your data, avoid vendor lock-in, and reduce latency by keeping inference and storage on your own hardware. Among the available options, Qdrant stands out for its performance, ease of deployment, and a permissive open-source license (Apache 2.0).

This guide walks you through deploying Qdrant v1.19.0 (the latest official release as of August 2026) on your own server using Docker Compose. You'll learn the hardware prerequisites, a production-ready Compose configuration, advanced settings for reverse proxy and backups, and how to solve the most common pitfalls. By the end, you'll have a fully functional vector search service ready to integrate with your AI stack.

We'll focus on practical steps—every command is copy-paste ready, and every configuration is explained. We'll also cover security hardening so your instance isn't left wide open on the network. Whether you're running a small Raspberry Pi cluster or a dedicated rack server, this guide adapts to your setup.

Let's get started.

Prerequisites / Requirements

Before you begin, ensure your host meets the following requirements. These are typical ranges—actual usage depends on the number of vectors, their dimensions, and query load.

Component Minimum Recommended Notes
CPU 1 core 2+ cores Qdrant is efficient, but indexing large collections benefits from multiple cores.
RAM 512 MB 2 GB+ Memory usage scales with collection size and number of concurrent queries.
Storage 10 GB free SSD with 50+ GB Qdrant uses memory-mapped files; SSD dramatically improves performance.
Software Docker 20.10+, Docker Compose v2 Latest stable Install from official Docker repos.
Network Open port 6333 (HTTP) and 6334 (gRPC) Firewall rules If you expose Qdrant beyond localhost, use a reverse proxy with SSL.

Note on versions: We use image: qdrant/qdrant:v1.19.0 as verified from the official release. However, always check the official Qdrant GitHub releases page before pinning—the version may be outdated by the time you read this. The guide uses a .env file so you can easily update the version without editing the Compose file.

Step-by-Step Installation Guide

Step 1: Create the Project Directory and .env File

Create a dedicated directory for Qdrant and set up an environment file to store configuration variables. This keeps secrets out of your Compose file and allows easy version updates.

mkdir -p ~/qdrant && cd ~/qdrant && touch .env

Now edit the .env file with your favorite text editor (e.g., nano .env) and add the following content. Important: Never commit this file to Git—it contains sensitive values.

# .env
QDRANT_VERSION=v1.19.0
QDRANT_API_KEY=change_this_to_a_long_random_string
QDRANT__SERVICE__GRPC_PORT=6334
QDRANT__SERVICE__HTTP_PORT=6333

Generate a strong API key using openssl rand -base64 32 and replace the placeholder. This key will be required for all API calls.

Step 2: Create the Docker Compose File

Create a docker-compose.yml file in the same directory. This configuration uses the official Qdrant image, mounts a volume for persistent storage, and applies security best practices.

services:
  qdrant:
    image: qdrant/qdrant:${QDRANT_VERSION:-latest}
    container_name: qdrant
    restart: unless-stopped
    ports:
      - "${QDRANT__SERVICE__HTTP_PORT:-6333}:6333"
      - "${QDRANT__SERVICE__GRPC_PORT:-6334}:6334"
    volumes:
      - ./qdrant_storage:/qdrant/storage
    environment:
      - QDRANT__SERVICE__API_KEY=${QDRANT_API_KEY}
      - QDRANT__SERVICE__GRPC_PORT=${QDRANT__SERVICE__GRPC_PORT:-6334}
      - QDRANT__SERVICE__HTTP_PORT=${QDRANT__SERVICE__HTTP_PORT:-6333}
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:6333/healthz"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s

Explanation:

  • image uses the version from .env, falling back to latest if not set.
  • Ports are mapped from the host to the container, using the same environment variables.
  • The volume ./qdrant_storage persists data between container restarts.
  • The API key is passed via environment variable—never hardcode it in the Compose file.
  • The healthcheck uses curl (available in the image) to verify readiness.

Step 3: Start the Container

Launch the Qdrant container in detached mode.

docker compose up -d && docker compose logs -f

Wait for the logs to show Qdrant listening on 0.0.0.0:6333 and gRPC listening on 0.0.0.0:6334. Then press Ctrl+C to stop following logs.

Step 4: Verify the Installation

Test the HTTP API with a simple curl request. You should see the Qdrant version and commit hash.

curl -s http://localhost:6333/ | jq .

If you have jq installed, this pretty-prints the JSON. Otherwise, just use curl -s. The response should include "title":"qdrant" and "version":"1.19.0".

Step 5: Create a Collection and Insert a Vector

To confirm the API key works, create a test collection and insert a vector. Replace YOUR_API_KEY with the value from your .env file.

curl -X PUT http://localhost:6333/collections/test_collection \
  -H "api-key: $QDRANT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"vectors": {"size": 4, "distance": "Dot"}}'

Then insert a point:

curl -X PUT http://localhost:6333/collections/test_collection/points \
  -H "api-key: $QDRANT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"points": [{"id": 1, "vector": [0.1, 0.2, 0.3, 0.4]}]}'

If both return {"result":true,"status":"ok"}, your setup is functional.

Step 6: Configure the Storage Volume (Optional but Recommended)

By default, the volume is owned by the root user inside the container. For easier host access, you can adjust permissions. First, stop the container, then check the user ID used inside the image.

docker compose down && docker run --rm -it qdrant/qdrant:v1.19.0 id

The output will show uid=1000(qdrant) gid=1000(qdrant). To match this on your host, run id -u && id -g and note your host user's IDs. If they differ, you can either use a named volume (which Docker manages) or set the user: directive in Compose to match the container's user. For simplicity, we'll keep the default and access data via docker exec if needed.

Step 7: Set Up a Reverse Proxy with SSL (Caddy)

Exposing Qdrant directly on port 6333 is fine for LAN use, but for internet access you should use a reverse proxy with TLS. Here's a minimal Caddy configuration that sits in front of Qdrant.

First, add a Caddy service to your Compose file (or create a separate one). We'll extend the existing file.

# Add this to docker-compose.yml under 'services:'
  caddy:
    image: caddy:2.7.6
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config

Create a Caddyfile with the following content (replace qdrant.example.com with your domain):

qdrant.example.com {
    reverse_proxy qdrant:6333
}

Finally, add named volumes to the bottom of the Compose file:

volumes:
  caddy_data:
  caddy_config:

Restart the stack:

docker compose up -d

Now you can access Qdrant via https://qdrant.example.com.

Step 8: Enable HTTPS for Internal Services (Optional)

If you're only using Qdrant internally, you can still enable TLS by generating self-signed certificates and mounting them into the container. However, this is beyond the scope of this guide—refer to Qdrant's official TLS documentation for details.

Step 9: Back Up Your Data

Backups are critical. The simplest method is to stop the container and copy the qdrant_storage directory. For a running system, use docker exec to create a snapshot using Qdrant's built-in snapshot API.

curl -X POST http://localhost:6333/snapshots \
  -H "api-key: $QDRANT_API_KEY"

This creates a snapshot file inside the container. To copy it to the host, use:

docker cp qdrant:/qdrant/storage/snapshots .

Alternatively, automate backups with a cron job that runs docker exec and tar. We'll cover a more robust backup strategy in the advanced section.

Step 10: Update Qdrant Version

To upgrade to a newer version, simply change the QDRANT_VERSION in your .env file and run:

docker compose pull && docker compose up -d

Always check the upgrade notes for breaking changes.

Advanced Configuration / Optimization

Reverse Proxy and SSL

We already set up Caddy in Step 7. For Nginx or Traefik, the principle is the same: proxy requests to qdrant:6333 and handle TLS termination. Remember to forward the api-key header—Caddy does this automatically.

Backups and Restore

For production, schedule regular snapshots. Here's a cron job that runs daily at 2 AM:

0 2 * * * curl -X POST http://localhost:6333/snapshots -H "api-key: $QDRANT_API_KEY" && find /path/to/snapshots -type f -mtime +7 -delete

To restore, copy the snapshot file into the container and use the recovery API:

curl -X POST http://localhost:6333/snapshots/recover \
  -H "api-key: $QDRANT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"location": "snapshots/your_snapshot.snapshot"}'

Security Hardening (Optional)

The following are advanced security measures. They may break container functionality if not adapted to your environment—do not copy them blindly.

  • Read-only filesystem: Add read_only: true to the service. This prevents writes to the container's filesystem, but Qdrant needs to write to /qdrant/storage. You must mount a writable volume for that path.
  • Drop capabilities: Add cap_drop: ["ALL"] to the service. This removes all Linux capabilities, but Qdrant may need CHOWN and SETGID to manage storage. Test thoroughly.
  • Run as non-root user: Add user: "1000:1000" to the service, but verify the UID/GID against the image's default (see Step 6).

Example snippet (adapt carefully):

    read_only: true
    cap_drop:
      - ALL
    user: "1000:1000"

Resource Limits

To prevent Qdrant from consuming all host memory, set limits in the Compose file:

    deploy:
      resources:
        limits:
          memory: 2G

This is a Docker Compose v2 feature; for docker run, use --memory.

Troubleshooting Common Issues

Error / Symptom Likely Cause Solution
Connection refused on port 6333 Container not running or port not mapped correctly Check docker ps; verify port mapping in Compose; ensure no firewall blocks the port.
401 Unauthorized Wrong API key or missing header Confirm the API key in .env matches the one used in requests; add -H "api-key: $QDRANT_API_KEY" to every request.
Out of memory error Host RAM insufficient Increase host memory or reduce collection size; set memory limits in Compose.
Volume permission denied Host user doesn't match container user Run id -u on host and compare with container's user (1000). Adjust user: directive or chown the volume.
Healthcheck fails curl not installed in image Use wget or remove healthcheck; or use a custom healthcheck with Python.
Snapshot not found during recovery Snapshot path incorrect Ensure the snapshot file is placed in the correct directory (e.g., /qdrant/storage/snapshots).
Slow queries Storage on HDD, no index optimization Move to SSD; create indexes on payload fields; adjust optimizers settings.

Conclusion and FAQ

Self-hosting Qdrant is a straightforward process that gives you a powerful vector search engine with full data sovereignty. By following this guide, you've deployed a production-ready instance with persistent storage, API key authentication, and a reverse proxy for secure remote access. The advanced sections help you scale and harden your setup as needed.

Remember to keep your .env file safe, back up regularly, and watch for new releases. Qdrant is actively developed, and staying current ensures you get performance improvements and security patches.

Frequently Asked Questions

1. Can I run Qdrant on a Raspberry Pi?

Yes, Qdrant works on ARM architectures. Use the official ARM image (qdrant/qdrant:latest includes multi-arch). Performance will be limited by the Pi's RAM and CPU, but for small collections (e.g., <100k vectors of 768 dimensions), it's usable. Expect slower indexing and query times compared to a desktop server.

2. How do I change the default API key after deployment?

Edit the .env file, change QDRANT_API_KEY, then run docker compose up -d to recreate the container. All existing collections remain intact. Clients must use the new key.

3. What is the difference between HTTP and gRPC ports?

HTTP (port 6333) is the REST API, used for most operations. gRPC (port 6334) is a high-performance RPC interface, ideal for large payloads and low latency. Both are enabled by default. You can disable gRPC by setting QDRANT__SERVICE__GRPC_PORT=0.

4. How do I back up Qdrant without downtime?

Use the snapshot API (POST /snapshots). It creates a consistent snapshot without stopping the service. Then copy the snapshot file from the container to your backup location. For critical systems, also back up the entire qdrant_storage directory periodically.

5. Can I use Qdrant with LangChain or LlamaIndex?

Yes, both frameworks have built-in Qdrant integrations. Set the QDRANT_URL environment variable to your instance's URL (e.g., http://localhost:6333) and provide the API key. This allows you to use Qdrant as a vector store for RAG pipelines.

AdSense — In-article (responsive)

Related Guides