LiteLLM на сервере: частые ошибки и решения
LiteLLM разворачивается за пять минут, а дальше начинается интересное: клиент получает «LLM Provider NOT provided», OpenAI отвечает 403 «по стране», стриминг обрывается ровно на шестидесятой секунде, а через неделю диск съедает таблица логов. Ошибки LiteLLM на сервере повторяются от установки к установке, и почти каждая чинится одной строкой в конфиге. Разберём их по схеме «симптом — причина — решение».
Содержание
- Как за две минуты понять, где именно сломалось
- Прокси не стартует: зависимости, YAML и занятый порт
- База, Prisma и внезапно «отвалившиеся» модели
- «LLM Provider NOT provided» и ошибки маршрутизации
- 403 по стране, таймауты и обрывы стриминга
- Что ломается на второй неделе: диск, воркеры и обновления
- Какой сервер брать под LiteLLM в MAATRIX
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Как за две минуты понять, где именно сломалось
LiteLLM — это три слоя, и ошибка живёт в одном из них: процесс прокси (не стартует, падает, не слушает порт), маршрутизация в конфиге (не тот model, неподдерживаемый параметр) и апстрим (401, 403, 429, таймаут). Начинайте с определения слоя, а не с гугления текста ошибки.
Сначала — жив ли процесс, что он писал последним и слушает ли свой порт (по умолчанию 4000):
journalctl -u litellm -n 200 --no-pager | grep -iE "error|traceback"
docker logs --tail 200 litellm 2>&1 | tail -50
ss -ltnp | grep 4000
Здоровый ответ последней команды:
LISTEN 0 2048 0.0.0.0:4000 0.0.0.0:* users:(("python3",pid=1421,fd=9))
Нет строки — проблема в слое процесса, читайте следующую секцию. Порт слушается — проверьте готовность: curl -s http://127.0.0.1:4000/health/readiness. В ответе важны статус, состояние базы и версия LiteLLM: частая потеря времени — когда вы правите конфиг по документации свежей ветки, а на сервере образ полугодовой давности.
Для разбора конкретного запроса включите LITELLM_LOG=DEBUG или --detailed_debug. Режим шумный: в логи попадают тела запросов с промптами, выключайте его сразу.
Прокси не стартует: зависимости, YAML и занятый порт
Самая частая причина — установлен SDK, а не прокси. pip install litellm даёт только библиотеку, серверная часть живёт в extras, и litellm --config падает с ошибкой импорта. На Ubuntu 24.04 добавляется вторая грабля: системный Python 3.12 помечен как externally managed, и обычный pip install отвечает:
error: externally-managed-environment
× This environment is externally managed
Через --break-system-packages не надо — сломаете системные пакеты:
apt install -y python3-venv
python3 -m venv /opt/litellm/venv
/opt/litellm/venv/bin/pip install -U 'litellm[proxy]'
Третья причина — синтаксис config.yaml: кривой отступ даёт yaml.scanner.ScannerError: mapping values are not allowed in this context. Проверяйте до перезапуска: python3 -c "import yaml;yaml.safe_load(open('/etc/litellm/config.yaml'))".
Четвёртая — мастер-ключ: LITELLM_MASTER_KEY обязан начинаться с sk-, иначе виртуальные ключи и админ-роуты не работают. Генерируйте его как sk-$(openssl rand -hex 24) и держите в /etc/litellm/.env с chmod 600.
Пятая — занятый порт: [Errno 98] Address already in use. Владелец находится тем же ss -ltnp | grep 4000.
И про Docker: путь в --config — это путь внутри контейнера, а не на хосте. Отсюда «конфиг не найден» и дефолты без моделей:
docker run -d --name litellm --restart=always \
-p 127.0.0.1:4000:4000 \
-v /etc/litellm/config.yaml:/app/config.yaml:ro \
--env-file /etc/litellm/.env \
--log-opt max-size=50m --log-opt max-file=3 \
ghcr.io/berriai/litellm:main-stable --config /app/config.yaml
Порт прокси держите на локалхосте, наружу — 443 через nginx с TLS: ufw allow 443/tcp и никакого ufw allow 4000. Открытый LiteLLM сканеры находят за часы.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть LiteLLMБаза, Prisma и внезапно «отвалившиеся» модели
Виртуальные ключи, бюджеты и учёт расходов требуют PostgreSQL — не MySQL и не SQLite; в репозитории Ubuntu 24.04 лежит PostgreSQL 16, его достаточно. Самое частое сообщение здесь — от Prisma:
Error: P1001: Can't reach database server at `postgres`:`5432`
По адресу из DATABASE_URL базы нет. Типичные причины: имя сервиса из docker compose (postgres) в конфиге, а контейнер запущен обычным docker run вне этой сети, либо база слушает только UNIX-сокет. Проверьте: psql "postgresql://litellm:PASS@127.0.0.1:5432/litellm" -c "select 1;".
Вторая засада — закрытый исходящий трафик: при старте Prisma-клиент тянет бинарные движки с внешнего хоста binaries.prisma.sh, и если egress режет фаервол, контейнер зависает на старте.
Третья, самая недооценённая — LITELLM_SALT_KEY: если ключи провайдеров хранятся в базе, они шифруются этим значением. Симптом потери: после переезда или пересоздания контейнера все модели разом отвечают ошибками авторизации, хотя в базе они на месте. Расшифровать без прежней соли нельзя — только заводить ключи заново, поэтому salt ставится один раз и попадает в бэкап рядом с дампом:
pg_dump -Fc "postgresql://litellm:PASS@127.0.0.1:5432/litellm" > /var/backups/litellm-$(date +%F).dump
«LLM Provider NOT provided» и ошибки маршрутизации
Текст, который приносит больше всего вопросов:
litellm.BadRequestError: LLM Provider NOT provided. Pass in the LLM provider
you are trying to call. You passed model=my-gpt
Причина одна: в litellm_params.model нет префикса провайдера, и LiteLLM не знает, куда слать my-gpt. Различайте два поля: model_name — псевдоним для ваших клиентов, litellm_params.model — реальный идентификатор у провайдера с префиксом.
model_list:
- model_name: fast
litellm_params:
model: openai/gpt-4o-mini
api_key: os.environ/OPENAI_API_KEY
- model_name: smart
litellm_params:
model: anthropic/claude-sonnet-4-5
api_key: os.environ/ANTHROPIC_API_KEY
- model_name: local
litellm_params:
model: ollama/llama3.1
api_base: http://172.17.0.1:11434
litellm_settings:
drop_params: true
Второй симптом — клиент шлёт имя, которого нет в model_list, и получает 400. Спросите у прокси: curl -s -H "Authorization: Bearer sk-КЛЮЧ" http://127.0.0.1:4000/v1/models.
Третий — жалоба на неподдерживаемый параметр: чужая библиотека или нода n8n шлёт frequency_penalty либо logit_bias, а провайдер их не принимает. Строка drop_params: true выбрасывает такие поля вместо падения, но глушит симптом: если параметр влиял на качество, вы потеряете его молча.
Четвёртый — локальная модель. Внутри контейнера localhost указывает на сам контейнер, до Ollama на хосте запрос не дойдёт, и вы увидите APIConnectionError с причиной All connection attempts failed. Берите адрес docker-моста http://172.17.0.1:11434 (сверьте через ip -4 addr show docker0) или --add-host=host.docker.internal:host-gateway. И помните: Ollama слушает только 127.0.0.1, ей нужен OLLAMA_HOST=0.0.0.0.
403 по стране, таймауты и обрывы стриминга
Этот класс ошибок не про конфиг, а про то, откуда идёт запрос. Если шлюз стоит в России, крупные провайдеры отказывают ещё до проверки ключа:
OpenAIException - Error code: 403 - {'error': {'code':
'unsupported_country_region_territory', 'message': 'Country, region, or
territory not supported', 'type': 'request_forbidden'}}
Признак: 403 и слово country вместо invalid_api_key. Ключ рабочий, дело в IP, правки config.yaml бессильны. Замер с нашего нью-йоркского узла командой curl -o /dev/null -s -w "connect=%{time_connect} tls=%{time_appconnect} total=%{time_total}\n" https://api.openai.com/v1/models:
connect=0.004 tls=0.021 total=0.089
С московской машины через цепочку VPN тот же запрос занимает 0,6–1,1 с, а часть попыток отдаёт всё тот же 403: диапазоны публичных VPN провайдеры давно отсекают.
Вторая сетевая причина зависаний — нерабочий IPv6-маршрут: клиент уходит по нему и ждёт таймаута. Проверка — curl -4 против curl -6, лечение — строка precedence ::ffff:0:0/96 100 в /etc/gai.conf. Ретраи и фолбэки задавайте явно, иначе единичный сбой апстрима сразу видит пользователь:
router_settings:
num_retries: 2
timeout: 120
fallbacks: [{"smart": ["fast"]}]
Ретраи не бесплатны: каждая попытка — ещё один оплаченный запрос, так что для 429 разумнее фолбэк, чем повторы в ту же модель.
Теперь стриминг. Симптом: через curl ответ идёт токен за токеном, а через веб-интерфейс приходит одним куском или обрывается. Виноват nginx: он буферизует ответ апстрима, SSE-поток превращается в блок, а на длинной генерации падает по таймауту. В error.log лежит upstream timed out (110: Connection timed out) while reading response header from upstream, ровно через 60 секунд — подпись дефолтного proxy_read_timeout. Рабочая секция:
location /v1/ {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
}
Применяйте через nginx -t && systemctl reload nginx. Если перед сервером Cloudflare в режиме проксирования, помните его потолок: ответ, не начавший приходить примерно за 100 секунд, закрывается ошибкой 524 — домен шлюза лучше держать в режиме DNS-only.
Что ломается на второй неделе: диск, воркеры и обновления
Первое — база расходов. Таблица LiteLLM_SpendLogs пишет строку на каждый запрос; у нас выходило около 2 КБ на запись: сто тысяч запросов — 200–300 МБ с индексами, миллион — пара гигабайт. Смотрите размер и чистите старое по крону:
psql -U litellm -d litellm -c "SELECT pg_size_pretty(pg_total_relation_size('\"LiteLLM_SpendLogs\"'));"
psql -U litellm -d litellm -c "DELETE FROM \"LiteLLM_SpendLogs\" WHERE \"startTime\" < NOW() - INTERVAL '30 days';"
Если детальный лог запросов не нужен, в general_settings есть disable_spend_logs: true — агрегированные траты по ключам сохранятся. Заодно ограничьте логи Docker: json-file по умолчанию безлимитный и кладёт десятки гигабайт в /var/lib/docker/containers.
Второе — мониторинг, который стоит денег. Эндпоинт /health дёргает каждую модель из model_list тестовым запросом: чекер с интервалом в минуту даёт круглосуточный расход токенов. Для внешних проверок берите /health/liveliness.
Третье — память и воркеры. Флаг --num_workers множит потребление: каждый воркер это отдельный процесс. На нашем тестовом узле один воркер в простое держал около 400 МБ RSS, четыре — под полтора гигабайта, и на машине с 2 ГБ ядро начинало убивать процессы: Worker (pid:2431) was sent SIGKILL! Perhaps out of memory? Подтверждает dmesg -T | grep -i "out of memory".
Четвёртое — обновления. Тег main-latest меняется под вами, и однажды прокси не поднимется после планового docker pull. Берите main-stable или фиксируйте версию. Перед апгрейдом — дамп базы и копия config.yaml с .env.
Какой сервер брать под LiteLLM в MAATRIX
Хорошая новость: сам шлюз лёгкий — он не считает нейросети, а разбирает JSON, подставляет ключи и проксирует потоки, поэтому GPU не нужен. Плохая: почти всё разобранное выше — 403 по стране, лишние сотни миллисекунд на рукопожатии, обрывы через кривые прокси — упирается не в мощность, а в точку выхода в интернет.
Минимум, на котором это честно работает: 2 vCPU, 4 ГБ RAM, 40–60 ГБ NVMe. Хватает на «LiteLLM в один-два воркера плюс PostgreSQL в контейнере» и десятки запросов в минуту — нагрузка команды из 5–15 человек или пары агентов. Диск берите с запасом из-за SpendLogs и логов.
Комфортный вариант: 4 vCPU, 8 ГБ RAM, 80 ГБ NVMe. Это 4 воркера, Redis для общих лимитов между ними, база с местом под историю расходов и запас на пики. Redis чинит и неочевидную проблему: без него лимиты RPM и TPM считает каждый воркер отдельно, и суммарно вы вылетаете за квоту провайдера раньше, чем ожидали.
Локация — США (Нью-Йорк). Для шлюза к OpenAI, Anthropic и Google это вариант без танцев: чистый IP, который не встречает unsupported_country_region_territory, и минимальная задержка до API. Российская площадка нужна в одном сценарии: LiteLLM ходит только к своим моделям (Ollama, vLLM) или российским провайдерам, а 152-ФЗ важнее зарубежных API. Лондон и Францию берут, когда шлюзом пользуется команда из ЕС.
Оплата — картами российских банков, по СБП, криптовалютой или токеном MAAT; зарубежная карта не нужна. LiteLLM разворачивается из каталога приложений: связка с прокси и базой поднимается автоматически, дальше вы правите config.yaml под свои модели. Не уверены в конфигурации — опишите профиль нагрузки, подберём без запаса «на всякий случай».
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть LiteLLMОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Почему ключ рабочий, а прокси получает 403?
Если в тексте ошибки unsupported_country_region_territory, дело не в ключе, а в IP сервера: провайдер отказывает по геолокации до проверки авторизации. Лечится переносом шлюза в разрешённую локацию.
Стриминг приходит одним куском — это баг LiteLLM?
Почти никогда: виноват обратный прокси, нужны proxy_buffering off и увеличенный proxy_read_timeout в nginx. Если домен проксируется через Cloudflare, учитывайте его лимит около 100 секунд.
Можно ли обойтись без PostgreSQL?
Да, если нужен только маршрутизатор без виртуальных ключей, бюджетов и учёта расходов — хватит config.yaml и мастер-ключа. С ключами на пользователей и лимитами база обязательна, а с ней бэкап дампа и LITELLM_SALT_KEY.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.