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

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

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

MAATRIX

Официальная команда запуска AnythingLLM помещается в один экран — и именно поэтому на Ubuntu 24.04 она так часто кончается контейнером, который молча исчезает, каталогом .env вместо файла и отказом включить мультиюзер. Ниже — путь от чистой noble до рабочего RAG-чата на домене под HTTPS: что проверить до установки и где в 24.04 лежат грабли, которых нет в мануалах под 22.04.

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

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

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

Что вы разворачиваете и из чего это состоит

AnythingLLM от Mintplex Labs — оболочка для работы с документами: рабочие пространства, нарезка файлов на чанки, эмбеддинги, поиск по векторной базе и чат поверх найденного. Главное усвоить до установки: модели он не считает. Инференса внутри нет — вы подключаете внешний API (любой OpenAI-совместимый эндпоинт) либо локальный движок вроде Ollama на той же машине. От этого зависит вся арифметика по железу.

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

Что получится в итоге:

  • Ubuntu 24.04 LTS (noble), ядро 6.8, Docker Engine с плагином docker compose v2;
  • образ mintplexlabs/anythingllm, порт 3001, SQLite-файл anythingllm.db и встроенная векторная база LanceDB;
  • эмбеддер all-MiniLM-L6-v2 в формате ONNX, 384 измерения, считается на процессоре;
  • Nginx 1.24 из репозитория Ubuntu и Let's Encrypt.

Три проверки на noble, которые экономят вечер

Официальные требования скромные — 2 ГБ памяти, два ядра, 5 ГБ диска, — но в них зарыто жёсткое условие к железу: процессор обязан поддерживать AVX2. Без него контейнер падает не при старте, а на первом обращении к векторной базе.

lscpu | grep -o -m1 avx2 || echo "AVX2 НЕТ — AnythingLLM работать не будет"

Если проверка молчит, в docker compose logs будет ровно эта строка, а в браузере — оборванное соединение:

/usr/local/bin/docker-entrypoint.sh: line 7: 115 Illegal instruction (core dumped) node /app/server/index.js

Ловится это чаще не на старом железе, а на виртуалках: QEMU и Proxmox с типом CPU kvm64 вместо host флаги AVX2 внутрь не пробрасывают.

Вторая проверка — память. Заявленные 2 ГБ — граница выживания: Node-сервер, парсер документов и эмбеддер живут в одном контейнере, а на индексации крупного PDF потребление скачет. Без swap ядро молча убьёт процесс, оставив след только в journalctl -k: kernel: Out of memory: Killed process 2417 (node).

fallocate -l 4G /swapfile && chmod 600 /swapfile
mkswap /swapfile && swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab

Оговорка честная: swap спасает от убийства процесса, но не от тормозов — уехавший в подкачку расчёт эмбеддингов растянет индексацию.

Третья проверка специфична для 24.04: в noble включено ограничение AppArmor на непривилегированные user namespace.

sysctl kernel.apparmor_restrict_unprivileged_userns
kernel.apparmor_restrict_unprivileged_userns = 1

Единица — штатное состояние, менять её не нужно, но флаг держите в голове: коллектор AnythingLLM для сбора страниц по ссылке запускает headless-Chromium, которому нужны namespace для песочницы. Поэтому в официальном запуске стоит --cap-add SYS_ADMIN — без него сбор ссылок отваливается с No usable sandbox!, а обычные файлы грузятся как ни в чём не бывало. Симптом контринтуитивный: «PDF индексируются, а сайты нет» — разбор в статье про то, почему AnythingLLM не индексирует документы.

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

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

Развернуть AnythingLLM

Docker Engine: репозиторий для noble, а не пакет docker.io

Соблазн обойтись строкой apt install docker.io велик, но сначала посмотрите apt-cache policy docker.io: в noble лежит ветка 24.0.x и, главное, без плагина docker compose — вместо него приедет старый питоновский docker-compose, не понимающий половину современного синтаксиса.

apt update && apt install -y ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
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" > /etc/apt/sources.list.d/docker.list
apt update && apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Слово noble в строке репозитория принципиально: в руководствах под 22.04 там стоит jammy, и apt update ответит жалобой на отсутствующий Release-файл. Результат проверяют docker --version и docker compose version: если вторая пишет docker: 'compose' is not a docker command, у вас установился docker.io.

Фаервол пускает внутрь только SSH и веб — ufw allow 22/tcp && ufw allow 80,443/tcp && ufw enable, — и вот ловушка, которая эту строку обесценивает. Docker публикует порты правилами в цепочке DOCKER таблицы nat, и они срабатывают раньше ufw: публикация вида -p 3001:3001 выставит приложение в интернет, даже если ufw status отвечает Status: active. Цена ошибки высокая: до включения мультиюзера интерфейс не спрашивает пароль, а в настройках лежат ключи от OpenAI. Поэтому публикуем порт только на 127.0.0.1:3001:3001.

Каталоги, .env и права UID 1000

Контейнер работает от пользователя с UID и GID 1000, и всё смонтированное снаружи должно принадлежать этому UID — иначе получите жалобу «your storage folder is not writable by the container».

mkdir -p /opt/anythingllm/storage
touch /opt/anythingllm/.env
chown -R 1000:1000 /opt/anythingllm

Строка с touch — не формальность: если указанного в монтировании файла на хосте нет, Docker создаст на его месте каталог с тем же именем. Приложение стартует и выглядит живым, но любая сохраняемая настройка проваливается — заметнее всего в отказе включить мультиюзер:

Failed to enable Multi-User mode: Unexpected token 'I', "Internal S" is not valid JSON

Сервер вернул Internal Server Error там, где фронтенд ждал JSON; причина видна в логах строкой EACCES: permission denied, open '/app/server/.env' и лечится тем же chown. Теперь /opt/anythingllm/compose.yaml — секреты сгенерируйте заранее, openssl rand -hex 32 три раза:

services:
  anythingllm:
    image: mintplexlabs/anythingllm:latest
    container_name: anythingllm
    restart: unless-stopped
    user: "1000:1000"
    cap_add:
      - SYS_ADMIN
    ports:
      - "127.0.0.1:3001:3001"
    environment:
      - SERVER_PORT=3001
      - STORAGE_DIR=/app/server/storage
      - DISABLE_TELEMETRY=true
      - JWT_SECRET=первый_вывод_openssl
      - SIG_KEY=второй_вывод_openssl
      - SIG_SALT=третий_вывод_openssl
    volumes:
      - ./storage:/app/server/storage
      - ./.env:/app/server/.env
    extra_hosts:
      - "host.docker.internal:host-gateway"

cap_add: SYS_ADMIN — капабилити для Chromium в коллекторе; не нужен сбор страниц по ссылкам — уберите её. extra_hosts даёт имя host.docker.internal, через которое из контейнера виден хост: на Linux такого имени нет. SIG_KEY и SIG_SALT задайте сразу — на них завязана подпись.

Тег latest пересобирается почти ежедневно и однажды принесёт мигрировавшую базу без предупреждения. Зафиксируйте версию после первого удачного запуска:

docker image inspect --format '{{index .RepoDigests 0}}' mintplexlabs/anythingllm
mintplexlabs/anythingllm@sha256:9f2c...

Строку целиком поставьте в image вместо :latest. И помните: .env — не файл, который заполняют один раз. AnythingLLM пишет в него настройки из веб-интерфейса, это живое состояние приложения: правьте руками только на остановленном контейнере и кладите в бэкап вместе со storage.

Первый запуск: онбординг, провайдер и мультиюзер

cd /opt/anythingllm && docker compose up -d
docker compose ps
NAME          IMAGE                      STATUS
anythingllm   mintplexlabs/anythingllm   Up 40 seconds (healthy)
curl -s http://127.0.0.1:3001/api/ping
{"online":true}
ss -tulpn | grep 3001
tcp LISTEN 0 4096 127.0.0.1:3001 0.0.0.0:* users:(("docker-proxy",pid=2318,fd=7))

Статус (healthy) значит, что встроенная проверка достучалась до сервера, а /api/ping не требует авторизации и годится для мониторинга. Главное — в выводе ss стоит 127.0.0.1:3001, а не 0.0.0.0:3001: второе означает потерянный префикс в ports, то есть приложение в интернете без пароля.

Наружу порт мы не открывали, поэтому ходите через туннель ssh -L 3001:127.0.0.1:3001 user@ваш-сервер и открывайте http://localhost:3001. Мастер спросит провайдера LLM, эмбеддер, векторную базу и имя рабочего пространства; для сервера разумны встроенный эмбеддер (native) и LanceDB. Сменить эмбеддер потом можно, но документы придётся переиндексировать: размерности векторов у моделей разные.

Если модель крутится локально, здесь ждёт частая ошибка: адрес http://localhost:11434 из контейнера не работает никогда, потому что localhost для контейнера — это он сам. Рабочие варианты — http://172.17.0.1:11434 (шлюз docker0, адрес покажет ip -4 addr show docker0) или http://host.docker.internal:11434 из extra_hosts. Проверка: docker compose exec anythingllm curl -s http://host.docker.internal:11434/api/tags.

При встроенном эмбеддере первая индексация дольше последующих: приложение сначала скачивает ONNX-модель в storage/models/. Отсюда сценарий для серверов с урезанным исходящим доступом: если huggingface.co недоступен, загрузка документа зависает без сообщения. Проверьте заранее — getent hosts huggingface.co.

Последний шаг, который нельзя откладывать, — мультипользовательский режим. По умолчанию AnythingLLM однопользовательский: пароля нет, любой дотянувшийся до порта получает доступ к настройкам, документам и ключам провайдеров. Включается он в разделе «Security», там же задаются логин и пароль администратора. Переключение разработчики описывают как одностороннее, и делать его надо до выхода на домен: порядок «сначала certbot, потом безопасность» кончается чужим браузером в вашем интерфейсе.

Домен, HTTPS и обслуживание

Заведите A-запись, дождитесь, пока dig +short llm.example.com вернёт адрес сервера, затем apt install -y nginx certbot python3-certbot-nginx. Здесь третья ловушка noble: в 24.04 лежит nginx/1.24.0, а директива http2 on; появилась только в 1.25.1 — свежие мануалы её используют, и конфиг не проходит проверку:

nginx: [emerg] unknown directive "http2" in /etc/nginx/sites-enabled/anythingllm:3

На 1.24 пишите по-старому — listen 443 ssl http2;. Файл /etc/nginx/sites-available/anythingllm:

server {
    listen 443 ssl http2;
    server_name llm.example.com;
    client_max_body_size 512m;

    location ~* ^/api/agent-invocation/(.*) {
        proxy_pass http://127.0.0.1:3001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
    }

    location / {
        proxy_pass http://127.0.0.1:3001;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 605s;
        proxy_buffering off;
    }
}

Отдельный блок для /api/agent-invocation/ — не украшение. Агенты общаются с браузером по WebSocket, и без заголовков Upgrade и Connection они молча не запускаются: чат отвечает, документы ищутся, а @agent не делает ничего. proxy_buffering off включает потоковую выдачу, иначе прокси накопит весь ответ и вывалит одним куском. А client_max_body_size 512m спасает загрузку документов: с дефолтным лимитом в мегабайт пользователь получает 413, а вы — строку client intended to send too large body в логе Nginx.

ln -s /etc/nginx/sites-available/anythingllm /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx && certbot --nginx -d llm.example.com

Certbot сам допишет редирект с 80-го порта и поставит таймер продления (systemctl list-timers | grep certbot). Дальше обслуживание. Обновление: поменяйте digest, затем docker compose pull && docker compose up -d && docker image prune -f; перед сменой минорной версии загляните в changelog — миграции базы назад не откатываются. Бэкап: одна команда на остановленном контейнере:

docker compose down
tar czf /root/anythingllm-$(date +%F).tar.gz -C /opt/anythingllm storage .env
docker compose up -d

Внутри storage лежат anythingllm.db (пользователи, настройки, переписка), documents/ с распарсенным текстом, vector-cache/, lancedb/ и models/ со скачанными моделями. Документ хранится фактически трижды, поэтому каталог растёт быстрее, чем подсказывает интуиция: смотрите du -sh /opt/anythingllm/storage/* раз в месяц. Что ломается дальше — в статье про частые ошибки AnythingLLM на сервере.

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

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

СценарийvCPURAMДиск
Интерфейс к внешнему API24 ГБ40 ГБ NVMe
Команда, много документов48 ГБ80 ГБ NVMe
Вместе с локальной моделью 7–8B816 ГБ160 ГБ NVMe

Честный минимум — 2 vCPU, 4 ГБ, 40 ГБ NVMe. Документация называет 2 ГБ, но это граница выживания: в контейнере работают Node-сервер, парсер документов и эмбеддер. Диск складывается из образа, моделей и документов в трёх копиях.

Комфортный вариант — 4 vCPU, 8 ГБ, 80 ГБ NVMe. Разница ощущается не в чате, а в индексации: разбор PDF на сотни страниц и расчёт эмбеддингов — процессорная работа.

Если модель локальная, прибавляются веса. Модель на 7–8 миллиардов параметров в квантовании Q4 — около 4,5–5 ГБ только весов, плюс контекст и расходы движка. Отсюда третья строка таблицы, и это разговор о работоспособности, а не о скорости: генерация на процессоре идёт темпом медленно печатающего человека. Расчёт по моделям — в материале про то, сколько RAM нужно для AnythingLLM.

Про процессор: серверы MAATRIX построены на AMD EPYC, AVX2 там есть, и проблема с Illegal instruction из второй секции на них не воспроизводится.

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

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

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

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

Развернуть AnythingLLM

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

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

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

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

Можно ли поставить AnythingLLM без Docker, прямо на Ubuntu 24.04?

Технически да, но разработчики называют bare-metal путём для разработки, а не для эксплуатации: собирать нужно три части — сервер, коллектор и фронтенд, — следить за версией Node (в noble это 18.19) и повторять всё при обновлениях.

Контейнер стартует, а на первом документе исчезает без ошибки в интерфейсе. Что смотреть?

Сначала docker compose logs --tail=50 anythingllm. Строка Illegal instruction (core dumped) — это отсутствие AVX2, лечится сменой сервера или внешней векторной базой. EACCES или жалоба на права записи в storage — каталог принадлежит не UID 1000: chown -R 1000:1000 /opt/anythingllm. Пустой лог при исчезнувшем контейнере — почти всегда OOM, подтверждение в journalctl -k.

Что перенести на новый сервер, чтобы ничего не потерять?

Каталог storage целиком и файл .env: в anythingllm.db лежат пользователи и переписка, в lancedb — векторы, в documents — тексты. Разворачивайте тот же образ, что был на старой машине, и только потом обновляйтесь — миграции базы идут в одну сторону.

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

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