Быстрый запуск Qwen3 на VPS без GPU. 1 CPU, 2GB RAM
Нужна полноценная настройка API с токеном, proxy и внешним доступом? Есть расширенная инструкция: Qwen3 на VPS с API и токеном .
В ней показано, как закрыть llama-server через proxy, добавить токен авторизации и использовать модель через API.
Технические детали
Модель поднималась на VPS от Бегет:
Процессор: 1 виртуальное ядро Intel Xeon
Оперативная память: 2 ГБ
Swap: 2 ГБ
Диск: 15 ГБ NVMe
OS: Ubuntu
Модель: Qwen3-1.7B, квантование Q4_K_M
Запуск: llama.cpp
Команды для запуска модели
mkdir -p /root/llama
cd /root/llama
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
grep -q '^/swapfile ' /etc/fstab || echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
sudo apt update
sudo apt install build-essential git cmake python3-pip python3-venv wget curl -y
git clone https://github.com/ggml-org/llama.cpp
cd llama.cpp
mkdir build
cd build
cmake ..
cmake --build . --config Release -j1
python3 -m venv /root/hfvenv
/root/hfvenv/bin/pip install -U "huggingface_hub[cli]"
mkdir -p /root/qwen3
/root/hfvenv/bin/hf download \
unsloth/Qwen3-1.7B-GGUF \
Qwen3-1.7B-Q4_K_M.gguf \
--local-dir /root/qwen3
/root/llama/llama.cpp/build/bin/llama-cli \
-m /root/qwen3/Qwen3-1.7B-Q4_K_M.gguf \
-t 1 \
-c 1024 \
-n 120 \
--temp 0.7 \
--no-conversation \
-p "Ты мастер текстовой RPG. Отвечай кратко.
/no_think
Игрок: осматриваю комнату.
Мастер:"
После ввода команды '/root/llama/llama.cpp/build/bin/llama-cli \
-m /root/qwen3/Qwen3-1.7B-Q4_K_M.gguf \
-t 1 \
-c 1024 \
-n 120 \
--temp 0.7 \
--no-conversation \
-p "Ты мастер текстовой RPG. Отвечай кратко.
/no_think
Игрок: осматриваю комнату.
Мастер:"'
нужно не забыть нажать Enter )))) потому что сначала я подумал что модель не взлетела и зависла...
Запуск API для генерации текста
Ручной запуск через llama-cli подходит только для тестов. Для работы с ботом или сайтом удобнее поднять HTTP API. В llama.cpp уже есть встроенный сервер llama-server. Он умеет принимать POST-запросы и возвращать JSON с ответом модели.
В отличие от варианта с Flask и subprocess, тут модель постоянно загружена в память. За счёт этого запросы обрабатываются быстрее и стабильнее. Для VPS с 2 ГБ RAM модель Qwen3-1.7B в квантовании Q4_K_M работает нормально.
Ручной запуск API
/root/llama/llama.cpp/build/bin/llama-server \ -m /root/qwen3/Qwen3-1.7B-Q4_K_M.gguf \ -t 1 \ -c 1024 \ --host 0.0.0.0 \ --port 8092
После запуска API начинает слушать порт 8092. Проверить можно через health endpoint:
curl http://127.0.0.1:8092/health
Ожидаемый ответ:
{"status":"ok"}
Проверка генерации текста через curl
В Linux запрос выглядит так:
curl -X POST http://127.0.0.1:8092/completion \
-H "Content-Type: application/json" \
-d '{"prompt":"/no_think Ты мастер RPG. Игрок осматривает комнату.","n_predict":80}'
В Windows cmd лучше писать одной строкой:
curl -X POST http://VPS_IP:8092/completion -H "Content-Type: application/json" -d "{\"prompt\":\"/no_think Ты мастер RPG. Игрок осматривает комнату.\",\"n_predict\":80}"
Ответ приходит в JSON:
{
"content":" Внутри комнаты есть небольшой сундук...",
"tokens_predicted":80,
"timings":{
"predicted_per_second":9.63
}
}

Автозапуск через systemd
Ручной запуск удобен для теста. Но после перезагрузки VPS сервер остановится. Поэтому лучше сразу поднять systemd-сервис.
nano /etc/systemd/system/llm-server.service
Содержимое файла:
[Unit] Description=Qwen3 LLM Server After=network.target [Service] Type=simple ExecStart=/root/llama/llama.cpp/build/bin/llama-server \ -m /root/qwen3/Qwen3-1.7B-Q4_K_M.gguf \ -t 1 \ -c 1024 \ --host 0.0.0.0 \ --port 8092 WorkingDirectory=/root/llama/llama.cpp/build Restart=always RestartSec=3 [Install] WantedBy=multi-user.target
Запуск сервиса:
systemctl daemon-reload systemctl enable llm-server systemctl start llm-server systemctl status llm-server
Проверка после запуска:
curl http://127.0.0.1:8092/health
Просмотр логов:
journalctl -u llm-server -f
PHP-запрос к локальной LLM
<?php
function generateLocalLlmText($prompt, $max_tokens = 80)
{
$url = 'http://VPS_IP:8092/completion';
$data = array(
'prompt' => '/no_think ' . $prompt,
'n_predict' => $max_tokens
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json'
));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 300);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
$response = curl_exec($ch);
if ($response === false) {
$error = curl_error($ch);
curl_close($ch);
return array(
'ok' => false,
'error' => $error
);
}
curl_close($ch);
$json = json_decode($response, true);
if (!is_array($json)) {
return array(
'ok' => false,
'error' => 'bad json',
'raw' => $response
);
}
return array(
'ok' => true,
'text' => trim($json['content'])
);
}
$res = generateLocalLlmText('Ты мастер RPG. Игрок осматривает комнату.');
print_r($res);
?>