MAATRIX / Блог / Qdrant на Ubuntu 24.04: пошаговая установка

Qdrant на Ubuntu 24.04: пошаговая установка

Qdrant на Ubuntu 24.04: пошаговая установка

MAATRIX

В документации Qdrant установка — одна строка с docker run, и на Ubuntu 24.04 она честно отрабатывает: вместе с базой, открытой в интернет без пароля, дашбордом на 404 и хранилищем, которое исчезает при первом docker compose down -v. Ниже — установка Qdrant на Ubuntu двумя рабочими способами, бинарником под systemd и через Docker Compose, с закрытым периметром, ключом и снапшотами.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что именно ставится и чем noble отличается от jammy

Qdrant — векторная база на Rust: один исполняемый файл, без JVM, интерпретатора и GPU. Он держит коллекции векторов с полезной нагрузкой (payload), ищет ближайших соседей по индексу HNSW и отвечает по REST и gRPC. Портов три: 6333 — REST API и дашборд на /dashboard, 6334 — gRPC, быстрее на массовой загрузке, 6335 — обмен между узлами кластера.

Дальше главное: пакета Qdrant в репозиториях Ubuntu нет, и собственного apt-репозитория проект не держит. apt-cache policy qdrant на noble возвращает пустой кандидат, а в релизах на GitHub лежат tar-архивы, а не .deb. Рабочих путей ровно два — бинарник под systemd и контейнер.

Чем noble отличается от jammy — каждая строка ниже во что-нибудь упирается:

ЧтоUbuntu 22.04Ubuntu 24.04 (noble)
glibc2.352.39
Python по умолчанию3.103.12 + PEP 668
nginx в репозитории1.181.24.0
systemd249255
Compose v1 (docker-compose)ещё естьудалён
UID 1000свободензанят учёткой ubuntu

Собранный на noble бинарник не запустится на 22.04 — /lib/x86_64-linux-gnu/libc.so.6: version 'GLIBC_2.38' not found; обратное направление работает, поэтому официальный -gnu-архив ставится без вопросов. PEP 668 ломает pip install qdrant-client, отсутствие Compose v1 даёт docker-compose: command not found, а занятый UID 1000 мешает завести сервисного пользователя.

Подготовка системы: пользователь, каталоги, лимиты

Обновляемся и ставим инструменты — jq понадобится почти в каждой команде.

sudo apt update && sudo apt -y upgrade
sudo apt -y install curl jq ca-certificates

На 24.04 при каждом апгрейде вылезает синий диалог needrestart — в скрипте он вешает установку намертво. Отключается один раз:

sudo sed -i "s/^#\$nrconf{restart} = 'i';/\$nrconf{restart} = 'a';/" /etc/needrestart/needrestart.conf

Сервисному пользователю не задавайте UID 1000: в облачных образах 24.04 он занят учёткой ubuntu, и useradd -u 1000 qdrant отвечает useradd: UID 1000 is not unique.

sudo useradd --system --shell /usr/sbin/nologin \
  --home-dir /var/lib/qdrant --create-home qdrant
sudo mkdir -p /var/lib/qdrant/storage /var/lib/qdrant/snapshots /etc/qdrant
sudo chown -R qdrant:qdrant /var/lib/qdrant
sudo chmod 750 /var/lib/qdrant

Разделение каталогов не косметика: снапшот, занявший место рядом с данными, даёт Service internal error: No space left on device (os error 28). Запас смотрите заранее: df -h /var/lib.

Отдельно — лимит открытых файлов. Qdrant режет коллекцию на сегменты и отображает их файлы через mmap, так что счёт дескрипторов идёт на тысячи. Дефолтные 1024 однажды дают Too many open files (os error 24), и лечится это строкой LimitNOFILE=65536 в юните (для контейнера — секцией ulimits).

И безопасность — до первого запуска, а не после. По умолчанию Qdrant слушает 0.0.0.0 и не требует авторизации. Открытый наружу 6333 — это база, из которой любой выкачивает ваши эмбеддинги, а curl -X DELETE http://ваш-ip:6333/collections/docs сносит коллекцию без подтверждений и корзины.

sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status numbered

Порт 6333 сюда не добавляйте: наружу Qdrant выходит через прокси с TLS, а серверу приложений выдаётся правило sudo ufw allow from 203.0.113.10 to any port 6333 proto tcp.

Развернуть за пару минут

Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть Qdrant

Способ 1: бинарник из релиза и systemd-юнит

Меньше слоёв и понятные логи в journalctl. Забираем архив под glibc:

VER=$(curl -s https://api.github.com/repos/qdrant/qdrant/releases/latest | jq -r .tag_name)
sudo mkdir -p /opt/qdrant
curl -sL -o /tmp/qdrant.tar.gz \
  "https://github.com/qdrant/qdrant/releases/download/${VER}/qdrant-x86_64-unknown-linux-gnu.tar.gz"
sudo tar -xzf /tmp/qdrant.tar.gz -C /opt/qdrant
sudo /opt/qdrant/qdrant --version

Рядом лежит статический вариант -musl — он нужен для переезда на старый дистрибутив; для Ubuntu 24.04 берите -gnu.

Дальше конфиг и главная ловушка бинарной установки. Qdrant ищет каталог config/ относительно рабочего каталога процесса, а storage_path и snapshots_path по умолчанию тоже относительные. Без WorkingDirectory systemd стартует процесс из /, и Qdrant создаёт /storage в корне файловой системы, считая это нормой. Лечится абсолютными путями и явным --config-path в /etc/qdrant/config.yaml:

log_level: INFO
telemetry_disabled: true

storage:
  storage_path: /var/lib/qdrant/storage
  snapshots_path: /var/lib/qdrant/snapshots
  on_disk_payload: true

service:
  host: 127.0.0.1
  http_port: 6333
  grpc_port: 6334
  enable_cors: false

Ключ в этот файл не кладите: подстановку ${VAR} Qdrant в YAML не выполняет, строка уедет в конфиг дословно. Работает переопределение через окружение — параметр задаётся переменной QDRANT__ с двойным подчёркиванием вместо вложенности: QDRANT__SERVICE__API_KEY.

printf 'QDRANT__SERVICE__API_KEY=%s\n' "$(openssl rand -hex 32)" \
  | sudo tee /etc/qdrant/qdrant.env > /dev/null
sudo chown root:qdrant /etc/qdrant/qdrant.env && sudo chmod 640 /etc/qdrant/qdrant.env

Юнит /etc/systemd/system/qdrant.service:

[Unit]
Description=Qdrant vector database
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=qdrant
Group=qdrant
WorkingDirectory=/var/lib/qdrant
EnvironmentFile=/etc/qdrant/qdrant.env
ExecStart=/opt/qdrant/qdrant --config-path /etc/qdrant/config.yaml
Restart=always
RestartSec=5
LimitNOFILE=65536
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/lib/qdrant

[Install]
WantedBy=multi-user.target

ProtectSystem=strict монтирует всё только на чтение, поэтому ReadWritePaths=/var/lib/qdrant обязателен: забудете строку — сервис ляжет с Permission denied (os error 13).

sudo systemctl daemon-reload
sudo systemctl enable --now qdrant
journalctl -u qdrant -n 40 --no-pager

Успешный старт — ASCII-баннер и строки:

Version: 1.15.1, build: a1b2c3d
Access web UI at http://localhost:6333/dashboard

INFO qdrant: Qdrant HTTP listening on 6333
INFO actix_server::builder: starting 8 workers
INFO qdrant::actix: TLS disabled for REST API
INFO qdrant::tonic: Qdrant gRPC listening on 6334

Честное ограничение: в tar-архиве только исполняемый файл, статики дашборда там нет. API работает, а /dashboard отвечает 404 — это не поломка, а комплектация: веб-интерфейс докачивается отдельным архивом с той же страницы релиза и подключается через service.static_content_dir.

Способ 2: Docker Compose и ловушка с ufw

Контейнер удобнее версионированием, и дашборд уже внутри образа. Пакет docker.io из noble отстаёт от актуального Engine, поэтому подключаем официальный репозиторий — с кодовым именем noble, а не jammy:

. /etc/os-release && echo "$VERSION_CODENAME"   # должно быть noble
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
https://download.docker.com/linux/ubuntu noble stable" \
  | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update && sudo apt -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin
docker compose version

Команда именно docker compose, через пробел: Compose v1 из noble вырезан. Файл /opt/qdrant-docker/compose.yaml:

services:
  qdrant:
    image: qdrant/qdrant:v1.15.1
    container_name: qdrant
    restart: unless-stopped
    ports:
      - "127.0.0.1:6333:6333"
      - "127.0.0.1:6334:6334"
    environment:
      QDRANT__SERVICE__API_KEY: ${QDRANT_API_KEY}
      QDRANT__TELEMETRY_DISABLED: "true"
      QDRANT__LOG_LEVEL: INFO
    volumes:
      - /var/lib/qdrant/storage:/qdrant/storage
      - /var/lib/qdrant/snapshots:/qdrant/snapshots
    ulimits:
      nofile: 65536

Три решения здесь приняты намеренно.

  • Публикация на 127.0.0.1. Docker пишет правила DNAT в цепочку DOCKER таблицы nat, и она обрабатывается раньше ufw: sudo ufw deny 6333 не закроет порт, опубликованный как -p 6333:6333. Вы будете смотреть на ufw status с чувством выполненного долга, пока база отвечает всему интернету. Проверка — sudo iptables -t nat -L DOCKER -n.
  • Тег версии вместо latest. Формат хранилища мигрирует вперёд при старте новой версии, обратной миграции нет: с latest любой перезапуск может незаметно обновить движок, и вернуться на прежний тег уже не выйдет.
  • Монтирование в каталоги /var/lib/qdrant. Именованный том тоже работает, но docker compose down -v сносит его вместе с коллекциями.
cd /opt/qdrant-docker
printf 'QDRANT_API_KEY=%s\n' "$(openssl rand -hex 32)" > .env && chmod 600 .env
docker compose up -d && docker compose logs --tail=30 qdrant

Последний нюанс — права на тома. Стандартный образ работает от root; переключитесь на тег -unprivileged или user: "1000:1000" — каталог на хосте нужно отдать этому же UID, иначе контейнер падает с Permission denied (os error 13) при создании storage/collections.

Первая коллекция, API-ключ и клиент на Python 3.12

Проверяем, что сервис жив — корневой эндпоинт отдаёт версию, /healthz годится для мониторинга.

curl -s http://127.0.0.1:6333 | jq
# {"title":"qdrant - vector search engine","version":"1.15.1","commit":"a1b2c3d"}
curl -s http://127.0.0.1:6333/healthz

Теперь проверьте, что ключ включился: запрос без заголовка обязан получить 401 с телом {"status":{"error":"Must provide an API key or an Authorization bearer token"},"time":0.0}. Пришёл список коллекций — переменная не долетела до процесса; смотрите окружение PID, а не своей сессии: sudo tr '\0' '\n' < /proc/$(systemctl show -p MainPID --value qdrant)/environ | grep QDRANT.

Создаём коллекцию. Размерность берётся из модели эмбеддингов: 384 у all-MiniLM-L6-v2, 768 у bge-base, 1536 у text-embedding-3-small.

export QDRANT_API_KEY=$(sudo grep -oP '(?<=API_KEY=).*' /etc/qdrant/qdrant.env)
curl -s -X PUT http://127.0.0.1:6333/collections/docs \
  -H "api-key: $QDRANT_API_KEY" -H 'Content-Type: application/json' \
  -d '{"vectors":{"size":384,"distance":"Cosine"}}' | jq
# {"result":true,"status":"ok","time":0.02}

curl -s -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.05,0.11,0.02],"payload":{"url":"/faq"}}]}' | jq

Здесь ждёт самая частая ошибка старта — несовпадение размерности: коллекция создана под 384, а приложение считает эмбеддинги моделью OpenAI на 1536.

{"status":{"error":"Wrong input: Vector dimension error: expected dim: 384, got 1536"},"time":0.0}

Честно о последствиях: размерность существующей коллекции изменить нельзя. Никакого ALTER тут нет — коллекцию удаляют, создают заново с правильным size и переиндексируют весь корпус, поэтому модель эмбеддингов выбирают до первой загрузки. Второй по частоте ответ — 404 с текстом Not found: Collection 'docs' doesn't exist! (Qdrant обрамляет имя обратными кавычками).

Клиент на Python — место, где noble бьёт по рукам сильнее всего. Системный pip install qdrant-client завершается так:

error: externally-managed-environment

× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
    python3-xyz, where xyz is the package you want to install.

Это PEP 668, и на боевом сервере его не обходят флагом --break-system-packages: так ломаются системные утилиты Ubuntu на том же Python 3.12. Путь — виртуальное окружение, причём пакет python3-venv в noble отдельный.

sudo apt -y install python3-venv
python3 -m venv /opt/qdrant-client && source /opt/qdrant-client/bin/activate
pip install qdrant-client

Версию библиотеки держите рядом с версией сервера: при разрыве в лог падает «Qdrant client version is incompatible with server version». А включая prefer_grpc=True, убедитесь, что порт 6334 опубликован, — иначе вместо ошибки будет таймаут.

Домен, HTTPS, снапшоты и обновления

Qdrant слушает localhost, наружу его выводит nginx. И тут особенность 24.04: в noble лежит nginx 1.24.0, а директива http2 on; появилась только в 1.25.1 — свежий конфиг из интернета даст nginx: [emerg] unknown directive "http2". Пишется старый синтаксис:

server {
    listen 443 ssl http2;
    server_name qdrant.example.com;

    ssl_certificate     /etc/letsencrypt/live/qdrant.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/qdrant.example.com/privkey.pem;

    client_max_body_size 64m;
    proxy_read_timeout   300s;

    location / {
        proxy_pass http://127.0.0.1:6333;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

client_max_body_size поднят не случайно: батч из тысячи векторов по 768 измерений — это мегабайты JSON, и на дефолтном лимите в 1 МБ загрузка встанет с 413 Request Entity Too Large. Сертификат — обычным sudo certbot --nginx -d qdrant.example.com. gRPC через этот блок не проксируется: ему нужен отдельный слушатель с grpc_pass grpc://127.0.0.1:6334; и HTTP/2.

Бэкапы делаются снапшотами, а не копированием каталога на живой базе:

curl -s -X POST -H "api-key: $QDRANT_API_KEY" \
  http://127.0.0.1:6333/collections/docs/snapshots | jq
ls -lh /var/lib/qdrant/snapshots/docs/

Честное ограничение: снапшот не инкрементальный — каждый раз это полная копия коллекции, поэтому диск планируйте с двойным запасом и ставьте задачу в ночное окно через cron. Восстановление — загрузка файла на /collections/{name}/snapshots/upload, слепок всего хранилища — POST /snapshots.

Обновление одинаково для обоих способов: снять снапшот, остановить сервис, поменять версию, запустить, проверить /collections. Через минорные версии идите по порядку, а не прыгайте с 1.9 сразу на 1.15 — миграции формата рассчитаны на последовательное применение. И повторю про откат: его нет. На мониторинг повесьте /healthz и /metrics — метрики в формате Prometheus, включая число точек, сегментов и статус индексации; что делать, когда индексация не поспевает за загрузкой, разобрано в материале про частые ошибки Qdrant.

Какой сервер под Qdrant брать в MAATRIX

Сам движок скромен: пустой Qdrant занимает сотни мегабайт и почти не грузит процессор — считать нужно коллекцию. В документации есть прямая формула оценки памяти под векторы: количество векторов × размерность × 4 байта × 1,5, где множитель закрывает граф HNSW и служебные структуры.

КоллекцияМодель эмбеддинговПамять под векторыКонфигурация
100 тыс. × 384all-MiniLM-L6-v2~0,23 ГБ2 vCPU / 4 ГБ / 40 ГБ NVMe
1 млн × 384all-MiniLM-L6-v2~2,3 ГБ4 vCPU / 8 ГБ / 80 ГБ NVMe
1 млн × 768bge-base, e5-base~4,6 ГБ4 vCPU / 16 ГБ / 160 ГБ NVMe
5 млн × 1536text-embedding-3-small~46 ГБ8 vCPU / 64 ГБ или квантование

Это расчёт по формуле, а не замер: потребление зависит ещё от payload и доли сегментов на диске.

Честный минимум — 2 vCPU, 4 ГБ RAM, 40 ГБ NVMe. Хватает на базу знаний до сотен тысяч фрагментов с моделью на 384 измерения. На 1 vCPU и 1–2 ГБ Qdrant запустится, но первая же массовая загрузка с построением HNSW-индекса — самая прожорливая операция за всю жизнь базы — кончится процессом, снятым по OOM: в journalctl -k | grep -i oom будет Killed process ... (qdrant), а коллекция останется недоиндексированной.

Комфортный вариант — 4 vCPU, 8–16 ГБ RAM, 80–160 ГБ NVMe. Миллион векторов на 768 измерений, переиндексация без остановки поиска, место под рост. Диск считайте с коэффициентом 2,5–3 к объёму векторов: там же payload, журнал операций и копия коллекции в момент снапшота. Упираетесь в память — квантование int8 сжимает векторы вчетверо ценой небольшой потери точности, а hnsw_config.on_disk: true оставляет граф на диске; расчёт по моделям — отдельный разговор. GPU базе не нужен: он пригодится разве что при вычислении эмбеддингов, да и там не обязателен.

Локация — Лондон (UK). Qdrant почти никогда не стоит один: рядом модель эмбеддингов, тянущая веса с huggingface.co, и оркестрация RAG. С британской площадки всё это качается напрямую, до Европы пинг в десятки миллисекунд, плюс периметр GDPR. Завязан конвейер на OpenAI или Anthropic — логичнее США (Нью-Йорк); лежат персональные данные россиян — площадка в России закрывает 152-ФЗ.

Повторять всё руками не обязательно: Qdrant есть в каталоге приложений apps.maatrix.io. Он ставится автоматически при заказе сервера, работает на Ubuntu и Debian, а доступы — адрес и ключи — появляются в личном кабинете, в разделе «Доступ». Инструкция выше остаётся картой: вы знаете, где лежит хранилище, чем задан ключ и что чинить. Оплата — картами российских банков, по СБП, криптовалютой или токеном MAAT.

Развернуть за пару минут

Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть Qdrant

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Частые вопросы

Можно ли поставить Qdrant через apt install qdrant?

Нет: пакета в репозиториях 24.04 нет, apt-репозитория проект не публикует, .deb в релизах тоже отсутствует. Вариантов два — tar-архив с GitHub плюс свой systemd-юнит либо контейнер qdrant/qdrant.

/dashboard отдаёт 404, хотя API отвечает. Что сломалось?

Ничего: в tar-архиве релиза только исполняемый файл, статики веб-интерфейса нет. Докачайте архив с UI и укажите путь в service.static_content_dir — или берите Docker, там дашборд внутри образа.

Я закрыл 6333 через ufw, но Qdrant доступен снаружи. Почему?

Контейнер опубликован как -p 6333:6333, а правила Docker в таблице nat срабатывают раньше ufw. Смените публикацию на 127.0.0.1:6333:6333 и проверьте sudo iptables -t nat -L DOCKER -n.

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.