Полный справочник по развёртыванию Ubuntu + Ollama + Open WebUI: от статического IP до очистки системы
Чтобы сервер всегда имел один и тот же адрес в локальной сети 192.168.12.x
ip a
Ожидаемый результат: в выводе видите интерфейс со статусом UP и MAC-адресом.
Запомните его имя — дальше подставляете вместо ens33.
Ищите интерфейс со статусом UP и MAC-адресом. В VMware это обычно ens33, в VirtualBox — enp0s3, на реальном железе — eno1, enp3s0 и т.п.
ls /etc/netplan/
sudo cat /etc/netplan/*.yaml
sudo nano /etc/netplan/50-cloud-init.yaml
Привести к виду (заменить ens33 на своё имя):
network:
version: 2
ethernets:
ens33:
addresses:
- "192.168.12.33/24"
routes:
- to: "default"
via: "192.168.12.1"
nameservers:
addresses: [8.8.8.8, 1.1.1.1]
| Строка | Значение |
|---|---|
192.168.12.33/24 | IP-адрес + маска (/24 = 255.255.255.0) |
via: 192.168.12.1 | Шлюз (роутер). Обязательно IP, не маска! |
nameservers | DNS-серверы для доступа в интернет |
Типичная ошибка: указать в via маску 255.255.255.0 вместо адреса шлюза. Тогда система скажет Network is unreachable.
sudo netplan apply
ip a # должен быть 192.168.12.33/24
ip route # строка default via 192.168.12.1
Ожидаемый результат:
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500
inet 192.168.12.33/24 brd 192.168.12.255 scope global ens33
default via 192.168.12.1 dev ens33 proto static
Если видите свой IP и строку default via ... — сеть настроена.
Управлять сервером с другого компьютера
sudo apt update
sudo apt install -y openssh-server
sudo systemctl enable --now ssh
systemctl status ssh --no-pager
Ожидаемый результат: строка Active: active (running) зелёным.
Проверка с другого ПК: ssh — должен пустить в систему.
С другого ПК в сети 192.168.12.x:
ssh @192.168.12.33
Ubuntu Server ставится на LVM-раздел, который по умолчанию занимает не весь диск
df -h # текущий размер корня
sudo vgdisplay # ищем Free PE / Size
Ожидаемый результат:
Если Free PE / Size = 0 / 0 — места в группе томов нет. Используйте раздел 03-бис или добавляйте новый диск.
Если Free PE / Size больше нуля — свободное место есть, можно расширять.
sudo lvdisplay # точное имя тома
sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
sudo resize2fs /dev/ubuntu-vg/ubuntu-lv # для ext4
Если корень на xfs — команда sudo xfs_growfs /.
sudo apt install -y cloud-guest-utils
sudo growpart /dev/sda 3 # номер раздела уточнить в lsblk
sudo pvresize /dev/sda3
sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
sudo resize2fs /dev/ubuntu-vg/ubuntu-lv
df -h /
Когда sda2 — обычный ext4 прямо на диске, а не LVM-том. Именно этот случай на вашем сервере.
lsblk
sudo vgdisplay
vgdisplay видно ubuntu-vg) → используйте раздел 03.lsblk сразу sda2 → /) → используйте этот раздел.lsblk # раздел sda2 40G, а диск sda — 80G → есть куда расти
df -h / # покажет реальный размер ФС (не раздела!)
Ключевой момент: lsblk показывает размер раздела, а df -h — размер файловой системы внутри него. Они могут расходиться. Сначала расширяем раздел, потом — ФС.
sudo apt update
sudo apt install -y cloud-guest-utils
sudo growpart /dev/sda 2
Ожидаемый результат:
Строка CHANGED: partition=2 .... Если NOCHANGE — раздел уже максимального размера.
Ожидаемый вывод:
CHANGED: partition=2 start=... old: size=... end=...
new: size=... end=...
lsblk
В колонке SIZE для sda2 должно быть новое значение (например, 80G вместо 40G).
Ожидаемый результат:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 80G 0 disk
├─sda1 8:1 0 1M 0 part
└─sda2 8:2 0 80G 0 part /
Размер sda2 стал равен размеру диска (80G).
sudo resize2fs /dev/sda2 # для ext4, работает на лету
Ожидаемый результат:
resize2fs 1.47.0 (5-Feb-2023)
Filesystem at /dev/sda2 is mounted on /; on-line resizing required
The filesystem on /dev/sda2 is now 20709376 (4k) blocks long.
Ключевая строка — The filesystem ... is now ... blocks long.
Если корень на xfs — команда sudo xfs_growfs /.
df -h /
Пример вывода до и после:
| Момент | Size | Avail | Use% |
|---|---|---|---|
| До расширения | 40G | 15G | 62% |
После growpart + resize2fs | 79G | ~54G | 31% |
Ожидаемый результат:
Свободно больше 50 ГБ. Этого хватит на Qwen3-Coder-30B (Q5_K_M, ~20 ГБ) плюс запас на временные файлы.
После расширения должно остаться больше 50 ГБ свободных. Этого хватит на модель Qwen3-Coder-30B (Q5_K_M, ~20 ГБ) с запасом на временные файлы и кэш.
Иногда раздел занят так, что growpart отказывается работать. Тогда — через parted:
sudo parted /dev/sda
(parted) print # посмотреть таблицу разделов
(parted) resizepart 2 # выбрать раздел 2
End? [40.0GB]? 100% # указать 100% (или 80GB)
(parted) quit
sudo resize2fs /dev/sda2
df -h /
Тогда — либо добавить новый виртуальный диск в гипервизоре, либо перенести каталог моделей Ollama на другой носитель.
Добавить новый диск:
lsblk # увидеть новый /dev/sdb
sudo pvcreate /dev/sdb
sudo vgextend ubuntu-vg /dev/sdb
sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
sudo resize2fs /dev/ubuntu-vg/ubuntu-lv
df -h /
Перенести модели Ollama на другой носитель:
sudo systemctl stop ollama
sudo mkdir -p /mnt/data/ollama-models
sudo rsync -aP /usr/share/ollama/.ollama/models/ /mnt/data/ollama-models/
Затем добавить в /etc/systemd/system/ollama.service.d/override.conf:
[Service]
Environment="OLLAMA_HOST=0.0.0.0:11434"
Environment="OLLAMA_NUM_PARALLEL=1"
Environment="OLLAMA_MAX_LOADED_MODELS=1"
Environment="OLLAMA_MODELS=/mnt/data/ollama-models"
sudo systemctl daemon-reload
sudo systemctl restart ollama
Удобный консольный файловый менеджер (две панели, как в Norton Commander)
sudo apt install -y mc
mc
Ожидаемый результат: открывается двухпанельный интерфейс.
Сверху видно меню (Left File Command Options Right), снизу — функциональные клавиши 1–10. Выход — F10.
Управление: F3 — просмотр, F4 — редактирование, F10 — выход.
Нужен для запуска Open WebUI в контейнере
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
newgrp docker
docker --version
Ожидаемый результат:
Docker version 27.x.x, build xxxxxxx
Если docker не найдена — перезайдите в сессию (exit → ssh заново).
Движок для запуска локальных LLM
curl -fsSL https://ollama.com/install.sh | sh
newgrp ollama
systemctl status ollama --no-pager
Ожидаемый результат: строка Active: active (running).
Если failed — смотрите логи: journalctl -u ollama -n 50.
sudo mkdir -p /etc/systemd/system/ollama.service.d
sudo nano /etc/systemd/system/ollama.service.d/override.conf
Содержимое файла:
[Service]
Environment="OLLAMA_HOST=0.0.0.0:11434"
Environment="OLLAMA_NUM_PARALLEL=1"
Environment="OLLAMA_MAX_LOADED_MODELS=1"
sudo systemctl daemon-reload
sudo systemctl restart ollama
ss -tlnp | grep 11434 # должно быть 0.0.0.0:11434
Ожидаемый результат:
LISTEN 0 4096 0.0.0.0:11434 0.0.0.0:* users:(("ollama",pid=...,fd=...))
Важно: именно 0.0.0.0:11434, а не 127.0.0.1:11434. Иначе Docker-контейнер не увидит Ollama.
Что делают переменные:
OLLAMA_HOST=0.0.0.0:11434 — слушать все интерфейсы (для Docker);
OLLAMA_NUM_PARALLEL=1 — только один запрос к модели одновременно (чтобы CPU не захлёбывался);
OLLAMA_MAX_LOADED_MODELS=1 — держать в памяти только одну модель.
ollama pull llama3.1:8b
ollama list
ollama run llama3.1:8b # выход: /bye
Ожидаемый результат:
NAME ID SIZE MODIFIED
llama3.1:8b 46e0c10c039e 4.9 GB ...
Прогресс-бар скачивания → строка success.
Общаться с моделью из браузера, в том числе с других ПК
docker pull ghcr.io/open-webui/open-webui:main
Ожидаемый результат: строка Status: Downloaded newer image for ghcr.io/open-webui/open-webui:main.
Если рвётся соединение — попробовать зеркало:
docker pull ghcr.1ms.run/open-webui/open-webui:main
docker run -d -p 3000:8080 \
--add-host=host.docker.internal:host-gateway \
-v open-webui:/app/backend/data \
--name open-webui \
--restart always \
-e OLLAMA_NUM_PARALLEL=1 \
ghcr.io/open-webui/open-webui:main
| Параметр | Значение |
|---|---|
-d | Запуск в фоне |
-p 3000:8080 | Порт 3000 на хосте → 8080 в контейнере |
--add-host=host.docker.internal:host-gateway | Доступ контейнера к хосту (где Ollama) |
-v open-webui:/app/backend/data | Постоянное хранилище данных |
--name open-webui | Имя контейнера |
--restart always | Автозапуск при загрузке системы |
-e OLLAMA_NUM_PARALLEL=1 | Ограничение параллельных запросов |
docker ps # строка с open-webui, статус Up
docker exec -it open-webui curl -s http://host.docker.internal:11434/api/tags
Ожидаемый результат:
CONTAINER ID IMAGE STATUS PORTS NAMES
a1b2c3d4e5f6 ghcr.io/open-webui/open-webui:main Up 2 minutes 0.0.0.0:3000->8080/tcp open-webui
Второй запрос возвращает JSON со списком моделей: {"models":[{"name":"llama3.1:8b",...}]}.
http://192.168.12.33:3000
Ожидаемый результат: страница регистрации Open WebUI.
Создайте первого пользователя — он станет администратором. После входа в списке моделей видна llama3.1:8b.
Первый зарегистрированный пользователь становится администратором.
Llama 3.1 плохо держит русский. Qwen 2.5 справляется заметно лучше
ollama pull qwen2.5:7b # баланс качества и размера
ollama pull qwen2.5:3b # быстрее, для фоновых задач
ollama list
Ожидаемый результат:
NAME ID SIZE MODIFIED
qwen2.5:7b ... ~4.7 GB ...
qwen2.5:3b ... ~1.9 GB ...
llama3.1:8b 46e0c10c039e 4.9 GB ...
В Open WebUI после обновления страницы в списке моделей появились обе версии Qwen.
В Open WebUI: Аватар → Admin Panel → Settings → Models → выбрать модель → System Prompt
Ты — полезный ассистент. Всегда отвечай на русском языке, независимо от языка вопроса. Если пользователь пишет на другом языке — всё равно отвечай на русском. Не переходи на английский без явной просьбы. Технические термины можешь оставлять на английском, но объяснения давай по-русски.
System Prompt применяется только к новым чатам. Существующие чаты его не подхватывают.
В Admin Panel → Settings → Interface → Tasks:
qwen2.5:3b (чтобы фоновые задачи не забивали основную модель)ollama rm llama3.1:8b
Ожидаемый результат: команда возвращает deleted 'llama3.1:8b'.
Освободилось ~4.9 ГБ.
| Критерий | llama3.1:8b | qwen2.5:7b |
|---|---|---|
| Русский язык | Слабо, уходит в английский | Заметно лучше |
| Следование инструкциям | Хорошо | Лучше |
| Размер (Q4) | 4.9 ГБ | ~4.7 ГБ |
| Скорость на CPU | ~3–6 ток/сек | ~3–6 ток/сек |
Методы очистки очередей, зависших задач и починки Open WebUI
Принудительно убивает все активные запросы и освобождает RAM.
ollama ps # посмотреть, что загружено
ollama stop qwen2.5:7b # выгрузить конкретную модель
ollama stop qwen2.5:3b
ollama ps # проверить, что пусто
Ожидаемый результат: ollama ps больше не показывает модель.
RAM освободилась.
Задачи в Open WebUI хранятся в памяти процесса. Перезапуск контейнера гарантированно очищает всё накопленное.
docker restart open-webui
Ожидаемый результат: команда возвращает имя контейнера — open-webui.
Через 5–10 секунд страница в браузере снова отвечает. Зависшие задачи сброшены.
Если перезапуск не помог — удаляем контейнер и создаём заново. Данные в volume сохраняются.
docker stop open-webui
docker rm open-webui
docker run -d -p 3000:8080 \
--add-host=host.docker.internal:host-gateway \
-v open-webui:/app/backend/data \
--name open-webui \
--restart always \
-e OLLAMA_NUM_PARALLEL=1 \
ghcr.io/open-webui/open-webui:main
Если при запуске ошибка 500: Internal Error — конфиг в базе «застрял». Лечится переменной RESET_CONFIG_ON_START=true.
docker stop open-webui
docker rm open-webui
docker run -d -p 3000:8080 \
--add-host=host.docker.internal:host-gateway \
-v open-webui:/app/backend/data \
--name open-webui \
--restart always \
-e RESET_CONFIG_ON_START=true \
-e OLLAMA_NUM_PARALLEL=1 \
ghcr.io/open-webui/open-webui:main
После успешного запуска можно убрать RESET_CONFIG_ON_START=true — иначе настройки будут сбрасываться при каждом перезапуске.
Создайте файл ~/open-webui-run.sh:
nano ~/open-webui-run.sh
#!/bin/bash
docker stop open-webui 2>/dev/null
docker rm open-webui 2>/dev/null
docker run -d -p 3000:8080 \
--add-host=host.docker.internal:host-gateway \
-v open-webui:/app/backend/data \
--name open-webui \
--restart always \
-e OLLAMA_NUM_PARALLEL=1 \
ghcr.io/open-webui/open-webui:main
chmod +x ~/open-webui-run.sh
~/open-webui-run.sh # запуск при проблемах
Внимание: удалит все чаты, настройки и аккаунты внутри Open WebUI. Используйте только если ничего не помогает.
docker stop open-webui
docker rm open-webui
docker volume rm open-webui
# затем запустить контейнер заново
sudo apt clean # кэш пакетов
sudo apt autoremove --purge # ненужные зависимости
sudo journalctl --vacuum-size=100M # логи systemd
df -h # проверить результат
Ожидаемый результат: df -h / показывает больше свободного места.
Обычно освобождается от 500 МБ до нескольких ГБ.
В Admin Panel → Settings → Interface → Tasks:
| Задача | Что делает | Действие |
|---|---|---|
| Title Generation | Название чата | ✅ Оставить |
| Autocomplete Generation | Автодополнение при вводе | ❌ Выключить |
| Tags Generation | Теги для чатов | ❌ Выключить |
| Follow Up Generation | Предлагает вопросы | ❌ Выключить |
| Retrieval / Web Search | Для поиска | ❌ Выключить (если не используете) |
| Image Prompt / Tools | Для картинок | ❌ Выключить (если не используете) |
Если модель бесконечно вызывает один и тот же инструмент (search_calendar_events и т.п.):
Native на Legacy.Если вместо русских названий видны ключи вида settings.personal.general.title:
ru-RU).| Симптом | Что проверить |
|---|---|
| Нет сети | ip a, ip route, cat /etc/netplan/*.yaml |
Network is unreachable | Шлюз в via должен быть IP, не маска |
apt update падает | DNS (cat /etc/resolv.conf), связь (curl -I http://archive.ubuntu.com) |
| Контейнер не видит Ollama | ss -tlnp | grep 11434 → должно быть 0.0.0.0 |
| Модель не появилась в UI | docker restart open-webui, обновить страницу |
Ошибка 500: Internal Error | Запустить с RESET_CONFIG_ON_START=true |
| Модель зациклилась на инструментах | Отключить Built-in Tools в настройках модели |
| Диск заполнен | df -h, sudo vgdisplay |
| Медленные ответы | CPU-режим; GPU даст 10–50× ускорения |
| Сырые ключи вместо текста | Кэш браузера, режим инкогнито |
1. ip a → узнать имя интерфейса
2. sudo nano /etc/netplan/50-cloud-init.yaml → прописать IP/шлюз/DNS
3. sudo netplan apply → применить
4. ip a && ip route → проверить
5. sudo apt update && sudo apt install -y openssh-server mc
6. sudo systemctl enable --now ssh
7. sudo vgdisplay → проверить Free PE
8. sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
9. sudo resize2fs /dev/ubuntu-vg/ubuntu-lv
10. curl -fsSL https://get.docker.com | sudo sh
11. sudo usermod -aG docker $USER && newgrp docker
12. curl -fsSL https://ollama.com/install.sh | sh
13. newgrp ollama
14. sudo mkdir -p /etc/systemd/system/ollama.service.d
15. sudo nano /etc/systemd/system/ollama.service.d/override.conf
→ [Service]
→ Environment="OLLAMA_HOST=0.0.0.0:11434"
→ Environment="OLLAMA_NUM_PARALLEL=1"
→ Environment="OLLAMA_MAX_LOADED_MODELS=1"
16. sudo systemctl daemon-reload && sudo systemctl restart ollama
17. ollama pull qwen2.5:7b && ollama pull qwen2.5:3b
18. docker pull ghcr.io/open-webui/open-webui:main
19. docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway \
-v open-webui:/app/backend/data --name open-webui --restart always \
-e OLLAMA_NUM_PARALLEL=1 ghcr.io/open-webui/open-webui:main
20. Браузер: http://192.168.12.33:3000
21. Настроить System Prompt для русского языка
22. Переключить Task Model на qwen2.5:3b
23. Выключить лишние фоновые задачи (Autocomplete, Tags, Follow Up)
eno1, enp3s0). Узнать: ip a.ollama ps покажет 100% GPU.qwen2.5:14b, qwen2.5:32b.--restart always) поднимутся сами после перезагрузки.open-webui. Посмотреть: docker volume inspect open-webui.docker pull ghcr.io/open-webui/open-webui:main
docker stop open-webui && docker rm open-webui
# затем снова docker run с теми же параметрами
| Параметр | Где | Значение |
|---|---|---|
OLLAMA_NUM_PARALLEL | override.conf | 1 |
OLLAMA_MAX_LOADED_MODELS | override.conf | 1 |
| Context Length | Настройки модели | 2048–4096 |
| Top K (RAG) | Admin → Documents | 2–3 |
| Chunk Size (RAG) | Admin → Documents | 500–800 |
| Autocomplete | Tasks | выключить |