Как установить и настроить llama.cpp на VPS
Инструкции по llama.cpp обычно заканчиваются на cmake --build build, а дальше начинается настоящая жизнь: сборка падает по памяти, бинарь ловит Illegal instruction, скачанный GGUF оказывается текстовым файлом на 130 байт, сервер молча отвечает 503. Разберём установку llama.cpp на VPS без видеокарты — от флагов CMake до systemd-юнита, потоков и защиты порта.
Содержание
- Что даёт llama.cpp и когда он лучше готовых обёрток
- Готовим VPS: пакеты, swap и честный расчёт памяти
- Сборка из исходников: CMake, флаги и грабля с -march=native
- Модели в GGUF: где брать, как не скачать заглушку, как квантовать своё
- Первый запуск: llama-cli, llama-server и проверка API
- Настройка под нагрузку: потоки, контекст, слоты и обвязка
- Какой сервер под llama.cpp взять в MAATRIX
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что даёт llama.cpp и когда он лучше готовых обёрток
llama.cpp — движок инференса на C/C++ поверх библиотеки ggml, работающий с моделями в формате GGUF. Ему не нужны ни Python, ни PyTorch, ни CUDA: каталог бинарников занимает десятки мегабайт, тогда как venv у vLLM переваливает за 5 ГБ и без GPU не стартует вовсе. Это единственный вменяемый способ гонять локальную модель на VPS с четырьмя гигабайтами памяти.
Инструментов несколько: llama-cli для проверки в терминале, llama-server с OpenAI-совместимым API и веб-мордой (он и работает постоянно), llama-bench для замеров, llama-quantize для сжатия весов, llama-gguf-split для томов. Ollama и LM Studio — обёртки над той же ggml: удобнее в первый день и менее управляемы на второй. llama.cpp даёт прямой доступ к тому, что они прячут: потоки на генерацию и на промпт по отдельности, размер контекста, число слотов, тип KV-кэша.
Минусы стоит знать заранее. Семантического версионирования нет: релизы нумеруются сборками вида b9222, и флаги между ними меняются — булев -fa превратился в --flash-attn on|off|auto со значением auto по умолчанию, и старые скрипты ругаются на неизвестный аргумент. Параллелизм слабее специализированных серверов: четырёх пользователей движок держит отлично, сотни сессий — задача для vLLM на видеокарте. Скорость на CPU — единицы и десятки токенов в секунду: хватит личному ассистенту, но не публичному чат-боту.
Готовим VPS: пакеты, swap и честный расчёт памяти
Проверялось на Ubuntu 24.04 (cmake 3.28, gcc 13) и Debian 12 (cmake 3.25, gcc 12): нужен C++17 и CMake не ниже 3.14, штатных пакетов хватает.
sudo apt update
sudo apt install -y build-essential cmake git libcurl4-openssl-dev ccache
Дальше арифметика памяти — источник основного разочарования. RAM складывается из трёх слагаемых: веса + KV-кэш под контекст + вычислительные буферы. Первое известно заранее — вот наши замеры на стенде AMD EPYC 9554 (16 vCPU), снятые через Ollama 0.33.1: это обёртка над той же ggml с теми же GGUF, цифры переносятся напрямую.
| Модель, квант Q4_K_M | Занято в памяти |
|---|---|
| qwen2.5:3b | 2,2 ГБ |
| mistral:7b | 5,0 ГБ |
| qwen2.5:7b | 5,1 ГБ |
| llama3.1:8b | 5,6 ГБ |
Второе считается формулой: на токен контекста уходит 2 × слои × KV-головы × размер головы × 2 байта — двойка в начале это ключи и значения, двойка в конце f16.
- Qwen2.5-7B: 28 слоёв, 4 KV-головы, голова 128 → 56 КиБ на токен. Контекст 8192 стоит 448 МиБ, 32768 — уже 1,75 ГиБ.
- Llama-3.1-8B: 32 слоя, 8 KV-голов, голова 128 → 128 КиБ на токен. Контекст 8192 стоит 1 ГиБ, а обещанные в описании 128k потребуют 16 ГиБ только под кэш, сверх 5,6 ГБ весов.
Вывод: модель 8B в Q4 с контекстом 8k просит около 7 ГБ свободной памяти — на VPS с 8 ГБ это впритык. Подробнее — в статье сколько RAM нужно для Llama.
Swap нужен на сборке: компиляция ggml на двухгигабайтной машине с -j$(nproc) приводит к c++: fatal error: Killed signal terminated program cc1plus.
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile && sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
sudo sysctl -w vm.swappiness=10
Но swap спасает компиляцию, а не инференс: если веса не влезли в RAM, генерация падает до долей токена в секунду. Лечится памятью, а не настройками: что делать при нехватке RAM.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверСборка из исходников: CMake, флаги и грабля с -march=native
Базовый сценарий — три команды и 5–20 минут.
git clone https://github.com/ggml-org/llama.cpp /opt/llama.cpp
cd /opt/llama.cpp
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release -j 4
Обратите внимание на адрес: проект переехал из ggerganov/llama.cpp в ggml-org. Бинарники окажутся в build/bin/.
Could NOT find CURL (missing: CURL_LIBRARY CURL_INCLUDE_DIR) — самая частая ошибка первой сборки: LLAMA_CURL включён по умолчанию, а заголовков libcurl нет. Либо ставите пакет из раздела выше, либо собираете с -DLLAMA_CURL=OFF и теряете загрузку моделей флагом -hf.
Illegal instruction (core dumped) — бинарь собрался, но падает при первом запуске без единой строчки лога. GGML_NATIVE включён по умолчанию и даёт компилятору -march=native: код затачивается под инструкции хоста в момент сборки. На VPS это мина — провайдер переносит виртуалку на другую ноду, и вчера работавший сервер умирает молча. Портируемая сборка та же, что в релизах:
cmake -B build -DCMAKE_BUILD_TYPE=Release \
-DGGML_NATIVE=OFF -DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON
cmake --build build --config Release -j 4
GGML_CPU_ALL_VARIANTS собирает варианты бэкенда без AVX, с AVX2 и с AVX-512, а GGML_BACKEND_DL подгружает нужный при запуске.
llama-server: error while loading shared libraries: libllama.so: cannot open shared object file — после установки: разделяемые библиотеки уезжают в /usr/local/lib, куда линковщик не смотрит.
sudo cmake --install build --prefix /usr/local
sudo ldconfig
llama-server --version
Нужен самодостаточный файл для переноса между машинами — соберите с -DBUILD_SHARED_LIBS=OFF. Собирать вовсе не обязательно: в releases лежат архивы вида llama-b9222-bin-ubuntu-x64.zip. А OpenBLAS (-DGGML_BLAS=ON) ускоряет только промпт и заметен на процессорах без AVX2.
Модели в GGUF: где брать, как не скачать заглушку, как квантовать своё
Со сборкой, знающей curl, llama-server скачает модель сам: llama-server -hf bartowski/Qwen2.5-7B-Instruct-GGUF:Q4_K_M. Файл ляжет в ~/.cache/llama.cpp (каталог задаётся через LLAMA_CACHE). На продакшене удобнее качать явно:
pip install -U "huggingface_hub[cli]"
hf download bartowski/Qwen2.5-7B-Instruct-GGUF \
--include "Qwen2.5-7B-Instruct-Q4_K_M.gguf" \
--local-dir /opt/models
Команда huggingface-cli download из старых мануалов работает, но объявлена устаревшей в пользу hf.
Главная ловушка. Утянете файл через wget по ссылке вида .../blob/main/... — получите не модель, а указатель Git LFS: 130 байт текста, начинающихся с version https://git-lfs.github.com/spec/v1. Запуск закончится так:
gguf_init_from_file: invalid magic characters 'vers'
llama_model_load: error loading model: llama_model_loader: failed to load model from /opt/models/model.gguf
common_init_from_params: failed to load model '/opt/models/model.gguf'
srv load_model: failed to load model
Настоящий GGUF начинается с четырёх байт GGUF, проверка за секунду:
head -c 4 /opt/models/Qwen2.5-7B-Instruct-Q4_K_M.gguf; echo
ls -lh /opt/models/*.gguf
Сверьте и размер: оборванная закачка даёт ту же ошибку, только магия будет корректной. Для прямой ссылки нужен путь resolve, а не blob, плюс wget --content-disposition -c.
Вторая ошибка — llama_model_load: error loading model architecture: unknown model architecture: 'qwen3moe': модель новее бинарника, лечится git pull и пересборкой. Многотомные веса вида model-00001-of-00003.gguf свежие сборки подхватывают сами, если указать первую часть.
Своё квантование требуется, когда подходящего уровня никто не выложил:
python3 -m venv /opt/llama.cpp/venv && source /opt/llama.cpp/venv/bin/activate
pip install -r /opt/llama.cpp/requirements.txt
python3 /opt/llama.cpp/convert_hf_to_gguf.py /opt/hf/Qwen2.5-7B-Instruct \
--outfile /opt/models/qwen2.5-7b-f16.gguf --outtype f16
llama-quantize /opt/models/qwen2.5-7b-f16.gguf \
/opt/models/qwen2.5-7b-Q4_K_M.gguf Q4_K_M
Честно про цену: промежуточный F16 для 7B занимает около 15 ГБ сверх исходных safetensors — держите свободными 35 ГБ. Разумный дефолт — Q4_K_M; ниже спускаться не стоит: первым ломается не английский, а русский и вывод в JSON. Подробнее — в разборе какое квантование выбрать.
Первый запуск: llama-cli, llama-server и проверка API
Убедитесь, что модель читается:
llama-cli -m /opt/models/Qwen2.5-7B-Instruct-Q4_K_M.gguf \
-p "Назови три достопримечательности Лондона" -n 96 -no-cnv
Флаг -no-cnv выключает интерактивный режим: модель отвечает и процесс завершается. В логе смотрите строки n_ctx и n_threads — там видно, что движок решил сам.
llama-server -m /opt/models/Qwen2.5-7B-Instruct-Q4_K_M.gguf \
--host 127.0.0.1 --port 8080 \
-c 8192 -t 8 -np 1 --jinja
Дефолты стоит знать: адрес 127.0.0.1, порт 8080, контекст 4096 токенов. Наружу сервер из коробки не смотрит — это ломают первым же --host 0.0.0.0. Флаг --jinja включает разбор чат-шаблона из GGUF; без него ломаются вызовы инструментов.
curl -s http://127.0.0.1:8080/health
curl -s http://127.0.0.1:8080/props | jq '.default_generation_settings.n_ctx'
curl -s http://127.0.0.1:8080/v1/chat/completions -H 'Content-Type: application/json' \
-d '{"model":"any","messages":[{"role":"user","content":"Одно предложение о Темзе"}]}' \
| jq -r '.choices[0].message.content'
Здоровый сервер отвечает {"status":"ok"}. Пока веса читаются с диска, приходит HTTP 503 и тело {"error":{"code":503,"message":"Loading model","type":"unavailable_error"}} — это не поломка, а загрузка: на холодном кэше страниц для модели в 5 ГБ она занимает десятки секунд. Учитывайте в скриптах деплоя.
Поле model сервер игнорирует: модель у него одна. Кроме OpenAI-совместимых путей есть родные /completion, /props, /slots и /metrics, а по корню / — встроенный веб-интерфейс.
Настройка под нагрузку: потоки, контекст, слоты и обвязка
Самый недооценённый параметр — число потоков. Наш замер на AMD EPYC 9554, 16 vCPU (8 физических ядер плюс HT), qwen2.5:7b в Q4_K_M, Ollama 0.33.1 — тот же ggml-движок, что внутри llama.cpp:
| Потоков | Генерация, ток/с | Обработка промпта, ток/с |
|---|---|---|
| 2 | 5,7 | 12,6 |
| 4 | 7,6 | 31,0 |
| 8 | 7,6 | 61,7 |
| 16 | 7,4 | 68,0 |
| 32 | 0,35 | 10,9 |
Генерация выходит на полку уже на четырёх потоках. Дальше она не растёт: упирается не в процессор, а в пропускную способность памяти — на каждый токен движок читает все веса. Обработка промпта считает матрицы и растёт до 8–16 потоков. Отсюда: -t по числу физических ядер, -tb (потоки на батч) — по числу vCPU.
Потоков больше, чем vCPU, — катастрофа. 32 потока на 16 vCPU дали обвал в двадцать раз: 0,35 токена в секунду вместо 7,4. Никогда не выставляйте -t «с запасом».
Модель важнее числа ядер. На том же стенде при 16 потоках llama3.1:8b дала 12,8 токена в секунду, mistral:7b — 12,1, gemma2:9b — 8,8, qwen2.5:3b — 34,1. Смежные грабли — в статьях Ollama медленно генерирует токены и Ollama не использует все ядра CPU.
Контекст и слоты. Параметр -c задаёт не контекст на запрос, а общий бюджет токенов, делящийся между слотами -np: -c 8192 -np 4 даёт четырём клиентам по 2048 токенов, и на первом же длинном документе прилетит 400: the request exceeds the available context size. try increasing the context size or enable context shift. Контекстный сдвиг по умолчанию выключен — сервер отказывает вместо молчаливого обрезания диалога.
Память под KV-кэш ополовинивает его квантование; при -fa auto (по умолчанию) flash attention включается сам. Плата — деградация на длинных контекстах, заметная в точном цитировании:
llama-server -m /opt/models/Qwen2.5-7B-Instruct-Q4_K_M.gguf \
-c 32768 -np 2 -t 8 -tb 16 \
--cache-type-k q8_0 --cache-type-v q8_0 --jinja
Systemd вместо nohup. У всех аргументов есть парные переменные LLAMA_ARG_*, и юнит выходит компактным:
[Unit]
Description=llama.cpp server
After=network-online.target
[Service]
User=llama
Group=llama
WorkingDirectory=/opt/llama.cpp
Environment=LLAMA_ARG_MODEL=/opt/models/Qwen2.5-7B-Instruct-Q4_K_M.gguf
Environment=LLAMA_ARG_CTX_SIZE=8192
Environment=LLAMA_ARG_THREADS=8
Environment=LLAMA_ARG_HOST=127.0.0.1
Environment=LLAMA_ARG_PORT=8080
EnvironmentFile=-/etc/llama/llama.env
ExecStart=/usr/local/bin/llama-server
Restart=on-failure
RestartSec=5
LimitMEMLOCK=infinity
[Install]
WantedBy=multi-user.target
Ключ кладите в /etc/llama/llama.env строкой LLAMA_ARG_API_KEY=sk-... под chown root:llama и chmod 640. LimitMEMLOCK=infinity нужен при --mlock, иначе в логе будет failed to mlock ... Cannot allocate memory.
Доступ снаружи. Порт 8080 не публикуйте: без --api-key сервер обслуживает любого, кто дотянулся. Схема — ufw allow 22/tcp, ufw allow 443/tcp, ufw deny 8080/tcp, наружу только Nginx с TLS. Для стриминга обязательны две директивы, иначе ответ придёт одним куском в конце:
location /llm/ {
proxy_pass http://127.0.0.1:8080/;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off;
proxy_read_timeout 600s;
}
Какой сервер под llama.cpp взять в MAATRIX
llama.cpp упирается в память и её пропускную способность, а не в частоту, — это видно по таблице выше. Конфигурацию подбирают от модели и контекста, а не от числа ядер.
Честный минимум: 2 vCPU, 4 ГБ RAM, 40 ГБ NVMe. Влезает модель 3B в Q4 — по нашему замеру 2,2 ГБ весов — плюс контекст 4096 и место под сборку. Но два ядра не дотягивают до полки, которая начинается на четырёх: это площадка для знакомства и фоновых задач по расписанию.
Рабочий вариант: 4 vCPU, 8 ГБ RAM, 80 ГБ NVMe. Под модели 7–8B в Q4_K_M: 5,0–5,6 ГБ весов, контекст 8–16k, запас на систему и сборку. Точка входа для личного ассистента, помощника по коду или обработки документов.
Комфорт: 8 vCPU, 16 ГБ RAM, 160 ГБ NVMe. Здесь можно позволить 7–8B в Q5_K_M или Q6_K ради качества, контекст 32k, два-три слота и соседей — векторную базу, веб-интерфейс. Диск не про запас: пять GGUF набирают 30–40 ГБ незаметно.
Где llama.cpp честно не подходит: сотни пользователей и сотни токенов в секунду. Это уже GPU-сервер под инференс — ядрами тут не добрать по физике памяти.
Локация — Великобритания, Лондон. Инференс идёт локально, и зарубежный адрес нужен не ради чужого API, а ради двух вещей: веса с Hugging Face тянутся напрямую, без прокси и обрывов на многогигабайтных файлах, а RTT от Москвы до Лондона держится в районе 45–60 мс — на стриминге незаметно. Европейской аудитории UK даёт минимальную задержку, а тексты клиентов никуда не уходят.
Про установку честно: llama.cpp в каталоге apps.maatrix.io нет — сервер приезжает чистым, с Ubuntu 24.04 или Debian 12, и собирается по разделам выше за 10–20 минут. Зато в каталоге есть родственные сервисы: они ставятся автоматически при заказе, доступы появляются в кабинете — Ollama, AnythingLLM и Dify для интерфейса и RAG, LiteLLM как шлюз к вашему llama-server. Оплата — картой российского банка, по СБП, криптой или токеном MAAT. Конфигурацию выбирают на странице аренды VPS.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Бинарник падает с Illegal instruction (core dumped) без единой строчки лога. Что делать?
GGML_NATIVE=ON по умолчанию даёт -march=native, и после миграции виртуалки набор инструкций перестаёт совпадать. Пересоберите портируемо: cmake -B build -DGGML_NATIVE=OFF -DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON.
Сколько потоков ставить в -t на VPS с 4 vCPU?
Четыре, и никогда не больше числа vCPU: по нашему замеру на 16 vCPU генерация выходит на полку уже на четырёх потоках, а 32 потока обрушили скорость с 7,4 до 0,35 токена в секунду. Промпт можно отдать всем ядрам флагом -tb.
Сервер отвечает 400 про available context size, хотя контекст задан 8192. Почему?
-c — общий бюджет токенов, делящийся между слотами -np: при -c 8192 -np 4 клиенту достаётся 2048. Увеличьте -c кратно числу слотов, уменьшите -np или включите сдвиг флагом --context-shift.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.