Как установить и настроить AnythingLLM на VPS
Развернуть AnythingLLM — это один docker run, и большинство руководств на этом заканчивается. Работа начинается дальше: свежая установка пускает внутрь без пароля, режет документы кусками по тысяче символов, отдаёт модели ровно четыре фрагмента и на половину вопросов отвечает, что информации не нашла. Ниже — установка AnythingLLM на VPS целиком: развёртывание, модель, эмбеддер и векторная база, настройка пространства, доступы, API и виджет.
Содержание
- Что вы разворачиваете и четыре решения до первой команды
- Развёртывание: compose-файл, к которому не придётся возвращаться
- Подключение модели: базовый URL, имя и окно контекста
- Эмбеддер и векторная база: где решается качество ответов
- Рабочее пространство: чанки, порог схожести и режим ответа
- Доступ, API и виджет на сайте
- Какой сервер под AnythingLLM брать в MAATRIX
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество 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-text | 768 | на вашем сервере | окно 8192 токена, нужен Ollama |
OpenAI text-embedding-3-small | 1536 | у провайдера | платно, текст уходит наружу |
OpenAI text-embedding-3-large | 3072 | у провайдера | дороже, векторы тяжелее |
Ограничение встроенного 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 — десятки моделей в одном окне. Оплата картой РФ и по СБП.