LocalAI на CPU-сервере: LLM без видеокарты
TL;DR
LocalAI позволяет запустить локальную языковую модель с OpenAI-совместимым API на VPS или dedicated-сервере без GPU. В этом руководстве будет настроен защищённый LocalAI на Ubuntu 24.04 LTS с Docker, CPU-бэкендом llama.cpp, моделью в формате GGUF, HTTPS через Caddy, API-ключом и резервным копированием.
- Для первого рабочего запуска достаточно 4 vCPU, 8 ГБ RAM и 40–60 ГБ SSD.
- Для комфортной работы с моделями 7B–8B в квантизации Q4 лучше использовать 8 vCPU и 16–32 ГБ RAM.
- LocalAI предоставляет интерфейс, совместимый с OpenAI API:
/v1/chat/completions,/v1/modelsи другие endpoints. - На CPU важнее скорость одного ядра и объём RAM, чем номинальное число слабых vCPU.
- Модели GGUF можно хранить локально: запросы и документы не отправляются во внешние AI-сервисы.
- Для публичного доступа обязательны TLS, firewall, API-ключ и ограничение доступа по IP или reverse proxy.
Что мы настраиваем и зачем
LocalAI — это self-hosted AI-сервис, который запускает языковые модели, модели для генерации эмбеддингов, speech-to-text и часть других задач на собственном сервере. Для LLM на CPU обычно применяется бэкенд llama.cpp и модели в формате GGUF. Они квантизированы: занимают меньше памяти, чем исходные веса в FP16 или BF16, и могут работать без NVIDIA GPU.
Практический результат этого руководства — API-сервис, доступный по HTTPS на собственном домене. К нему смогут подключаться приложения, которые умеют работать с OpenAI API: внутренний чат для команды, бот в Telegram или Mattermost, IDE-ассистент, n8n, Dify, LibreChat, Open WebUI, собственный SaaS или backend на Python, Node.js и Go.
На сервере будут работать четыре слоя: Docker Compose управляет контейнером, LocalAI предоставляет API, GGUF-модель отвечает на запросы, а Caddy принимает HTTPS-трафик и проксирует его внутрь. Сам LocalAI не будет опубликован напрямую в интернет: порт 8080 останется доступен только на localhost.
Когда LocalAI на CPU оправдан
- Нужен автономный API для небольшой команды, бота или внутренних инструментов.
- Данные нельзя или нежелательно отправлять в облачные LLM-провайдеры.
- Нагрузка умеренная: от нескольких десятков до сотен запросов в день.
- Допустима задержка ответа в несколько секунд, а не потоковая скорость GPU-сервиса.
- Нужен предсказуемый ежемесячный бюджет без оплаты за токены.
- Вы хотите экспериментировать с моделями, системными промптами и параметрами inference.
Что CPU-сервер не решает
CPU-инференс не заменяет GPU для высокой параллельности. На сервере с 8 современными vCPU модель 8B в Q4 обычно выдаёт примерно 4–12 токенов в секунду, но реальная цифра зависит от поколения CPU, частоты, AVX2/AVX-512, размера контекста и нагрузки соседних процессов. Для интерактивного одного пользователя этого часто достаточно. Для десятков одновременных диалогов — уже нет.
Не следует ожидать хорошего результата от крупных моделей 30B, 70B и выше на обычном VPS. Даже если модель поместится в память, время до первого токена и общая задержка сделают сервис неудобным. Для таких моделей нужен сервер с большим объёмом RAM, мощными CPU либо GPU-инфраструктура.
Облачный API и self-hosted LocalAI
| Критерий | Облачный managed API | LocalAI на собственном сервере |
|---|---|---|
| Запуск | Практически мгновенный | Нужны сервер, Docker, модель и защита API |
| Качество крупнейших моделей | Обычно выше | Зависит от выбранной локальной модели |
| Конфиденциальность | Данные уходят внешнему провайдеру | Данные остаются в вашей инфраструктуре |
| Стоимость | Оплата за токены или подписка | Фиксированная стоимость сервера и хранения |
| Скорость на большой нагрузке | Высокая, инфраструктура масштабируется автоматически | Ограничена CPU, RAM и настройками очереди |
| Контроль над моделью | Ограничен доступными моделями | Полный контроль над моделью, шаблонами и версиями |
Рациональная схема для небольшого продукта — использовать LocalAI для задач, где важны приватность, низкая стоимость и предсказуемость: классификация, извлечение данных, суммаризация внутренних текстов, RAG по документации, помощь разработчикам. Внешний облачный API можно оставить как резерв для сложных запросов или пиков.
Какой VPS-конфиг нужен под эту задачу
Главный ресурс для LocalAI на CPU — оперативная память. Вторая по значимости характеристика — производительность процессорного ядра. Диск важен для хранения моделей: одна GGUF-модель 3B в Q4 обычно занимает 2–3 ГБ, модель 8B в Q4 — около 4,5–6 ГБ, а несколько вариантов моделей и резервные копии быстро заполняют небольшой SSD.
| Сценарий | CPU | RAM | SSD/NVMe | Рекомендуемые модели |
|---|---|---|---|---|
| Тесты, один пользователь | 4 vCPU | 8 ГБ | 50 ГБ | 1B–4B, Q4 |
| Чат, бот, RAG для команды | 8 vCPU | 16 ГБ | 100 ГБ NVMe | 7B–8B, Q4_K_M |
| Несколько пользователей и моделей | 12–16 vCPU | 32–64 ГБ | 200 ГБ NVMe | 8B–14B, embeddings, reranker |
| Крупные модели на CPU | 16+ выделенных ядер | 64–128 ГБ | 500 ГБ NVMe | 14B–32B с компромиссом по скорости |
Практичный стартовый конфиг
Для первой production-инсталляции берите 8 vCPU, 16 ГБ RAM, 100 ГБ NVMe и канал от 1 Гбит/с. Такой сервер позволит запустить одну основную модель уровня Llama 3.1/3.2 8B, Qwen2.5 7B или Mistral 7B в GGUF-квантизации Q4, оставить запас операционной системе и Caddy, а также хранить несколько файлов моделей. Как один из нейтральных вариантов можно взять VPS с указанными характеристиками.
При выборе тарифа уточняйте, являются ли vCPU гарантированными, какое поколение CPU используется и есть ли у процессора AVX2. Для llama.cpp AVX2 заметно влияет на производительность. Иногда 8 быстрых выделенных ядер дают более полезный результат, чем 16 перегруженных виртуальных ядер.
Оценка памяти для GGUF
Нельзя рассчитывать RAM только по размеру файла GGUF. Помимо весов модели память требуется под KV cache, буферы inference, контейнер, ядро Linux и файловый кэш. Безопасное практическое правило: для модели 8B Q4 размером 5 ГБ выделяйте сервер минимум с 12–16 ГБ RAM. Для 14B Q4 размером 9–11 ГБ нужен минимум 24–32 ГБ RAM.
Контекст также потребляет память. Если вы увеличиваете context_size с 4096 до 16384 токенов, потребление RAM может вырасти на несколько гигабайт. Не задавайте максимальный контекст «на всякий случай»: для обычного чата и RAG в большинстве случаев достаточно 4096–8192 токенов.
Когда нужен dedicated, а не VPS
Dedicated-сервер нужен, когда важны стабильно высокая скорость генерации, гарантия отсутствия noisy neighbors, 32–128 ГБ RAM, большие модели или постоянные параллельные запросы. Это также правильный выбор, если LocalAI обслуживает коммерческий продукт, где задержка напрямую влияет на конверсию.
VPS остаётся хорошим вариантом для прототипа, внутреннего сервиса, личного ассистента и малой команды. Начинайте с VPS, измеряйте реальную скорость через API и переходите на dedicated только после появления подтверждённого узкого места: нехватки RAM, CPU saturation или роста очереди запросов.
Как влияет локация сервера
Локация не ускоряет вычисление токенов, но влияет на сетевую задержку до пользователей. Для чата желательно размещать сервер в регионе, близком к большинству клиентов. Разница в 50–100 мс особенно заметна при streaming-ответах, хотя основная задержка на CPU всё равно будет связана с генерацией модели.
Если LocalAI обрабатывает персональные данные, документы компании или медицинскую информацию, также учитывайте требования к юрисдикции, хранению данных и трансграничной передаче. Размещайте резервные копии отдельно от основного сервера, желательно в другом дата-центре.
Подготовка сервера
Ниже используется Ubuntu Server 24.04 LTS. На момент настройки это стабильная LTS-база с длительным сроком поддержки. Войдите на сервер под пользователем root только для первоначальной подготовки, затем создайте отдельного администратора и отключите вход root по SSH.
Обновление системы и базовые пакеты
Команда устанавливает актуальные обновления безопасности, инструменты диагностики, firewall и fail2ban.
apt update && apt full-upgrade -y
apt install -y ca-certificates curl gnupg jq nano vim \
ufw fail2ban unattended-upgrades \
htop iotop ncdu rsync
Перезагрузите сервер, если обновилось ядро. Это применит новый kernel и исключит ситуацию, когда уязвимое ядро продолжает работать в памяти.
if [ -f /var/run/reboot-required ]; then reboot; fi
Создание администратора
Замените deploy на собственное имя пользователя. Учётная запись будет использоваться для Docker Compose и последующего обслуживания LocalAI.
adduser deploy
usermod -aG sudo deploy
Скопируйте свой публичный SSH-ключ на сервер с локального компьютера. Выполняйте эту команду на своём компьютере, а не на VPS.
ssh-copy-id deploy@SERVER_IP
Проверьте вход в отдельном терминале. Не закрывайте текущую root-сессию, пока не убедитесь, что авторизация по ключу работает.
ssh deploy@SERVER_IP
Защита SSH
Откройте конфигурацию SSH и запретите root-вход и парольную авторизацию. Перед этим убедитесь, что у пользователя deploy есть работающий ключ.
sudo nano /etc/ssh/sshd_config.d/99-hardening.conf
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
X11Forwarding no
MaxAuthTries 3
LoginGraceTime 30
Проверьте синтаксис и перезапустите SSH. Если команда sshd -t не выводит ошибок, конфигурация корректна.
sudo sshd -t && sudo systemctl restart ssh
Firewall и fail2ban
Откройте только SSH, HTTP и HTTPS. Порт LocalAI 8080 не открывайте: после настройки он будет слушать только 127.0.0.1.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose
Включите fail2ban. Ubuntu поставляет готовый фильтр для OpenSSH; сервис будет временно блокировать IP после серии неудачных входов.
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
Проверка ресурсов до установки
До загрузки модели проверьте доступную RAM, размер диска и характеристики процессора. Это поможет заранее выбрать подходящую квантизацию и число потоков.
free -h
df -h /
lscpu | egrep 'Model name|CPU\(s\)|Thread|AVX|Flags'
nproc
Если в выводе lscpu нет AVX2, LocalAI всё равно может работать, но производительность на CPU может быть заметно ниже. В таком случае разумнее использовать компактную модель 3B–4B и не пытаться обслуживать несколько одновременных чатов.
Установка ПО — пошагово
В этой конфигурации используются Docker Engine 28+ и Docker Compose v2, Ubuntu 24.04 LTS, Caddy 2.8+ и актуальная стабильная ветка LocalAI 3.x. Для production не оставляйте tag latest навсегда: после успешного тестирования зафиксируйте конкретный тег либо digest образа в compose.yaml.
Установка Docker Engine
Удалите старые пакеты Docker, если они присутствуют. Это исключает конфликт между пакетами Ubuntu и официальным Docker Engine.
sudo apt remove -y docker.io docker-compose docker-compose-v2 \
docker-doc podman-docker containerd runc 2>/dev/null || true
Добавьте официальный ключ репозитория Docker и подключите репозиторий для Ubuntu 24.04.
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
Установите Docker Engine, containerd и Compose plugin. Compose будет запускать LocalAI и выполнять healthcheck.
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
Разрешите пользователю deploy управлять Docker без sudo. После команды выйдите из SSH-сессии и войдите снова, чтобы группа применилась.
sudo usermod -aG docker deploy
exit
После повторного входа убедитесь, что Docker работает. Контейнер hello-world должен завершиться без ошибок.
docker version
docker compose version
docker run --rm hello-world
Создание структуры проекта
Все файлы LocalAI будут находиться в /opt/localai. Каталог models хранит GGUF-файлы и YAML-конфигурации моделей, а data сохраняет данные LocalAI между перезапусками.
sudo mkdir -p /opt/localai/{models,data,backups}
sudo chown -R deploy:deploy /opt/localai
cd /opt/localai
Загрузка первой модели
Для CPU-первого запуска возьмите инструктивную модель Qwen2.5-3B-Instruct в квантизации Q4_K_M. Она компактнее моделей 7B–8B, нормально работает на 8 ГБ RAM и подходит для проверки API. Перед использованием в production изучите лицензию конкретной модели и условия её распространения.
Следующая команда скачивает GGUF в каталог моделей. URL указан как пример публичного репозитория; перед загрузкой проверьте актуальное имя файла и хеш на странице релиза модели.
cd /opt/localai/models
curl -L --fail --retry 3 \
-o Qwen2.5-3B-Instruct-Q4_K_M.gguf \
"https://huggingface.co/bartowski/Qwen2.5-3B-Instruct-GGUF/resolve/main/Qwen2.5-3B-Instruct-Q4_K_M.gguf"
Проверьте, что файл действительно скачался и не имеет нулевой длины. Для модели 3B Q4 ожидайте размер порядка 2–3 ГБ.
ls -lh /opt/localai/models
sha256sum /opt/localai/models/Qwen2.5-3B-Instruct-Q4_K_M.gguf
Создание секретов
API-ключ не храните в compose-файле или исходном коде приложения. Сгенерируйте длинное значение и запишите его в файл .env, доступный только пользователю deploy.
cd /opt/localai
umask 077
printf 'LOCALAI_API_KEY=%s\n' "$(openssl rand -hex 32)" > .env
chmod 600 .env
cat .env
Сохраните этот ключ в менеджере секретов. Он потребуется клиентским приложениям в заголовке Authorization: Bearer.
Конфигурация LocalAI, моделей и HTTPS
Описание модели
Создайте YAML-файл конфигурации. Параметр threads задаёт количество CPU-потоков для inference. На сервере с 8 vCPU начните с 6: останется ресурс для ОС, reverse proxy и обработки сети. Значение context_size 4096 — безопасная стартовая точка для CPU-сервера.
nano /opt/localai/models/qwen-cpu.yaml
name: qwen2.5-3b-cpu
backend: llama-cpp
parameters:
model: Qwen2.5-3B-Instruct-Q4_K_M.gguf
context_size: 4096
threads: 6
temperature: 0.7
top_p: 0.9
max_tokens: 512
template:
chat: |
{{if .System}}<|im_start|>system
{{.System}}<|im_end|>
{{end}}{{range .Messages}}<|im_start|>{{.Role}}
{{.Content}}<|im_end|>
{{end}}<|im_start|>assistant
{{.Assistant}}
Шаблон чата важен: он преобразует сообщения OpenAI API в формат, на котором обучалась модель Qwen. Если ответы внезапно содержат служебные токены, повторяют промпт или игнорируют роли, сначала проверьте именно chat template.
Docker Compose для CPU-инференса
Создайте compose.yaml. Образ localai/localai:latest-aio-cpu предназначен для CPU и включает нужные компоненты для типового запуска. После подтверждения рабочей версии замените latest-aio-cpu на конкретный version tag из официальных release notes.
nano /opt/localai/compose.yaml
services:
localai:
image: localai/localai:latest-aio-cpu
container_name: localai
restart: unless-stopped
env_file:
- .env
environment:
- DEBUG=false
- MODELS_PATH=/models
- THREADS=6
- CONTEXT_SIZE=4096
volumes:
- ./models:/models
- ./data:/data
ports:
- "127.0.0.1:8080:8080"
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8080/readyz || curl -fsS http://localhost:8080/v1/models"]
interval: 30s
timeout: 10s
retries: 5
start_period: 120s
deploy:
resources:
limits:
memory: 12G
Лимит памяти в 12 ГБ подходит для сервера с 16 ГБ RAM и одной моделью 3B. На VPS с 8 ГБ RAM установите memory: 6G и используйте более компактную модель. На сервере с 32 ГБ RAM для модели 8B можно поднять лимит до 20–24 ГБ.
Запустите контейнер в фоновом режиме и посмотрите журналы. Первая загрузка может занять больше времени, поскольку LocalAI инициализирует backend и читает файл модели с диска.
cd /opt/localai
docker compose pull
docker compose up -d
docker compose ps
docker compose logs -f --tail=100
Не публикуйте локальный порт 8080 через firewall. Проверка ниже выполняется прямо на сервере и показывает, что API видит настроенную модель.
curl -s http://127.0.0.1:8080/v1/models | jq .
Проверка chat completion локально
Замените значение ключа командой, которая читает его из .env. Параметр stream выключен для простой диагностики; после запуска приложения его можно включить для постепенной выдачи токенов.
cd /opt/localai
source .env
curl -sS http://127.0.0.1:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${LOCALAI_API_KEY}" \
-d '{
"model": "qwen2.5-3b-cpu",
"messages": [
{
"role": "system",
"content": "Ты краткий технический помощник."
},
{
"role": "user",
"content": "Объясни в одном предложении, что такое reverse proxy."
}
],
"temperature": 0.2,
"max_tokens": 100,
"stream": false
}' | jq .
Если API отвечает JSON-объектом с choices, базовая настройка завершена. Если LocalAI возвращает 401, проверьте имя переменной и поддержку API-ключа используемой версией образа. В некоторых сборках LocalAI ключ задаётся отдельной переменной окружения или аутентификацию удобнее реализовать на уровне Caddy.
Настройка Caddy и TLS
Для HTTPS нужен домен, A-запись которого указывает на IP сервера. До запуска Caddy проверьте DNS: домен должен возвращать публичный IPv4-адрес VPS. Порты 80 и 443 должны быть доступны извне.
Установите Caddy из официального репозитория. Он автоматически получает и продлевает сертификаты Let’s Encrypt, если DNS и firewall настроены корректно.
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | \
sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | \
sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install -y caddy
Создайте дополнительный пароль для basic authentication. Это второй барьер перед API: клиенту потребуется и Basic Auth, и Bearer token. Хеш, который вернёт команда, вставьте в Caddyfile.
caddy hash-password --plaintext 'СЮДА_ДЛИННЫЙ_ОТДЕЛЬНЫЙ_ПАРОЛЬ'
Откройте конфигурацию Caddy. Замените домен, имя пользователя и хеш. При необходимости вместо basic auth можно ограничить доступ VPN-сетью WireGuard или IP-адресами офиса.
sudo nano /etc/caddy/Caddyfile
llm.example.com {
encode zstd gzip
@not_api not path /v1/ /readyz /healthz
respond @not_api "Not found" 404
basicauth {
apiadmin $2a$14$REPLACE_WITH_CADDY_PASSWORD_HASH
}
reverse_proxy 127.0.0.1:8080 {
header_up Host {host}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
transport http {
read_timeout 300s
write_timeout 300s
}
}
log {
output file /var/log/caddy/localai-access.log
format json
}
}
Проверьте файл перед применением. Затем перезагрузите Caddy и убедитесь, что сертификат выдан.
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
sudo systemctl status caddy --no-pager
sudo journalctl -u caddy -n 50 --no-pager
Внешняя проверка HTTPS API
Выполните команду с рабочего компьютера. Она проверяет TLS, basic authentication, Bearer token и доступность списка моделей через публичный домен.
curl -sS https://llm.example.com/v1/models \
-u 'apiadmin:ВАШ_ОТДЕЛЬНЫЙ_ПАРОЛЬ' \
-H 'Authorization: Bearer ВАШ_LOCALAI_API_KEY' | jq .
Для Python-клиента используйте обычный OpenAI SDK, указав свой base_url. Пароль basic auth лучше передавать через защищённый reverse proxy или VPN; для API-приложений удобнее оставить только Bearer-аутентификацию и ограничить IP-адреса в Caddy.
from openai import OpenAI
client = OpenAI(
base_url="https://llm.example.com/v1",
api_key="ВАШ_LOCALAI_API_KEY",
)
response = client.chat.completions.create(
model="qwen2.5-3b-cpu",
messages=[
{"role": "user", "content": "Напиши короткое приветствие."}
],
temperature=0.4,
)
print(response.choices[0].message.content)
Контроль производительности
Во время тестового запроса в отдельном SSH-окне запустите htop. Процессы inference должны использовать примерно то число ядер, которое задано параметром threads. Если сервер начинает использовать swap, уменьшите контекст, выберите меньшую квантизацию или увеличьте RAM.
htop
free -h
docker stats localai
docker compose -f /opt/localai/compose.yaml logs --tail=100 localai
Бэкапы и обслуживание
LocalAI обычно не содержит критичной базы данных, если используется только как inference API. Однако нужно сохранять конфигурацию, файлы моделей, переменные окружения, Caddyfile, данные приложений-клиентов и, если они появятся, векторную базу RAG. Не считайте Docker image бэкапом: образ можно скачать заново, а конфиги и данные — нет.
Что включить в резервную копию
/opt/localai/compose.yaml— версия сервиса и настройки контейнера./opt/localai/models/.yaml— параметры и chat templates моделей./opt/localai/.env— API-ключи; хранить только в зашифрованном backup./opt/localai/data— постоянные данные LocalAI, если они используются./etc/caddy/Caddyfile— reverse proxy и правила доступа.- Каталог моделей GGUF — по ситуации: файлы крупные, но их повторная загрузка может быть долгой.
- Данные RAG-стека: PostgreSQL, Qdrant, pgvector, Chroma или другой vector store.
Для конфигурации делайте ежедневную копию. Модели можно бэкапить еженедельно либо не бэкапить вовсе, если вы храните проверенный список URL, версий и SHA256. Для production-сервиса разумнее иметь хотя бы одну удалённую копию GGUF: публичный репозиторий может изменить структуру, удалить файл или ограничить доступ.
Резервное копирование через restic
Restic шифрует архив до отправки в S3-совместимое хранилище. Установите пакет и создайте отдельный файл секретов. Не добавляйте этот файл в Git и не отправляйте его в мессенджеры.
sudo apt install -y restic
sudo install -d -m 700 /root/.config/restic
sudo nano /root/.config/restic/localai.env
export RESTIC_REPOSITORY="s3:https://s3.example.net/localai-backups"
export RESTIC_PASSWORD="ДЛИННЫЙ_СЛУЧАЙНЫЙ_ПАРОЛЬ_РЕПОЗИТОРИЯ"
export AWS_ACCESS_KEY_ID="S3_ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="S3_SECRET_KEY"
Ограничьте доступ к файлу и инициализируйте удалённый репозиторий. Эту операцию выполняют один раз.
sudo chmod 600 /root/.config/restic/localai.env
sudo bash -c 'source /root/.config/restic/localai.env && restic init'
Создайте скрипт. В примере модели исключены из ежедневного бэкапа; добавьте каталог /opt/localai/models, если хотите копировать и GGUF-файлы. Скрипт также удаляет слишком старые snapshots по политике хранения.
sudo nano /usr/local/sbin/backup-localai.sh
#!/usr/bin/env bash
set -euo pipefail
source /root/.config/restic/localai.env
restic backup \
/opt/localai/compose.yaml \
/opt/localai/.env \
/opt/localai/data \
/opt/localai/models \
/etc/caddy/Caddyfile \
--exclude='.gguf' \
--tag localai
restic forget \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \
--prune
Сделайте скрипт исполняемым, запустите вручную и проверьте список snapshots. Первый backup подтвердит, что доступ к S3, шифрование и права настроены правильно.
sudo chmod 700 /usr/local/sbin/backup-localai.sh
sudo /usr/local/sbin/backup-localai.sh
sudo bash -c 'source /root/.config/restic/localai.env && restic snapshots'
Добавьте ежедневный запуск через cron в 03:30. Логи сохраняются в отдельный файл, который полезно проверять хотя бы раз в неделю.
sudo crontab -e
30 3 /usr/local/sbin/backup-localai.sh >> /var/log/localai-backup.log 2>&1
Проверка восстановления
Бэкап без теста восстановления — только предположение. Раз в месяц восстановите snapshot во временную директорию на другом сервере или локальной машине, проверьте YAML-конфигурации и убедитесь, что .env присутствует.
sudo mkdir -p /tmp/localai-restore
sudo bash -c 'source /root/.config/restic/localai.env && \
restic restore latest --target /tmp/localai-restore'
sudo find /tmp/localai-restore -maxdepth 4 -type f | sort
Безопасные обновления
Не обновляйте LocalAI, Docker, Caddy и модель одновременно. Иначе при ошибке будет сложно понять её причину. Для небольшого сервиса используйте maintenance window: предупредите пользователей, сделайте backup, обновите один компонент, выполните smoke test и только затем переходите дальше.
Обновление LocalAI выглядит так: сначала сохраните текущий image digest, затем скачайте новый образ, пересоздайте контейнер и проверьте API. Если модель или API перестали работать, верните предыдущий тег образа в compose.yaml и снова выполните up -d.
cd /opt/localai
docker inspect localai --format='{{.Image}}'
docker compose pull
docker compose up -d
docker compose ps
curl -fsS http://127.0.0.1:8080/v1/models | jq .
Для rolling-обновления без простоя потребуется минимум два backend-инстанса, балансировщик и достаточный запас RAM. На одном CPU VPS чаще безопаснее плановое короткое окно обслуживания: загрузка одной модели уже потребляет существенную часть памяти.
Troubleshooting и FAQ
Почему LocalAI не видит модель в /v1/models?
Сначала проверьте путь монтирования: каталог хоста /opt/localai/models должен быть подключён в контейнер как /models. Затем посмотрите логи: docker compose logs --tail=200 localai. Частая причина — неверный YAML, несовпадение имени GGUF-файла в параметре model или неправильные права на каталог. Также убедитесь, что файл конфигурации имеет расширение .yaml и находится рядом с моделью.
Почему ответ генерируется очень медленно?
Проверьте нагрузку через htop и docker stats localai. На CPU нормальна скорость в несколько токенов в секунду, особенно для моделей 7B–8B. Уменьшите context_size до 4096, выставьте threads примерно на число доступных физических или виртуальных ядер минус один-два, используйте Q4_K_M вместо Q5/Q6 и выберите модель 3B–4B. Если CPU постоянно загружен на 100%, а пользователей становится больше, нужен более мощный сервер или GPU.
Контейнер перезапускается, а в логах есть out of memory. Что делать?
Это означает, что модели, KV cache и системным процессам не хватило RAM. Выполните free -h и проверьте, использовался ли swap. Уменьшите размер контекста, число одновременно загружаемых моделей и квантизацию. Например, замените 8B Q5 на 8B Q4 или 3B Q4. Не пытайтесь исправить проблему только большим swap: inference станет крайне медленным. Для модели 8B Q4 практичный минимум — 16 ГБ RAM.
Почему HTTPS-сертификат Caddy не выпускается?
Проверьте A-запись домена командой dig +short llm.example.com: она должна указывать на IP сервера. Убедитесь, что порты 80 и 443 открыты в UFW и в панели провайдера, если там есть отдельный firewall. Посмотрите sudo journalctl -u caddy -n 100. Частые причины: DNS ещё не обновился, домен проксируется сторонним CDN с неподходящим режимом TLS или порт 80 занят другим веб-сервером.
API возвращает 401 Unauthorized. Где искать ошибку?
Разделите проверку на уровни. Сначала выполните запрос на 127.0.0.1:8080 без Caddy. Затем проверьте Basic Auth через curl -u, а после — Bearer token. Убедитесь, что значение в .env не содержит лишних пробелов, а контейнер был перезапущен после изменения файла: docker compose up -d --force-recreate. Не передавайте ключ в URL и не сохраняйте его в shell history.
Какой VPS-конфиг минимально подойдёт?
Для знакомства с LocalAI минимально подойдёт VPS с 4 vCPU, 8 ГБ RAM и 50 ГБ SSD. На нём следует запускать одну небольшую модель 1B–4B в Q4-квантизации, контекст 2048–4096 и один активный диалог. Для модели 7B–8B такой конфиг уже пограничный: сервис может работать, но будет медленным или столкнётся с нехваткой памяти. Для стабильной работы 8B выбирайте 8 vCPU и 16 ГБ RAM.
Что выбрать — VPS или dedicated для этой задачи?
VPS подходит для личного ассистента, прототипа, RAG по внутренним документам и команды с несколькими пользователями. Dedicated стоит выбирать при постоянной CPU-нагрузке, требовании к стабильному времени ответа, использовании моделей 14B и больше, 32–64 ГБ RAM или заметной параллельности. Практичный подход — начать с VPS, собрать метрики скорости, памяти и очередей, а затем мигрировать на выделенный сервер только при подтверждённой необходимости.
Как добавить вторую модель без остановки первой?
Скопируйте второй GGUF-файл в /opt/localai/models, создайте для него отдельный YAML с уникальным name и перезапустите контейнер. Учитывайте, что несколько одновременно загруженных моделей суммируют потребление RAM. На 16 ГБ сервере разумно держать одну модель 8B либо несколько компактных моделей. Если модель нужна редко, рассмотрите отдельный инстанс LocalAI или механизм выгрузки неиспользуемых моделей, если он поддерживается вашей версией.
Почему модель отвечает бессвязно, повторяет текст или игнорирует системный промпт?
Обычно проблема в несовместимом chat template, а не в CPU. У каждой instruct-модели свой формат ролей и специальных токенов. Проверьте официальную model card и сравните рекомендуемый шаблон с YAML-файлом LocalAI. Также снизьте temperature до 0.2–0.5, убедитесь, что выбрана именно instruct-версия модели, и не смешивайте шаблон Qwen с Llama или Mistral. Для диагностики отправьте короткий запрос без длинной истории.
Выводы и следующие шаги
Теперь на сервере работает LocalAI с CPU-инференсом, локальной GGUF-моделью, OpenAI-совместимым API, HTTPS и базовой защитой. Такой стек подходит для приватных AI-инструментов и умеренной нагрузки без покупки или аренды GPU.
- Измерьте скорость генерации, использование RAM и реальные задержки на типовых запросах вашей задачи.
- Добавьте RAG: embeddings-модель, vector store и контроль доступа к документам.
- При росте нагрузки перейдите на более быстрые CPU, dedicated-сервер, несколько инстансов за reverse proxy или GPU-инференс.
Перед внедрением в production зафиксируйте версии Docker image и моделей, документируйте SHA256 GGUF-файлов, регулярно проверяйте восстановление бэкапов и не публикуйте API без аутентификации.