vLLM на GPU-сервере: OpenAI-совместимый API для своей LLM
TL;DR
В этом гайде вы развернёте vLLM на GPU-сервере с Docker, запустите локальную языковую модель и получите защищённый OpenAI-совместимый API на адресе /v1/chat/completions. Такой сервер можно подключить к собственному приложению, LangChain, OpenWebUI, ботам и внутренним сервисам без отправки промптов стороннему AI-провайдеру.
- vLLM обслуживает LLM быстрее обычного Hugging Face inference благодаря PagedAttention и continuous batching.
- Для первого запуска подойдёт модель уровня Qwen3-8B или Llama 3.1 8B на GPU с 16–24 ГБ VRAM.
- API vLLM совместим с форматом OpenAI:
/v1/models,/v1/chat/completions,/v1/completions. - Модель, API-ключ и конфигурация запускаются через Docker Compose и файл
.env. - Внешний доступ закрывается TLS-прокси Caddy, а порт vLLM остаётся доступным только локально.
- Для продакшена нужно сохранять конфигурацию, список моделей, API-ключи и при необходимости кеш Hugging Face.
Что мы настраиваем и зачем
vLLM — это сервер инференса больших языковых моделей. Он загружает модель в память GPU, принимает HTTP-запросы и возвращает сгенерированный текст. Главная практическая особенность vLLM — совместимость с API OpenAI. Приложение, которое умеет работать с OpenAI SDK, обычно можно переключить на собственный сервер заменой base_url и API-ключа.
В этом сценарии GPU-сервер работает как частный endpoint для одной или нескольких LLM. Например, вы можете использовать Qwen3-8B для внутреннего чат-бота, Llama 3.1 8B для суммаризации документов, DeepSeek-R1-Distill для рассуждений или embedding-модель для поиска по базе знаний. Сам vLLM не является веб-чатом: это API-слой. Интерфейс для сотрудников или клиентов подключается отдельно.
Что получится в итоге
- Ubuntu 24.04 LTS-сервер с установленным NVIDIA-драйвером, Docker и NVIDIA Container Toolkit.
- Контейнер
vllm/vllm-openai, использующий GPU через Docker. - Модель
Qwen/Qwen3-8B, автоматически загружаемая в локальный кеш Hugging Face. - OpenAI-совместимый API:
https://llm.example.com/v1/chat/completions. - Авторизация Bearer-токеном, который проверяет сам vLLM.
- TLS-сертификат Let’s Encrypt, автоматически управляемый Caddy.
- Понятная схема обновления, резервного копирования и диагностики ошибок GPU.
Почему vLLM, а не обычный запуск Transformers
Запуск модели через Python-библиотеку Transformers удобен для эксперимента, но плохо подходит для постоянного API. При нескольких одновременных запросах Python-приложение часто простаивает или обрабатывает запросы последовательно. vLLM использует непрерывную пакетную обработку запросов: GPU генерирует токены для разных пользователей в одном вычислительном цикле.
Также vLLM экономнее управляет KV-кешем — памятью, в которой модель хранит контекст диалога. Для чатов с длинной историей именно KV-кеш часто становится ограничением раньше, чем вес самой модели. PagedAttention разбивает этот кеш на блоки и снижает фрагментацию VRAM.
Self-hosted или managed API
| Критерий | Managed API | Свой vLLM на GPU-сервере |
|---|---|---|
| Старт | Нужен ключ и биллинг | Нужны сервер, GPU и настройка |
| Данные промптов | Передаются внешнему поставщику | Остаются в вашей инфраструктуре |
| Выбор модели | Ограничен каталогом сервиса | Можно выбирать совместимые открытые модели |
| Цена при постоянной нагрузке | Зависит от числа токенов | Фиксирована стоимость GPU-сервера |
| Обслуживание | Выполняет поставщик | Вы отвечаете за безопасность, обновления и мониторинг |
Self-hosted вариант оправдан, если данные нельзя отправлять во внешнее API, нагрузка предсказуема, требуется конкретная open-weight модель или нужен полный контроль над лимитами, логированием и версиями. Если трафик редкий и непредсказуемый, managed API обычно экономичнее: GPU не должен простаивать круглосуточно.
Важно: не каждая модель на Hugging Face имеет лицензию для коммерческого использования. Перед интеграцией в продукт проверьте лицензию модели, требования к указанию авторства и условия доступа к gated-репозиториям.
Какой VPS-конфиг нужен под эту задачу
Для vLLM важнее всего не число CPU-ядер, а объём и тип GPU-памяти. В VRAM должны одновременно разместиться веса модели, KV-кеш контекста, временные тензоры и запас на фрагментацию. Оперативная память сервера используется для загрузки файлов модели, Docker, кеша и операционной системы.
Оценка памяти для модели
Грубая формула для весов: число параметров умножается на размер одного параметра. Модель на 8 миллиардов параметров в FP16 занимает около 16 ГБ только под веса. В 4-битном формате AWQ или GPTQ она занимает примерно 5–7 ГБ, но точное значение зависит от архитектуры, quantization-конфига и версии движка.
| Задача | GPU и VRAM | RAM | Диск NVMe | Практический результат |
|---|---|---|---|---|
| Тесты, 7B–8B в 4-bit | NVIDIA L4 24 ГБ или RTX 4090 24 ГБ | 32 ГБ | 100 ГБ | Небольшой чат и разработка |
| 8B FP16, несколько пользователей | 24–48 ГБ VRAM | 64 ГБ | 200 ГБ | Качественный общий API |
| 32B в 4-bit | 48 ГБ VRAM | 64–128 ГБ | 300 ГБ | Серьёзные задачи и длинный контекст |
| 70B в 4-bit | 80 ГБ VRAM или несколько GPU | 128 ГБ | 500 ГБ | Высокое качество при дорогом инференсе |
Для этого руководства оптимален сервер с одной GPU на 24 ГБ VRAM, 8 vCPU, 32–64 ГБ RAM, 200 ГБ NVMe и сетью от 1 Гбит/с. Такой конфиг даёт запас для Qwen3-8B, Llama 3.1 8B и сопоставимых моделей. Как один из нейтральных вариантов можно взять VPS с указанными характеристиками, если в описании явно гарантированы выделенная NVIDIA GPU, объём VRAM и доступ к ней из виртуальной машины.
Почему нельзя ориентироваться только на название GPU
Уточняйте объём VRAM, а не только модель ускорителя. Например, датацентровые GPU могут выпускаться в конфигурациях с разной памятью. Уточните, что GPU выделена вам целиком, а не разделяется между клиентами без гарантированной доли. Также убедитесь, что провайдер разрешает Docker и предоставляет драйвер NVIDIA либо совместимый GPU passthrough.
Когда нужен dedicated, а не GPU VPS
Выделенный сервер нужен при нескольких GPU, модели от 70B параметров, высокой постоянной нагрузке, строгих требованиях к изоляции или необходимости полного контроля над PCIe-топологией. Он также полезен, если вы хотите запускать отдельные модели на нескольких GPU или обслуживать десятки параллельных пользователей.
GPU VPS рационален для одной GPU и умеренной нагрузки: он проще в запуске, дешевле на старте и легче масштабируется заменой конфигурации. Для одиночной 8B-модели dedicated обычно избыточен.
Выбор локации
Локация влияет на задержку API. Если пользователи и приложение находятся в Европе, сервер в европейском дата-центре обычно даст задержку сети 10–60 мс вместо сотен миллисекунд. Для LLM это не единственный фактор: генерация каждого токена тоже занимает время. Но удалённый сервер заметно ухудшает ощущение отзывчивости в потоковом чате.
Если API обрабатывает персональные данные, учитывайте требования юрисдикции и хранения данных. Не отправляйте логи запросов в регионы, где их хранение противоречит вашим договорам или правилам обработки данных.
Подготовка сервера
Ниже используется Ubuntu 24.04 LTS. На момент подготовки этого руководства это практичный базовый выбор для GPU-нагрузок: система имеет долгий срок поддержки, совместима с актуальными драйверами NVIDIA, Docker Engine 29 и NVIDIA Container Toolkit. Выполняйте начальную настройку под пользователем с правами sudo, а не под root.
Создайте пользователя и настройте SSH-ключ
Подключитесь к серверу первоначальным способом, который предоставил хостинг. На своём компьютере создайте ключ, если его ещё нет, затем добавьте публичную часть на сервер. Не закрывайте текущую SSH-сессию до проверки входа под новым пользователем.
# На сервере: создаём отдельного администратора и добавляем его в sudo
sudo adduser deploy
sudo usermod -aG sudo deploy
# На локальном компьютере: копируем публичный SSH-ключ на сервер
ssh-copy-id deploy@SERVER_IP
Проверьте вход в новом окне терминала:
# На локальном компьютере: проверяем вход по ключу
ssh deploy@SERVER_IP
Обновите систему и установите базовые инструменты
# Обновляем пакеты Ubuntu и устанавливаем диагностические утилиты
sudo apt update && sudo apt full-upgrade -y
sudo apt install -y ca-certificates curl gnupg git jq htop tmux \
fail2ban ufw unzip ncdu
После обновления ядра или NVIDIA-драйвера перезагрузите сервер. На GPU-узлах перезагрузка особенно важна: загруженный драйвер должен соответствовать установленным библиотекам.
# Перезагружаем сервер, если обновлялось ядро или драйвер
sudo reboot
Закройте лишние сетевые порты
vLLM по умолчанию слушает HTTP-порт 8000. Не публикуйте его напрямую в интернет: API-ключ не заменяет сетевой периметр, а незашифрованный HTTP передаёт запросы и токен открытым текстом. Снаружи будут доступны только SSH, HTTP для выпуска сертификата и HTTPS.
# Разрешаем SSH, HTTP и HTTPS; все остальные входящие соединения запрещаем
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose
Настройте Fail2ban и отключите вход по паролю
Fail2ban блокирует источники с серией неудачных попыток SSH-входа. После проверки SSH-ключа отключите парольную авторизацию. Если вы потеряете приватный ключ и не имеете консольного доступа через панель сервера, восстановление потребует вмешательства провайдера.
# Включаем защиту SSH и создаём локальную конфигурацию Fail2ban
sudo systemctl enable --now fail2ban
sudo tee /etc/fail2ban/jail.d/sshd.local > /dev/null <<'EOF'
[sshd]
enabled = true
maxretry = 5
findtime = 10m
bantime = 1h
EOF
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd
# Отключаем SSH-пароли и root-вход только после проверки ключа
sudo tee /etc/ssh/sshd_config.d/99-hardening.conf > /dev/null <<'EOF'
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
EOF
sudo sshd -t && sudo systemctl reload ssh
Проверьте также правила firewall в панели самого сервера, если они существуют. Внешний firewall должен совпадать с UFW: разрешите 22, 80 и 443, а 8000 не открывайте.
Установка ПО — пошагово
Перед установкой контейнера убедитесь, что GPU видна операционной системе. Многие GPU VPS поставляются с готовым драйвером NVIDIA. Если команда nvidia-smi не работает, сначала установите рекомендованный драйвер из репозитория Ubuntu или обратитесь к документации образа сервера.
Проверьте NVIDIA-драйвер
# Показываем модель GPU, версию драйвера и доступную VRAM
nvidia-smi
Вы должны увидеть таблицу с GPU и версией драйвера. Для современных образов vLLM с CUDA 12 обычно требуется драйвер NVIDIA серии 535 или новее; на практике предпочтительны ветки 550, 570 или новее, совместимые с вашей ОС. Не устанавливайте CUDA Toolkit на хост без необходимости: контейнер vLLM уже содержит нужные пользовательские CUDA-библиотеки.
Установите Docker Engine
Устанавливайте Docker из официального репозитория Docker, а не старый пакет docker.io из базового репозитория Ubuntu. Это даст актуальный Docker Engine 29.x и плагин Docker Compose.
# Добавляем официальный GPG-ключ и репозиторий Docker для Ubuntu
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
# Разрешаем пользователю deploy запускать Docker без sudo и проверяем версию
sudo usermod -aG docker deploy
newgrp docker
docker version
docker compose version
Установите NVIDIA Container Toolkit
NVIDIA Container Toolkit передаёт GPU из хоста в Docker-контейнер. Репозиторий и ключ ниже используются для актуальных пакетов toolkit. После установки перезапускается Docker daemon, поэтому кратковременно остановятся уже работающие контейнеры.
# Подключаем официальный репозиторий NVIDIA Container Toolkit
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \
sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt update
sudo apt install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
Проверьте GPU внутри контейнера
# Запускаем официальный CUDA-контейнер и проверяем, что GPU передаётся в Docker
docker run --rm --gpus all nvidia/cuda:12.8.0-base-ubuntu24.04 nvidia-smi
Если вывод внутри контейнера показывает вашу GPU, базовая инфраструктура готова. Ошибка could not select device driver "" with capabilities: [[gpu]] обычно означает, что toolkit не установлен или Docker не был перезапущен.
Подготовьте каталог приложения
Разделяйте данные приложения и данные контейнера. В каталоге проекта будут Compose-файл, Caddyfile, переменные окружения и скрипты. Кеш Hugging Face вынесен в отдельный volume, чтобы не скачивать десятки гигабайт модели после пересоздания контейнера.
# Создаём структуру проекта vLLM и каталоги для постоянных данных
sudo mkdir -p /opt/vllm/{caddy,data/hf-cache,backups,scripts}
sudo chown -R deploy:deploy /opt/vllm
cd /opt/vllm
Получите токен Hugging Face при необходимости
Для публичной Qwen3-8B токен обычно не нужен. Но он потребуется для gated-моделей, например некоторых вариантов Llama. Создайте access token с минимальным правом Read в личном кабинете Hugging Face и сохраните его только в .env. Не вставляйте такой токен в Git, Docker image или Compose-файл.
Конфигурация
В примере используется vLLM OpenAI server и модель Qwen/Qwen3-8B. Образ закреплён на конкретном теге v0.10.2, чтобы обновление не меняло поведение незаметно. Перед новым развёртыванием проверьте актуальный стабильный тег в официальном реестре vLLM и протестируйте его в отдельном окружении; не используйте latest в продакшене.
Создайте файл переменных окружения
Сгенерируйте длинный случайный API-ключ. Пользовательские приложения будут передавать его в заголовке Authorization: Bearer .... Значение VLLM_MAX_MODEL_LEN ограничивает контекст: 8192 токена — безопасная начальная настройка для GPU с 24 ГБ VRAM.
# Генерируем секреты и создаём .env с правами только для владельца
cd /opt/vllm
umask 077
cat > .env <<EOF
DOMAIN=llm.example.com
VLLM_API_KEY=$(openssl rand -hex 32)
HF_TOKEN=
MODEL_NAME=Qwen/Qwen3-8B
SERVED_MODEL_NAME=qwen3-8b
VLLM_MAX_MODEL_LEN=8192
GPU_MEMORY_UTILIZATION=0.88
EOF
chmod 600 .env
# Просматриваем ключ только локально; не копируйте его в публичные чаты и репозитории
grep VLLM_API_KEY .env
Замените llm.example.com на свой домен. До запуска Caddy создайте DNS-запись типа A, указывающую на публичный IPv4-адрес сервера. Если используется IPv6, добавьте AAAA-запись и убедитесь, что порт 443 доступен по IPv6.
Создайте Docker Compose-конфигурацию
Порт 8000 привязан к 127.0.0.1, поэтому его нельзя открыть напрямую из интернета. Caddy и vLLM находятся в одной Docker-сети. Переменная HF_TOKEN передаётся контейнеру только если вы указали её в .env.
services:
vllm:
image: vllm/vllm-openai:v0.10.2
container_name: vllm-api
restart: unless-stopped
env_file:
- .env
environment:
HF_HOME: /root/.cache/huggingface
HUGGING_FACE_HUB_TOKEN: ${HF_TOKEN}
TOKENIZERS_PARALLELISM: "false"
volumes:
- ./data/hf-cache:/root/.cache/huggingface
ports:
- "127.0.0.1:8000:8000"
ipc: host
gpus: all
command:
- --model
- ${MODEL_NAME}
- --served-model-name
- ${SERVED_MODEL_NAME}
- --host
- 0.0.0.0
- --port
- "8000"
- --api-key
- ${VLLM_API_KEY}
- --max-model-len
- ${VLLM_MAX_MODEL_LEN}
- --gpu-memory-utilization
- ${GPU_MEMORY_UTILIZATION}
- --enable-prefix-caching
healthcheck:
test: ["CMD-SHELL", "python3 -c \"import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=5)\""]
interval: 30s
timeout: 10s
retries: 10
start_period: 180s
caddy:
image: caddy:2.10-alpine
container_name: vllm-caddy
restart: unless-stopped
env_file:
- .env
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./data/caddy-data:/data
- ./data/caddy-config:/config
depends_on:
vllm:
condition: service_started
Сохраните этот файл как /opt/vllm/compose.yml. Параметр --gpu-memory-utilization 0.88 не резервирует всю VRAM, оставляя запас для CUDA и системных процессов. Если модель не помещается, сначала снизьте контекст, затем уменьшите это значение до 0.80–0.85 либо выберите квантованную модель.
Настройте Caddy и HTTPS
Caddy автоматически запросит и продлит TLS-сертификат, если домен уже указывает на сервер, а порты 80 и 443 открыты. Ниже проксируются только API и health endpoint. Не включайте подробные логи HTTP-запросов без необходимости: промпты пользователей могут оказаться в логах.
{
email [email protected]
}
{$DOMAIN} {
encode zstd gzip
@api {
path /v1/ /health
}
handle @api {
reverse_proxy vllm:8000 {
flush_interval -1
}
}
respond "Not found" 404
}
Сохраните конфигурацию как /opt/vllm/Caddyfile и замените email на рабочий адрес для уведомлений Let’s Encrypt. Caddy не добавляет авторизацию самостоятельно: проверку Bearer-токена выполняет vLLM через параметр --api-key.
Запустите сервис
# Скачиваем образы и запускаем Caddy с сервером модели в фоне
cd /opt/vllm
docker compose -f compose.yml pull
docker compose -f compose.yml up -d
# Смотрим прогресс скачивания модели и загрузки движка vLLM
docker compose -f compose.yml logs -f vllm
Первый запуск может занять от нескольких минут до часа: зависит от скорости сети, размера модели и компиляции CUDA kernels. Когда в логе появится сообщение о запуске API-сервера, прервите просмотр сочетанием Ctrl+C; контейнер продолжит работать в фоне.
Проверьте API локально и через HTTPS
# Проверяем readiness напрямую с сервера, не раскрывая API наружу
curl -s http://127.0.0.1:8000/health && echo
# Получаем перечень моделей через публичный HTTPS endpoint
source /opt/vllm/.env
curl -s https://$DOMAIN/v1/models \
-H "Authorization: Bearer $VLLM_API_KEY" | jq
Запрос должен вернуть объект с моделью qwen3-8b. Теперь отправьте тестовый запрос в формате Chat Completions:
# Отправляем тестовый запрос к OpenAI-совместимому API
source /opt/vllm/.env
curl -s https://$DOMAIN/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $VLLM_API_KEY" \
-d '{
"model": "qwen3-8b",
"messages": [
{"role": "system", "content": "Отвечай кратко и технически."},
{"role": "user", "content": "Что такое KV-кеш в LLM?"}
],
"temperature": 0.2,
"max_tokens": 180
}' | jq '.choices[0].message.content'
Для Python-клиента используйте официальный SDK OpenAI, но направьте его на свой адрес:
from openai import OpenAI
import os
client = OpenAI(
base_url="https://llm.example.com/v1",
api_key=os.environ["VLLM_API_KEY"],
)
response = client.chat.completions.create(
model="qwen3-8b",
messages=[{"role": "user", "content": "Составь план резервного копирования."}],
temperature=0.3,
)
print(response.choices[0].message.content)
Ограничьте доступ приложений
Один общий ключ удобен на старте, но недостаточен для команды или публичного SaaS. vLLM проверяет ключ, однако не предоставляет полноценные квоты, роли, отдельные ключи и биллинг. Для таких задач поставьте перед ним API gateway, например Kong, Traefik с middleware или отдельный backend, который выдаёт ключи, считает токены и применяет rate limit.
Не передавайте ключ браузеру. Клиентское веб-приложение должно обращаться к вашему backend, а backend — к vLLM. Иначе любой посетитель сможет извлечь токен из JavaScript или панели разработчика и использовать GPU за ваш счёт.
Бэкапы и обслуживание
Вес модели можно повторно скачать, поэтому это не главный объект резервного копирования. Критичны файлы .env, compose.yml, Caddyfile, TLS-данные Caddy и скрипты обслуживания. Если вы добавите RAG, базы векторного поиска, пользовательские файлы или собственные LoRA-адаптеры, их нужно включить в отдельный план бэкапов.
Что сохранять
| Данные | Нужно бэкапить | Причина |
|---|---|---|
.env |
Да, с шифрованием | Содержит API-ключ и настройки модели |
compose.yml, Caddyfile |
Да | Быстрое восстановление инфраструктуры |
| Данные Caddy | Да | TLS-сертификаты и состояние ACME |
| HF cache | Необязательно | Экономит время скачивания, но легко восстанавливается |
| Логи запросов | Обычно нет | Могут содержать чувствительные промпты |
| Векторная БД и документы RAG | Обязательно | Это уникальные бизнес-данные |
Резервное копирование через restic
Restic шифрует архивы до отправки в S3-совместимое хранилище, на отдельный сервер по SFTP или в поддерживаемый облачный backend. Ниже показан вариант с S3. Не храните пароль репозитория в том же публичном Git-репозитории, где лежит инфраструктурный код.
# Устанавливаем restic и создаём каталог для секретов резервного копирования
sudo apt install -y restic
sudo install -d -m 700 /root/.config/restic
# Создаём файл окружения; замените значения своими S3-реквизитами
sudo tee /root/.config/restic/vllm.env > /dev/null <<'EOF'
export RESTIC_REPOSITORY="s3:https://s3.example.net/vllm-backups"
export RESTIC_PASSWORD="CHANGE_THIS_TO_A_LONG_UNIQUE_SECRET"
export AWS_ACCESS_KEY_ID="CHANGE_ME"
export AWS_SECRET_ACCESS_KEY="CHANGE_ME"
EOF
sudo chmod 600 /root/.config/restic/vllm.env
# Инициализируем зашифрованный репозиторий один раз
sudo bash -c 'source /root/.config/restic/vllm.env && restic init'
# Создаём ежедневный скрипт: конфиги и сертификаты сохраняются, кеш модели исключается
sudo tee /opt/vllm/scripts/backup.sh > /dev/null <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
source /root/.config/restic/vllm.env
restic backup /opt/vllm \
--exclude /opt/vllm/data/hf-cache \
--exclude /opt/vllm/backups \
--tag vllm-config
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
restic check
EOF
sudo chmod 700 /opt/vllm/scripts/backup.sh
# Выполняем первый бэкап вручную и убеждаемся, что он завершается без ошибок
sudo /opt/vllm/scripts/backup.sh
# Запускаем бэкап ежедневно в 03:20 и сохраняем технический журнал в syslog
sudo crontab -e
# Добавьте следующую строку в открывшийся файл:
20 3 /opt/vllm/scripts/backup.sh >> /var/log/vllm-backup.log 2>&1
Проверяйте не только успешный статус бэкапа, но и восстановление. Раз в квартал разверните конфиги на тестовой машине или выполните restic restore latest --target /tmp/vllm-restore, не перезаписывая рабочие данные.
Обновления без неожиданностей
Для одного GPU-сервера безопаснее maintenance window: остановите API, обновите образ, запустите его и прогоните тестовый запрос. Rolling update имеет смысл при двух и более репликах за балансировщиком, когда можно выводить серверы из трафика по одному.
# Перед обновлением фиксируем текущий статус и делаем бэкап
cd /opt/vllm
docker compose -f compose.yml ps
sudo /opt/vllm/scripts/backup.sh
# После изменения тега образа в compose.yml перезапускаем только сервисы проекта
docker compose -f compose.yml pull
docker compose -f compose.yml up -d
docker compose -f compose.yml logs --tail=100 vllm
Не обновляйте одновременно Ubuntu, NVIDIA-драйвер, Docker, CUDA-базовые образы и vLLM перед важным релизом. Меняйте один слой за раз, фиксируйте версию, проверяйте nvidia-smi, затем выполняйте API smoke test.
Troubleshooting + FAQ
Почему контейнер vLLM не видит GPU?
Если в логах есть сообщение о недоступном CUDA-устройстве, сначала выполните nvidia-smi на хосте. Если оно не работает, проблема в драйвере или GPU passthrough. Если на хосте GPU видна, но не видна в Docker, проверьте команду docker run --rm --gpus all nvidia/cuda:12.8.0-base-ubuntu24.04 nvidia-smi. Переустановите NVIDIA Container Toolkit, выполните sudo nvidia-ctk runtime configure --runtime=docker и перезапустите Docker.
Ошибка CUDA out of memory при загрузке модели — что делать?
Ошибка CUDA out of memory означает, что VRAM не хватает для весов, KV-кеша или служебных буферов. Сначала уменьшите VLLM_MAX_MODEL_LEN, например с 8192 до 4096, и снизьте GPU_MEMORY_UTILIZATION до 0.80. Затем используйте меньшую либо квантованную модель AWQ/GPTQ, совместимую с vLLM. Посмотрите nvidia-smi: возможно, память занята другим контейнером или зависшим процессом.
API возвращает 401 Unauthorized, хотя ключ кажется правильным
Проверьте, что заголовок отправляется в формате Authorization: Bearer ВАШ_КЛЮЧ, без кавычек и лишних пробелов. Затем сравните ключ с содержимым /opt/vllm/.env. После изменения .env нужен перезапуск: docker compose -f compose.yml up -d --force-recreate vllm. Не используйте переменную с пустым значением из другой shell-сессии; выполните source /opt/vllm/.env перед curl.
Почему Caddy не выпускает HTTPS-сертификат?
Чаще всего DNS-запись домена ещё не указывает на IP сервера или порт 80 блокируется облачным firewall. Проверьте dig +short llm.example.com, затем sudo ufw status и сетевые правила в панели сервера. Посмотрите docker logs vllm-caddy: там будет причина ACME-ошибки. Для HTTP-01 проверки домен должен быть доступен извне по порту 80, даже если основной API работает только по HTTPS.
Модель отвечает слишком медленно. Что проверять?
Разделите задержку на время первого токена и скорость генерации. Проверьте GPU Utilization и VRAM через watch -n 1 nvidia-smi, логи vLLM и нагрузку CPU. Слишком длинный контекст, высокая параллельность и reasoning-модели увеличивают задержку. Уменьшите max_tokens, ограничьте контекст, включите потоковый режим stream: true в клиенте. Если GPU простаивает, убедитесь, что запросы действительно попадают в vLLM, а не блокируются proxy или приложением.
Какой VPS-конфиг минимально подойдёт?
Для учебного или личного API с 7B–8B моделью в 4-bit минимально разумный вариант — одна NVIDIA GPU с 16 ГБ VRAM, 4–8 vCPU, 32 ГБ RAM и 100 ГБ NVMe. Но комфортнее начинать с 24 ГБ VRAM: это оставляет запас для контекста и нескольких одновременных запросов. Для FP16-весов 8B-модели 16 ГБ обычно недостаточно, поскольку память нужна не только для самих весов.
Что выбрать — VPS или dedicated для этой задачи?
Для одной GPU, модели до 8B–14B и внутреннего API выбирайте GPU VPS, если платформа гарантирует доступ к ускорителю и позволяет запуск Docker. Dedicated нужен при нескольких GPU, 48–80 ГБ VRAM, моделях 32B–70B, высокой постоянной нагрузке и жёстких требованиях к изоляции. Начните с VPS, измерьте реальные токены в секунду, пиковую параллельность и VRAM, а затем переходите на выделенное железо при подтверждённой необходимости.
Можно ли открыть API напрямую на порту 8000?
Технически можно, но для продакшена это плохая практика. Прямой HTTP не шифрует Bearer-токен и содержимое промптов, а порт проще случайно оставить без ограничений. Оставьте 127.0.0.1:8000:8000 в Compose и публикуйте наружу только Caddy на 443. Если API нужен только вам, ещё безопаснее не открывать 443 вовсе и подключаться через WireGuard или SSH-туннель.
Как сменить модель без повторной настройки всего сервера?
Измените MODEL_NAME и при необходимости SERVED_MODEL_NAME в .env, затем перезапустите контейнер командой docker compose -f compose.yml up -d --force-recreate vllm. Учитывайте требования новой модели к VRAM, chat template, лицензии и токену Hugging Face. Старый кеш можно оставить: он не мешает работе, но занимает диск. Перед заменой модели сохраните текущую конфигурацию и протестируйте новый вариант в отдельное окно обслуживания.
Выводы и следующие шаги
Теперь у вас есть собственный OpenAI-совместимый API на базе vLLM: модель работает на выделенной GPU, API защищён токеном и TLS, а конфигурация воспроизводима через Docker Compose. Такая схема подходит для внутренних ассистентов, RAG-систем, автоматизации разработки и частных AI-приложений.
- Измерьте реальную нагрузку: токены в секунду, время первого токена, VRAM и число параллельных запросов.
- Добавьте API gateway с отдельными ключами, rate limit и метриками, если сервисом пользуются несколько команд или клиентов.
- Для поиска по документам подключите embedding-модель и векторную БД, а для роста нагрузки разверните несколько vLLM-реплик за балансировщиком.