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.
Усунення несправностей + 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 за балансувальником.