MAATRIX / Блог / Как установить и настроить AnythingLLM на VPS

Как установить и настроить AnythingLLM на VPS

Как установить и настроить AnythingLLM на VPS

MAATRIX

Развернуть AnythingLLM — это один docker run, и большинство руководств на этом заканчивается. Работа начинается дальше: свежая установка пускает внутрь без пароля, режет документы кусками по тысяче символов, отдаёт модели ровно четыре фрагмента и на половину вопросов отвечает, что информации не нашла. Ниже — установка AnythingLLM на VPS целиком: развёртывание, модель, эмбеддер и векторная база, настройка пространства, доступы, API и виджет.

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

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

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

Что вы разворачиваете и четыре решения до первой команды

AnythingLLM от Mintplex Labs — это RAG-оболочка, а не модель. Каждая настройка ниже живёт на одном из участков пути запроса: браузер стучится в Node-сервер на порту 3001, тот превращает вопрос в вектор через эмбеддер, ищет фрагменты в векторной базе и отправляет найденное вместе с историей чата и системным промптом языковой модели. Файлы разбирает коллектор на порту 8888, состояние лежит в /app/server/storage, актуальная ветка образа — 1.16.x. Отсюда четыре решения, которые лучше принять до загрузки первой сотни документов.

РешениеЗначение по умолчаниюЧего стоит смена потом
Чем считается ответ (LLM)спросит при первом входеПереключается свободно
Чем считаются эмбеддингивстроенный native, 384 измеренияПереиндексация всей библиотеки
Где лежат векторыLanceDB внутри storage/Перенос коллекций или та же переиндексация
Кто имеет доступодин пользователь, пароля нетВключается в одну сторону

Первое дешёвое: провайдера меняют хоть каждый день. Второе и третье дорогие — векторы одного эмбеддера несовместимы с другим. Четвёртое разработчики описывают как одностороннее: включив мультиюзер, назад без правки базы не вернуться. И учтите: мультиюзер, ключи API и виджет есть только в серверном образе.

До заказа проверьте требование к железу: процессор обязан поддерживать AVX2, иначе контейнер падает с Illegal instruction (core dumped) на первом обращении к LanceDB — lscpu | grep -o -m1 avx2, разбор в установке на Ubuntu 24.04.

Развёртывание: compose-файл, к которому не придётся возвращаться

Разложите конфигурацию на два файла: compose.yaml и anythingllm.env с секретами (openssl rand -hex 32 три раза, значения разные).

mkdir -p /opt/anythingllm/storage && touch /opt/anythingllm/anythingllm.env
chown -R 1000:1000 /opt/anythingllm && chmod 600 /opt/anythingllm/anythingllm.env
cat > /opt/anythingllm/anythingllm.env <<'EOF'
JWT_SECRET=<первый вывод, не короче 12 символов>
SIG_KEY=<второй вывод, не короче 32 символов>
SIG_SALT=<третий вывод, не короче 32 символов>
DISABLE_TELEMETRY=true
EOF

В compose.yaml важны четыре вещи, которых нет в однострочнике из документации: фиксированный тег, ротация логов, потолок по памяти и проверка живости.

services:
  anythingllm:
    image: mintplexlabs/anythingllm:1.16.1
    container_name: anythingllm
    restart: unless-stopped
    user: "1000:1000"
    cap_add: [SYS_ADMIN]
    ports:
      - "127.0.0.1:3001:3001"
    env_file: ./anythingllm.env
    environment:
      - SERVER_PORT=3001
      - STORAGE_DIR=/app/server/storage
    volumes:
      - ./storage:/app/server/storage
    extra_hosts:
      - "host.docker.internal:host-gateway"
    mem_limit: 6g
    healthcheck:
      test: ["CMD", "curl", "-fs", "http://127.0.0.1:3001/api/ping"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 60s
    logging:
      driver: json-file
      options: { max-size: "50m", max-file: "3" }

Тег 1.16.1 вместо latest — образ пересобирается из master почти ежедневно, а миграции схемы Prisma выполняются при старте и назад не откатываются: однажды docker compose pull принесёт базу, которую прежняя версия не откроет. mem_limit — предохранитель: без него всплеск при индексации крупного PDF убивает не контейнер, а что-нибудь ещё на хосте. Блок logging нужен потому, что json-лог Docker не ротирует вообще, а cap_add: SYS_ADMIN требуется headless-Chromium в коллекторе.

Чего в environment: нет — ни LLM_PROVIDER, ни EMBEDDING_ENGINE, ни ключей провайдеров. Переменные из compose попадают в процесс раньше, чем читается storage/.env, куда пишет веб-интерфейс, и при конфликте выигрывают они: вы меняете модель в UI, а после перезапуска возвращается прежняя.

cd /opt/anythingllm && docker compose up -d
docker compose ps --format 'table {{.Name}}\t{{.Status}}'
curl -s http://127.0.0.1:3001/api/ping
{"online":true}

В статусе должно появиться Up 2 minutes (healthy). Порт наружу не публикуем намеренно: до включения мультиюзера интерфейс не спрашивает пароль, а в настройках лежат ваши ключи от OpenAI. Наружу — только Nginx с TLS на отдельном поддомене, его директивы разобраны в статье про частые ошибки AnythingLLM.

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

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

Развернуть AnythingLLM

Подключение модели: базовый URL, имя и окно контекста

При первом входе мастер предложит выбрать провайдера; три сценария покрывают почти всё.

Внешний API — OpenAI, Anthropic, Groq, Mistral: вставляете ключ, выбираете модель. Но исходящий адрес сервера должен быть вне ограниченных регионов, иначе придёт 403 unsupported_country_region_territory, и верный ключ тут не поможет.

Локальный движок. Ollama на том же сервере подключается по адресу http://host.docker.internal:11434 — не 127.0.0.1, который внутри контейнера указывает на сам контейнер. Имя модели должно совпадать с выводом ollama list с тегом.

OpenAI-совместимый эндпоинт — LiteLLM, vLLM, LocalAI, OpenRouter, любой собственный шлюз. Самая частая ошибка здесь — базовый путь без суффикса /v1: AnythingLLM дописывает к нему /chat/completions, шлюз получает запрос не на тот адрес, и в чате появляется плашка Could not respond to message с 404 внутри.

LLM_PROVIDER=generic-openai
GENERIC_OPEN_AI_BASE_PATH=http://host.docker.internal:4000/v1
GENERIC_OPEN_AI_MODEL_PREF=gpt-4o-mini
GENERIC_OPEN_AI_MODEL_TOKEN_LIMIT=128000
GENERIC_OPEN_AI_API_KEY=sk-...
GENERIC_OPEN_AI_MAX_TOKENS=4096

Отдельного разговора заслуживает MODEL_TOKEN_LIMIT — поле «размер окна контекста» в интерфейсе. AnythingLLM не спрашивает модель, сколько она вмещает: он верит числу из настроек и по нему решает, сколько фрагментов и истории поместится в запрос. Занизите — модель получит один-два фрагмента вместо шести и станет отвечать «нет информации» на вопросы, ответ на которые в базе есть. Завысите — провайдер вернёт ошибку о превышении длины контекста, а локальная модель молча обрежет запрос с начала, вместе с системным промптом. Для локальных сборок ставьте окно, с которым модель запущена: у Ollama это num_ctx. И повторных попыток AnythingLLM не делает — одна сетевая ошибка равна одному потерянному сообщению.

Эмбеддер и векторная база: где решается качество ответов

Эмбеддер превращает текст в числа, и от его выбора зависит, найдёт ли поиск нужный абзац.

ЭмбеддерРазмерностьГде считаетсяОсобенности
native (Xenova/all-MiniLM-L6-v2)384на CPU сервераокно 256 токенов, ничего не уходит наружу
Ollama + nomic-embed-text768на вашем сервереокно 8192 токена, нужен Ollama
OpenAI text-embedding-3-small1536у провайдераплатно, текст уходит наружу
OpenAI text-embedding-3-large3072у провайдерадороже, векторы тяжелее

Ограничение встроенного native редко проговаривают: у all-MiniLM-L6-v2 окно всего 256 токенов, и текст длиннее модель молча обрезает. Фрагмент в 1000 символов русского текста — примерно 300–400 токенов, то есть часть каждого чанка в вектор не попадает; отсюда жалоба «ищет по началу и не видит середину».

Векторная база по умолчанию — LanceDB: встроенная, живёт файлами в storage/lancedb/, и для одной команды её достаточно. Внешнюю ставят, когда векторы нужны не только AnythingLLM.

VECTOR_DB=qdrant
QDRANT_ENDPOINT=http://host.docker.internal:6333
QDRANT_API_KEY=

Qdrant слушает 6333 по HTTP и 6334 по gRPC; наружу их публиковать нельзя — ключа у него по умолчанию нет, и открытый порт означает открытую базу знаний. Что выбрать — в статье про векторную базу для RAG.

Главное правило: смена эмбеддера или базы требует переиндексации. Векторы на 384 и на 1536 измерений несовместимы, старая коллекция либо отдаёт ошибку размерности, либо молча выдаёт мусор. Порядок: сменить эмбеддер, очистить storage/vector-cache/ (иначе кэш подставит старые векторы), удалить документы и загрузить снова.

Рабочее пространство: чанки, порог схожести и режим ответа

Модель отвечает — начинается настройка, ради которой всё затевалось. Общие параметры лежат в «Text Splitter & Chunking», остальные — в настройках пространства.

Размер чанка и перекрытие — по умолчанию 1000 и 20 символов. Для регламентов, инструкций и договоров 700–1000 символов при перекрытии 100–150 работают лучше дефолта: перекрытие спасает предложения, разрезанные пополам. Жёсткая граница — окно эмбеддера.

Максимум фрагментов в контексте (Max Context Snippets), по умолчанию 4 — сколько кусков поиск отдаст модели. Четыре мало для вопросов вида «собери все упоминания», 6–10 дают более полные ответы. Но десять фрагментов по 1000 символов — около 3000 токенов, и на окне 8k места уже не остаётся.

Порог схожести документов (Document Similarity Threshold) — четыре значения: без ограничения, низкий (0.25), средний (0.50), высокий (0.75). Это отсечка по косинусной близости, и ловушка в том, что абсолютные значения score зависят от эмбеддера: «средний» порог с одной моделью отсекает мусор, а с другой — всё. Симптом узнаваем: модель на каждый второй вопрос выдаёт дословную фразу из настроек — There is no relevant information in this workspace to answer your query.

Режим чата: Chat или Query. В Query модель отвечает только по найденным фрагментам, иначе выдаёт ту самую фразу отказа. В Chat — и без контекста, из собственных знаний. Для корпоративной базы почти всегда нужен Query: он превращает уверенную выдумку в честное «не нашёл».

История чата, по умолчанию 20 сообщений, съедает окно контекста наравне с документами: ответы стали обрываться — начните с этого числа. Закрепление документа (pin) — отдельный механизм: файл целиком уходит в каждый запрос, минуя поиск; для регламента на пару страниц идеальный ход, для стостраничного PDF — превышение контекста. И системный промпт: там задаётся язык ответов — русскоязычная база без явного указания регулярно отвечает по-английски.

Доступ, API и виджет на сайте

Свежая установка — открытая дверь: кто дошёл до порта, тот администратор, и закрывать её нужно до появления приложения на домене. В одиночку хватит переменной AUTH_TOKEN: единый пароль на вход, без ролей.

Многопользовательский режим включается переключателем в разделе «Security» и создаёт первого администратора. Появляются три роли: admin (всё, включая системные настройки и ключи), manager (пространства и пользователи) и default (назначенные пространства). Требования к паролям — переменными:

PASSWORDMINCHAR=10
PASSWORDUPPERCASE=1
PASSWORDNUMERIC=1
PASSWORDSYMBOL=1

Разработческий API. В админке заводится ключ, после чего доступны эндпоинты под /api/v1/, а документация — по адресу /api/docs.

curl -s -H "Authorization: Bearer $ANYTHINGLLM_KEY" \
     https://llm.example.com/api/v1/auth
{"authenticated":true}

curl -s -X POST https://llm.example.com/api/v1/workspace/baza-znanij/chat \
     -H "Authorization: Bearer $ANYTHINGLLM_KEY" \
     -H "Content-Type: application/json" \
     -d '{"message":"Каков срок гарантии по договору?","mode":"query"}'

Ответ приходит JSON-объектом с полями textResponse и sources — во втором лежат найденные фрагменты с именами файлов, и это лучший инструмент отладки RAG: видно, что поиск подал модели. Ограничение назвать надо прямо: областей действия у ключа нет, это полные права администратора.

Виджет для сайта. В разделе встраиваемых чатов создаётся эмбед, привязанный к пространству, и выдаётся готовый тег:

<script
  data-embed-id="8f5c0a2e-4f2b-4e7d-9a1c-3d2b1a0f9e8d"
  data-base-api-url="https://llm.example.com/api/embed"
  data-greeting="Спросите про наши услуги"
  src="https://llm.example.com/embed/anythingllm-chat-widget.min.js">
</script>

Перед публикацией заполните белый список доменов и лимиты — число чатов в сутки и на сессию. Виджет обращается к серверу без авторизации: без ограничений это открытый доступ к вашей квоте у провайдера. И режим почти всегда Query: публичный чат из общих знаний модели однажды скажет от лица компании лишнее.

И про агентов: режим @agent умеет искать в интернете, но нужен ключ поискового провайдера — AGENT_SERPER_DEV_KEY, AGENT_SERPAPI_API_KEY или пара AGENT_GSE_KEY/AGENT_GSE_CTX. Без него агент стартует, а веб-поиск молчит.

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

Требования делятся по одной границе: считается ли модель на этом же сервере.

Честный минимум: 2 vCPU, 4 ГБ RAM, 40 ГБ NVMe — AnythingLLM как интерфейс к внешнему API или шлюзу. Документация называет минимумом 2 ГБ, но это граница запуска, а не работы: сервер, коллектор с Chromium и эмбеддер живут в одном контейнере, и на первой партии PDF двух гигабайт не хватает — docker inspect anythingllm --format '{{.State.OOMKilled}}' вернёт true. Диск с запасом: документ хранится трижды — в documents/, vector-cache/ и lancedb/.

Комфортный вариант: 4 vCPU, 8 ГБ RAM, 80–120 ГБ NVMe. Разница видна в индексации: разбор PDF и расчёт эмбеддингов — процессорная работа, и она распараллеливается. Восьми гигабайт хватает на несколько пространств, десяток пользователей и внешнюю векторную базу рядом. Локальная модель прибавляет веса: 7–8 миллиардов параметров в Q4 — 4,5–5 ГБ плюс KV-кэш, отсюда 8 vCPU и 16 ГБ для связки с Ollama. И это про работоспособность, а не про скорость: на процессоре генерация идёт темпом медленно печатающего человека, за быстрыми ответами — на GPU-сервер.

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

Разворачивать руками не обязательно: AnythingLLM есть в каталоге apps.maatrix.io и ставится автоматически при заказе сервера, на Ubuntu и на Debian, а доступы — адрес панели и ключи — появляются в личном кабинете, в разделе «Доступ». Остаётся войти, включить мультиюзер, подключить провайдера и загрузить документы. Процессоры — AMD EPYC, проблема с AVX2 здесь не воспроизводится; оплата — картой российского банка, по СБП, криптой или токеном MAAT.

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

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

Развернуть AnythingLLM

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

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

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

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

Настроил всё в интерфейсе, а после перезапуска настройки откатились. Почему?

Переменные из environment: попадают в процесс раньше, чем читается storage/.env, куда пишет веб-интерфейс, и при конфликте выигрывают они. Сравните docker exec anythingllm env | grep -E 'LLM_PROVIDER|EMBEDDING|VECTOR_DB' и docker exec anythingllm cat /app/server/storage/.env, затем уберите из compose всё, кроме SERVER_PORT, STORAGE_DIR и секретов.

Модель отвечает, что в пространстве нет информации, хотя документ загружен. Что крутить?

По порядку: снимите порог схожести до «без ограничения»; поднимите максимум фрагментов с 4 до 8; проверьте окно контекста в настройках провайдера. Не помогло — смотрите поле sources в ответе /api/v1/workspace/{slug}/chat: там видно, что поиск реально нашёл.

Можно ли поставить виджет на публичный сайт без риска?

Только с ограничениями: белый список доменов, лимит чатов в сутки и на сессию, режим Query. Виджет ходит к серверу без авторизации, и без лимитов ваша квота у провайдера расходуется кем угодно.

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

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