Как установить и настроить LibreChat на VPS
LibreChat поднимается одной командой docker compose up -d — и ровно поэтому половина установок уезжает в интернет с открытым портом 3080, dev-образом вместо релиза и конфигом, который сервис ни разу не прочитал. Разберём установку LibreChat на VPS до состояния, которое не стыдно отдать команде: секреты, домен, HTTPS, модели и бэкап — с командами, версиями и местами, где эта конструкция ломается.
Содержание
- Что вы разворачиваете: шесть контейнеров, а не один
- Требования к серверу и подготовка Ubuntu
- Установка LibreChat: клон, секреты, первый старт
- Ключи и модели: .env, librechat.yaml и локальная Ollama
- Домен, HTTPS и стриминг: Nginx и переменные окружения
- Пользователи, обновление и бэкап
- Какой сервер взять в MAATRIX под LibreChat
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что вы разворачиваете: шесть контейнеров, а не один
LibreChat — веб-интерфейс чата на Node.js, который сам не считает ни одного токена. Он ходит в OpenAI, Anthropic, Google, в любой OpenAI-совместимый шлюз и в локальную Ollama, а взамен даёт аккаунты, историю в базе, поиск по ней, работу с файлами и разделение прав. Отсюда первое: «поставил LibreChat, а он тормозит» значит, что тормозит модель или канал до API.
Второе — приложение не одноконтейнерное. Штатный docker-compose.yml из репозитория поднимает шесть сервисов:
| Сервис | Контейнер | Образ | Роль |
|---|---|---|---|
api | LibreChat | registry.librechat.ai/danny-avila/librechat-dev:latest | сам сервис, порт 3080 |
mongodb | chat-mongodb | mongo:8.0.20 | пользователи, диалоги, пресеты |
meilisearch | chat-meilisearch | getmeili/meilisearch:v1.35.1 | поиск по истории |
vectordb | vectordb | pgvector/pgvector:0.8.0-pg15-trixie | векторы для файлов |
rag_api | rag_api | librechat-rag-api-dev-lite:latest | извлечение текста и эмбеддинги |
admin-panel | admin-panel | librechat-admin-panel:latest | админ-панель, порт 3000 |
Практических следствий три. api объявлен с depends_on: mongodb, rag_api — «только чат без RAG» из коробки не запустить. Образы тянутся не с Docker Hub, а из реестра registry.librechat.ai — проверьте доступность до клонирования: docker pull registry.librechat.ai/danny-avila/librechat:latest. Штатный тег — librechat-dev:latest, образ из ветки разработки; для боя его меняют.
Ориентиры по версиям: последний нумерованный релиз — v0.8.7, в main лежит v0.8.8-rc1, версия формата конфига в librechat.example.yaml — 1.3.14. Расхождение по ней LibreChat отмечает в логе предупреждением и часть новых полей игнорирует.
Требования к серверу и подготовка Ubuntu
Берите Ubuntu 24.04 LTS или Debian 12. Docker ставьте официальным скриптом, а не из репозитория дистрибутива: в пакете docker.io нет плагина compose, и docker compose version ответит docker: 'compose' is not a docker command.
curl -fsSL https://get.docker.com | sudo sh
sudo systemctl enable --now docker && docker compose version
sudo ufw allow 22/tcp && sudo ufw allow 80/tcp && sudo ufw allow 443/tcp
sudo ufw enable
Память. Считать надо по всему стеку. В нашем замере на VPS 2 vCPU / 4 ГБ (Ubuntu 24.04, Docker 27, Лондон) docker stats --no-stream в простое показывал около 198 МБ у контейнера LibreChat и 241 МБ у chat-mongodb; сверху — Meilisearch, rag_api с моделью эмбеддингов, Postgres 15 в vectordb и админ-панель. 4 ГБ — рабочий минимум для полного стека.
AVX. Образ mongo:8.0.20 требует инструкций AVX. На старых Xeon и при урезанных флагах в KVM контейнер chat-mongodb падает сразу, оставив в docker compose logs mongodb:
WARNING: MongoDB 5.0+ requires a CPU with AVX support, and your current system does not appear to have that!
see https://jira.mongodb.org/browse/SERVER-54407
Проверяется до заказа: grep -o ' avx ' /proc/cpuinfo | head -1. Пусто — MongoDB 8 здесь не поедет, и лечится это только сменой сервера.
Диск. Шесть образов, база Mongo, индекс Meilisearch, том pgvector, каталоги ./uploads, ./images и ./logs. Плюс в .env.example стоит DEBUG_LOGGING=true, логи растут быстрее ожидаемого. Минимум — 40 ГБ NVMe, комфорт — 60–80 ГБ.
UID и GID. В compose три сервиса объявлены как user: "${UID}:${GID}", а в .env.example обе переменные закомментированы (# UID=1000, # GID=1000). Оставите так — получите WARN[0000] The "UID" variable is not set. Defaulting to a blank string., каталоги ./data-node, ./logs и ./uploads создаст демон Docker от root, и процесс в контейнере упадёт на EACCES: permission denied.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверУстановка LibreChat: клон, секреты, первый старт
Клонируем репозиторий и готовим окружение с конфигом:
sudo apt install -y git
git clone https://github.com/danny-avila/LibreChat.git
cd LibreChat
cp .env.example .env
cp librechat.example.yaml librechat.yaml
Сразу проверьте ls -la .env: строка с d в начале значит, что вы уже запускали docker compose up без .env и Docker создал каталог на месте бинда ./.env:/app/.env, — rm -rf .env и копируйте заново.
Теперь секреты. Поля CREDS_KEY, CREDS_IV, JWT_SECRET и JWT_REFRESH_SECRET в примере пустые: оставите так — LibreChat сгенерирует временные и запишет в .env.temp. Путь задан в compose как LIBRECHAT_TEMP_CREDENTIALS_PATH=/app/data/.env.temp — внутри тома librechat-data. Один docker compose down -v удалит том вместе с ключом шифрования: пользователи вылетят по недействительным JWT, а их API-ключи расшифровать будет нечем. На бою значения задают руками:
{
echo "CREDS_KEY=$(openssl rand -hex 32)"
echo "CREDS_IV=$(openssl rand -hex 16)"
echo "JWT_SECRET=$(openssl rand -hex 32)"
echo "JWT_REFRESH_SECRET=$(openssl rand -hex 32)"
echo "MEILI_MASTER_KEY=$(openssl rand -hex 32)"
echo "ADMIN_PANEL_SESSION_SECRET=$(openssl rand -hex 32)"
echo "UID=$(id -u)"
echo "GID=$(id -g)"
} >> .env
Длины не случайны: CREDS_KEY — ключ AES-256, ровно 64 hex-символа, CREDS_IV — вектор инициализации, ровно 32. ADMIN_PANEL_SESSION_SECRET описан как «min 32 characters»; без него панель не стартует, хотя остальной стек поднимется. Всё сразу в менеджер паролей — восстановить CREDS_KEY нельзя.
Дальше — главный файл установки, docker-compose.override.yaml: он подключает конфиг, фиксирует версию образа и убирает порты из интернета.
services:
api:
image: registry.librechat.ai/danny-avila/librechat:v0.8.7
ports: !override
- "127.0.0.1:3080:3080"
volumes:
- type: bind
source: ./librechat.yaml
target: /app/librechat.yaml
admin-panel:
ports: !override
- "127.0.0.1:3000:3000"
Тег !override не украшательство. По правилам слияния Compose порты — «уникальный ресурс» с ключом {ip, target, published, protocol}. Строка 127.0.0.1:3080:3080 отличается от базовой 3080:3080 полем ip, конфликта нет — и Compose добавит её к существующей, оставив открытым наружу и 0.0.0.0:3080. !override заменяет атрибут целиком. Результат проверяем командами:
docker compose config | grep -A6 "ports:"
ss -tlnp | grep -E '3080|3000'
В выводе ss должно быть 127.0.0.1:3080 и 127.0.0.1:3000; 0.0.0.0:3080 означает, что интерфейс с чужими API-ключами открыт всему интернету по голому HTTP. Второй момент того же override: базовый docker-compose.yml не монтирует librechat.yaml вообще, отсюда жалоба «правлю конфиг, а ничего не меняется».
docker compose up -d && docker compose ps
docker compose logs -f api --tail=50
curl -I http://127.0.0.1:3080
curl должен вернуть HTTP/1.1 200 OK. Ответ Bind for 0.0.0.0:3080 failed: port is already allocated — порт занят предыдущим запуском, помогает docker compose down. Подхват конфига: docker compose exec api ls -l /app/librechat.yaml, ответ No such file or directory — бинд не сработал.
Ключи и модели: .env, librechat.yaml и локальная Ollama
В .env.example ключи заданы особым значением: OPENAI_API_KEY=user_provided, ANTHROPIC_API_KEY=user_provided, GOOGLE_KEY=user_provided. Это не заглушка, а режим «каждый приносит свой ключ»: пользователь вводит его в интерфейсе, LibreChat шифрует значение тем самым CREDS_KEY и кладёт в MongoDB. Нужен общий корпоративный — впишите реальное значение, и поле ввода исчезнет.
Всё сложнее живёт в librechat.yaml: обязательная строка version: 1.3.14 и провайдеры в блоке endpoints.custom:
version: 1.3.14
cache: true
endpoints:
allowedAddresses:
- '127.0.0.1:11434'
- 'host.docker.internal:11434'
custom:
- name: 'OpenRouter'
apiKey: '${OPENROUTER_KEY}'
baseURL: 'https://openrouter.ai/api/v1'
models:
default: ['meta-llama/llama-3-70b-instruct']
fetch: true
titleConvo: true
titleModel: 'meta-llama/llama-3-70b-instruct'
dropParams: ['stop']
modelDisplayLabel: 'OpenRouter'
- name: 'Ollama'
apiKey: 'ollama'
baseURL: 'http://host.docker.internal:11434/v1/'
models:
default: ['qwen2.5:7b']
fetch: true
titleConvo: true
titleModel: 'current_model'
modelDisplayLabel: 'Ollama'
Две тонкости, на которых спотыкаются чаще всего. allowedAddresses: свежие версии проверяют адреса на SSRF и блокируют всё, что смотрит в localhost, приватные подсети и домены .internal/.local. Локальная Ollama попадает под запрет, её вносят в белый список явно — с портом, без схемы, путей и CIDR. dropParams: часть шлюзов отвечает 422 Unprocessable Entity на параметры, которые LibreChat шлёт по умолчанию, — для Mistral в примере конфига перечислено ['stop', 'user', 'frequency_penalty', 'presence_penalty'].
Ollama на том же сервере работает и без видеокарты, но ожидания надо калибровать. На нашем стенде (AMD EPYC 9554, 16 vCPU, Ollama 0.33.1) qwen2.5:7b в Q4_K_M занимает 5,1 ГБ памяти и выдаёт около 7,4 токена в секунду на генерации, llama3.1:8b — 5,6 ГБ и около 12,8 токена, qwen2.5:3b при 2,2 ГБ разгоняется до 34 токенов. Там же видно, что генерация выходит на полку уже на четырёх потоках: она упирается в пропускную способность памяти, а не в число ядер, — «добавим ядер» тут не работает. Подробности — в разборе запуска моделей через Ollama.
Домен, HTTPS и стриминг: Nginx и переменные окружения
Порт закрыт на петлю, наружу пускаем через Nginx с сертификатом. Конфиг короткий, но три директивы в нём обязательны:
server {
server_name chat.example.com;
client_max_body_size 100M;
location / {
proxy_pass http://127.0.0.1:3080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 600s;
}
}
sudo apt install -y nginx certbot python3-certbot-nginx
sudo certbot --nginx -d chat.example.com
proxy_buffering off — против самого частого симптома: ответ не печатается по словам, а вываливается целиком через полминуты, потому что Nginx копит поток SSE в буфере. proxy_read_timeout 600s спасает длинные ответы рассуждающих моделей от разрыва по умолчанию в 60 секунд. client_max_body_size должен быть не меньше лимита загрузки файлов в LibreChat: иначе на PDF пользователь получит 413 Request Entity Too Large, а в логах приложения не будет ничего — запрос до него не дошёл.
Три переменные в .env надо привести в соответствие с доменом:
DOMAIN_CLIENTиDOMAIN_SERVER— по умолчанию обе равныhttp://localhost:3080. Их используют ссылки в письмах, callback-адреса OAuth и эвристика флагаSecureу cookie. Оставитеlocalhost— получите нерабочий вход через внешних провайдеров и битые ссылки восстановления пароля.TRUST_PROXY=1— уже стоит в.env.exampleи означает «за приложением один обратный прокси». Без этого запросы для рейт-лимитера приходят с одного адреса, иLIMIT_MESSAGE_IPбанит всех разом.SESSION_COOKIE_SECURE— трогают в одном случае: работа по чистому HTTP и зацикленный вход, когда форма принимает пароль и тут же возвращает обратно. Браузер выбрасывает cookie с флагомSecure, пришедшую по HTTP; тогда ставятfalse, а на HTTPS переменную не задают вовсе.
Пользователи, обновление и бэкап
Первое после успешной регистрации — закрыть её: по умолчанию ALLOW_REGISTRATION=true, и на публичном домене аккаунт заведёт кто угодно. Ставьте false, перезапускайте api, дальше — скрипты из репозитория:
docker compose exec api npm run create-user
docker compose exec api npm run invite-user
docker compose exec api npm run list-users
docker compose exec api npm run reset-password
docker compose exec api npm run ban-user
Поиск по истории выключен: SEARCH=false. Включается парой «SEARCH=true плюс непустой MEILI_MASTER_KEY» — вы его уже сгенерировали. Старые диалоги не находятся — переиндексацию делает docker compose exec api npm run reset-meili-sync. Грабля на будущее: том Meilisearch примонтирован как ./meili_data_v1.35.1 — путь с номером версии, и при обновлении образа каталог сменится, а индекс придётся строить заново. Диалоги целы, они в MongoDB.
Обновление: git pull, docker compose pull, docker compose up -d. Поскольку в override зафиксирован тег v0.8.7, pull сам по себе ничего не сломает — версию вы поднимаете осознанно, поменяв цифру. Так и надо: обратных миграций схемы нет, откат только из бэкапа.
Бэкап. Гарантированный способ — холодная копия при остановленном стеке:
docker compose down
sudo tar czf ~/librechat-$(date +%F).tar.gz \
.env librechat.yaml docker-compose.override.yaml \
data-node uploads images
docker compose up -d
Онлайн-вариант — docker compose exec -T mongodb mongodump --archive --db LibreChat | gzip > lc-$(date +%F).gz, если инструменты есть в образе (docker compose exec mongodb mongodump --version). Если секреты руками вы не задали, в архив обязан попасть и том librechat-data. Как поставить это на поток — в разборе бэкапа Docker-томов.
Две честные оговорки. NODE_MAX_OLD_SPACE_SIZE=6144 из .env.example — аргумент сборки, а не рантайм-настройка, в самом файле про это сказано прямым текстом; память Node на живом контейнере ограничивается только через NODE_OPTIONS. И MongoDB запускается командой mongod --noauth, а у vectordb открытым текстом прописаны myuser / mypassword: внутри сети Docker терпимо, но публиковать наружу порты 27017 и 5432 нельзя — частые ошибки MongoDB разобраны отдельно.
Какой сервер взять в MAATRIX под LibreChat
Конфигурация зависит от того, где считаются модели, — сценария ровно два.
Сценарий А: LibreChat как окно к внешним API. Модели считают OpenAI, Anthropic, Google или OpenRouter, сервер занят интерфейсом, базой, поиском и разбором файлов. Честный минимум — 2 vCPU, 4 ГБ RAM, 40–60 ГБ NVMe. На 2 ГБ стек тоже стартует, но первая же индексация большого PDF в rag_api кончается процессом, убитым по OOM: жить там можно, только вырезав override-файлом rag_api, vectordb, meilisearch и admin-panel. Комфорт для команды из пяти-десяти человек — 4 vCPU и 8 ГБ.
Сценарий Б: LibreChat плюс Ollama на той же машине без GPU. Здесь всё определяет модель — она целиком лежит в памяти: 7–8B в Q4 это 5–5,6 ГБ весов плюс контекст плюс сам стек. Рабочая конфигурация — 8 vCPU, 16 ГБ RAM, от 100 ГБ NVMe. Про скорость честно сказано выше: одному терпимо, пятерым одновременно нет.
Локация — Великобритания, Лондон. Для интерфейса, который целыми днями ходит в зарубежные API, это самый практичный выбор: британские адреса принимаются AI-провайдерами без региональных отказов, а задержка из Москвы примерно вдвое ниже, чем до Нью-Йорка. Франция равноценна, США берут ради американского IP, Россию — когда пользователи только внутри страны и в игре персональные данные, но тогда внешние API придётся выносить через зарубежный шлюз. Подробнее — VPS в Великобритании под нейросети.
Про установку без прикрас: готовой сборки LibreChat в каталоге apps.maatrix.io нет — сервер приходит чистым, с Ubuntu 24.04 или Debian, и ставить его вы будете по шагам из этой статьи. Родственные сервисы в каталоге есть и разворачиваются автоматически при заказе, доступы появляются в кабинете: Ollama для локальных моделей и LiteLLM как шлюз к провайдерам. Связка «LiteLLM снаружи, LibreChat как интерфейс» удобна: ключи и бюджеты живут в шлюзе, а LibreChat цепляется одним custom-эндпоинтом — её грабли в статье почему LiteLLM не видит API-ключи.
Оплата — картами российских банков, по СБП, криптовалютой или токеном MAAT; иностранная карта не нужна, даже когда сервер стоит в Лондоне. Не уверены, какой сценарий ваш, — напишите, сколько будет пользователей и нужны ли документы, и мы соберём конфигурацию под задачу. А сомневаетесь в выборе интерфейса — рядом Open WebUI против LibreChat.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Сколько памяти нужно, если модели считаются во внешних API?
4 ГБ — рабочий минимум для стека из шести контейнеров, 8 ГБ — комфорт. На 2 ГБ он поднимется, но упадёт по OOM на первой же индексации документа; чтобы жить там, отключайте rag_api, vectordb, meilisearch и админ-панель через override.
Правлю librechat.yaml, а в интерфейсе ничего не меняется. Почему?
Базовый docker-compose.yml не монтирует этот файл в контейнер — бинд добавляется только в override. Проверьте docker compose exec api ls -l /app/librechat.yaml: ответ No such file or directory подтверждает диагноз. Альтернатива — переменная CONFIG_PATH в .env.
Забыл пароль администратора, а регистрация закрыта. Что делать?
Сброс делается изнутри контейнера: docker compose exec api npm run reset-password. Там же npm run create-user и npm run list-users. Открывать ALLOW_REGISTRATION=true ради этого не нужно.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.