MAATRIX / Блог / Open WebUI на Ubuntu 24.04: пошаговая установка

Open WebUI на Ubuntu 24.04: пошаговая установка

Open WebUI на Ubuntu 24.04: пошаговая установка

MAATRIX

Половина руководств по Open WebUI написана под Debian 12 и на Ubuntu 24.04 разваливается в трёх местах: pip install упирается в externally-managed-environment, контейнер не видит Ollama на 127.0.0.1, а конфиг Nginx с директивой http2 on; не даёт сервису стартовать. Ниже — весь путь целиком, от чистой системы до рабочего чата на своём домене под HTTPS, с командами, которые можно копировать построчно.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что ставим и что получится в итоге

Open WebUI — это только интерфейс: чат, история переписки, роли пользователей, загрузка документов и ответы по ним через встроенный RAG. Модели он не считает, это делает движок: локально Ollama, а при желании любой OpenAI-совместимый эндпоинт. Собираем связку «Ollama на хосте плюс Open WebUI в Docker» — так компоненты обновляются отдельно, а гигабайты весов не оказываются внутри контейнера.

Стек на выходе: Ubuntu 24.04 LTS (кодовое имя noble, ядро ветки 6.8), Docker Engine из официального репозитория, Ollama как systemd-сервис на порту 11434, образ ghcr.io/open-webui/open-webui:main с портом 8080 внутри контейнера, Nginx 1.24 и сертификат Let's Encrypt. Проверьте окружение до начала: lsb_release -ds && uname -r && python3 --version на чистой машине отдаст Ubuntu 24.04.3 LTS, 6.8.0-79-generic и Python 3.12.3.

Сразу честно про скорость. Сам Open WebUI почти ничего не потребляет, а вот генерация на процессоре медленная: на 8 vCPU AMD EPYC модель на 8 миллиардов параметров в квантовании Q4_K_M отдаёт 6–8 токенов в секунду, темп медленно печатающего человека. Модель на 4B разгоняется до 12–16 токенов, 14B падает до 3–4. Для личного помощника и работы с документами хватает; для десятка одновременных пользователей нужен GPU.

Подготовка Ubuntu 24.04: три места, где ломаются чужие мануалы

Обновитесь и заведите непривилегированного пользователя вместо постоянной работы из-под root:

apt update && apt upgrade -y
adduser --gecos "" webui && usermod -aG sudo webui
rsync --archive --chown=webui:webui ~/.ssh /home/webui

Первая ловушка именно 24.04: sshd здесь запускается через socket-активацию. Проверьте systemctl is-enabled ssh.socket — если ответ enabled, смена порта в /etc/ssh/sshd_config не сработает, сервис останется на 22. Порт задаётся в юните сокета через systemctl edit ssh.socket: секция [Socket], пустое ListenStream= для сброса унаследованного значения и следом ListenStream=2222. Вход по новому порту проверяйте из второй сессии, не закрывая текущую.

Фаервол пускает внутрь только SSH и веб. Порты 8080 и 11434 в правилах не появляются намеренно: до них ходят через обратный прокси и loopback.

ufw allow 2222/tcp && ufw allow 80,443/tcp && ufw enable

Вторая ловушка noble — PEP 668. Если ставить Open WebUI пакетом, как советуют старые статьи, получите:

error: externally-managed-environment

× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
    python3-xyz, where xyz is the package you want to install.

Это защита: файл /usr/lib/python3.12/EXTERNALLY-MANAGED запрещает pip писать в системный Python. Флаг --break-system-packages существует, но название говорит само за себя. Плюс проект просит Python 3.11 при системном 3.12.3 — придётся тянуть отдельный интерпретатор. Поэтому дальше только Docker.

Третье — swap. В облачных образах 24.04 его обычно нет, и при нехватке памяти ядро молча убивает процесс: в journalctl -k появляется строка Out of memory: Killed process 1417 (ollama). Создайте подкачку на 4 ГБ (fallocate -l 4G /swapfile && chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile) и допишите её в /etc/fstab. Честно: swap спасает от убийства процесса, но не от тормозов — если веса модели уедут на диск, генерация упадёт до единиц секунд на токен.

Развернуть за пару минут

Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть Open WebUI

Docker: ставим из репозитория Docker, а не из docker.io

Соблазн выполнить apt install docker.io велик, но посмотрите через apt-cache policy docker.io, что там лежит: в noble это ветка 24.0.x, отставшая на несколько мажорных версий, и без плагина docker compose — вместо него старый docker-compose на Python. Ставьте из официального репозитория:

apt install -y ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu noble stable" > /etc/apt/sources.list.d/docker.list
apt update && apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Обратите внимание на слово noble: в мануалах под 22.04 там jammy, и apt update отдаст ошибку про отсутствующий Release-файл. Проверка — docker --version && docker compose version, ответ вида Docker version 28.x.x и Docker Compose version v2.x.x. Если вторая команда пишет docker: 'compose' is not a docker command, поставился старый docker.io. Пользователя в группу добавляют через usermod -aG docker webui, но помните: группа docker равносильна root.

Главная неочевидность связки Docker с ufw: опубликованный порт открывается в обход фаервола. Правила Docker попадают в цепочку DOCKER таблицы nat раньше, чем отрабатывает ufw, поэтому -p 8080:8080 выставит Open WebUI в интернет, даже если ufw status показывает Status: active без единого правила для 8080. Решение — публиковать порт на loopback: 127.0.0.1:8080:8080.

Ollama: установка и доступ из контейнера

Ставится одной командой, скрипт сам создаёт пользователя ollama и systemd-юнит:

curl -fsSL https://ollama.com/install.sh | sh && systemctl status ollama --no-pager

По умолчанию Ollama слушает 127.0.0.1:11434. У контейнера свой сетевой неймспейс, и 127.0.0.1 для него — это он сам, поэтому из коробки связка не работает. Откройте сервис на интерфейсы хоста через systemctl edit ollama:

[Service]
Environment="OLLAMA_HOST=0.0.0.0:11434"
Environment="OLLAMA_KEEP_ALIVE=30m"

От внешнего мира порт закрывает ufw: входящие запрещены по умолчанию, правило для 11434 мы не добавляли. OLLAMA_KEEP_ALIVE держит модель в памяти полчаса вместо стандартных пяти минут — иначе после паузы первый ответ ждёт повторной загрузки весов с диска, десятки секунд. После systemctl daemon-reload && systemctl restart ollama проверьте ss -tulpn | grep 11434:

tcp   LISTEN 0  4096   *:11434   *:*    users:(("ollama",pid=1893,fd=3))

Если вместо *:11434 там 127.0.0.1:11434, override не применился — проверьте файл /etc/systemd/system/ollama.service.d/override.conf. Отдельный разбор есть в статье про то, почему Open WebUI не видит Ollama. Веса моделей лягут в /usr/share/ollama/.ollama/models и займут основную часть диска:

МодельТег для pullВес на дискеМинимум RAMСкорость на 8 vCPU
Qwen3 4Bqwen3:4b≈2,6 ГБ6 ГБ12–16 т/с
Llama 3.1 8Bllama3.1:8b≈4,9 ГБ10 ГБ6–8 т/с
Gemma 3 12Bgemma3:12b≈8,1 ГБ16 ГБ3–5 т/с
Phi-4 14Bphi4:14b≈9,1 ГБ20 ГБ3–4 т/с

Скачайте первую модель (ollama pull llama3.1:8b) и сразу замерьте скорость на своём железе: ollama run llama3.1:8b --verbose "Объясни разницу между TCP и UDP". После ответа Ollama печатает статистику, главная строка в ней — eval rate:

load duration:        1.982s
prompt eval rate:     51.30 tokens/s
eval count:           142 token(s)
eval rate:            7.41 tokens/s

Эти 7,41 токена в секунду и увидит пользователь в браузере. Если цифра не устраивает, берите модель поменьше: добавление ядер помогает слабо, генерация на CPU упирается в пропускную способность памяти.

Запускаем Open WebUI

Создайте каталог проекта и ключ: mkdir -p /opt/open-webui && cd /opt/open-webui && openssl rand -hex 32. Вывод пойдёт в WEBUI_SECRET_KEY — он подписывает сессионные токены, и при его смене все пользователи разом получат разлогин. Не задавать его тоже можно: ключ создастся сам в /app/backend/data/.webui_secret_key внутри тома, но при пересоздании тома вы его потеряете. Файл /opt/open-webui/compose.yaml:

services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: open-webui
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:8080"
    environment:
      - OLLAMA_BASE_URL=http://172.17.0.1:11434
      - WEBUI_SECRET_KEY=вставьте_сюда_вывод_openssl
      - WEBUI_URL=https://ai.example.com
      - DEFAULT_USER_ROLE=pending
    volumes:
      - open-webui:/app/backend/data
volumes:
  open-webui:

Адрес 172.17.0.1 — шлюз сети docker0, то есть сам хост со стороны контейнера; уточняется через ip -4 addr show docker0. Запускаем docker compose up -d и смотрим docker compose logs -f. Первый старт долгий: образ занимает около 4 ГБ в распакованном виде, а при первом запуске Open WebUI ещё тянет с Hugging Face модель эмбеддингов sentence-transformers/all-MiniLM-L6-v2 — ещё около 90 МБ. Нормально, если от up -d до готовности прошло 3–5 минут. Проверяем результат:

curl -s http://127.0.0.1:8080/health
{"status":true}
ss -tulpn | grep 8080
tcp LISTEN 0 4096 127.0.0.1:8080 0.0.0.0:* users:(("docker-proxy",pid=2451,fd=7))

Именно 127.0.0.1:8080, а не 0.0.0.0:8080 — второе означает, что вы забыли префикс в секции ports. Откройте интерфейс через SSH-туннель ssh -L 8080:127.0.0.1:8080 webui@сервер -p 2222 и зарегистрируйтесь на http://localhost:8080. Первая учётная запись автоматически становится администратором — создайте её сразу, до того как сервер получит домен. Потом отключите свободную регистрацию; с DEFAULT_USER_ROLE=pending новые пользователи и так попадают в очередь на подтверждение.

Сколько это ест в покое, покажет docker stats --no-stream open-webui: на тестовой машине контейнер в простое держал 1.02GiB / 15.6GiB и 0,1% CPU, почти вся память уходит на модель эмбеддингов. Не нужен поиск по документам — верните её переключением RAG_EMBEDDING_ENGINE=ollama.

Домен, HTTPS и обслуживание

Заведите A-запись для ai.example.com и дождитесь, пока dig +short ai.example.com вернёт IP сервера. Затем apt install -y nginx certbot python3-certbot-nginx. Здесь третья ловушка noble: в репозитории Ubuntu 24.04 лежит nginx/1.24.0, а отдельная директива http2 on; появилась только в 1.25.1. Свежие мануалы её используют, и конфиг падает:

nginx: [emerg] unknown directive "http2" in /etc/nginx/sites-enabled/openwebui:12

На 1.24 пишите по-старому — listen 443 ssl http2;. Конфиг /etc/nginx/sites-available/openwebui:

server {
    listen 443 ssl http2;
    server_name ai.example.com;
    client_max_body_size 100m;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 600s;
        proxy_buffering off;
    }
}

Редирект с 80-го порта допишет certbot. Четыре строки в этом конфиге не декоративные. Upgrade и Connection нужны потому, что Open WebUI держит постоянное соединение через socket.io: без них интерфейс открывается, но ответы не приходят. proxy_buffering off включает потоковую выдачу — иначе Nginx копит ответ и вываливает его целиком в конце. proxy_read_timeout 600s спасает от 504-й: стандартные 60 секунд кончаются раньше, чем медленная CPU-модель дописывает длинный ответ. client_max_body_size 100m нужен для загрузки документов, без него в /var/log/nginx/error.log появится client intended to send too large body, а пользователь увидит 413.

ln -s /etc/nginx/sites-available/openwebui /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx && certbot --nginx -d ai.example.com

Команда nginx -t должна ответить syntax is ok и test is successful, а certbot сам пропишет пути к сертификатам и поставит таймер обновления (systemctl list-timers | grep certbot).

Дальше обслуживание. Обновление — docker compose pull && docker compose up -d, затем docker image prune -f. Честно про тег :main: это плавающая ветка, обновления прилетают часто и иногда ломающие, поэтому при работе на команду зафиксируйте версию явным тегом. Бэкап всей базы — один архив:

docker compose down
docker run --rm -v open-webui_open-webui:/data -v $PWD:/backup alpine \
  tar czf /backup/webui-$(date +%F).tar.gz -C /data .
docker compose up -d

Точное имя тома уточните через docker volume ls — Compose склеивает его из имени каталога проекта и имени тома. Внутри лежит webui.db (SQLite со всей перепиской и пользователями), каталог uploads и векторная база. Модели Ollama в архив не попадают и не должны: они качаются заново.

Какой сервер взять в MAATRIX

Всё упирается в то, где считаются модели.

Минимум, 2 vCPU / 4 ГБ RAM / 40 ГБ NVMe. Годится, если Open WebUI работает единым интерфейсом к внешним API и локальных моделей нет. Ollama здесь не запустится осмысленно: даже 4B-модель требует около 6 ГБ, и вы упрётесь в OOM на первом же запросе.

Рабочий вариант, 8 vCPU / 16 ГБ RAM / 80–100 ГБ NVMe. Конфигурация, под которую написана эта статья. В 16 ГБ комфортно живут модели на 7–8B с запасом под контейнер и файловый кеш. Диск считайте так: образ около 4 ГБ, две модели — ещё 10 ГБ, и это до первого загруженного документа.

С головой, 16 vCPU / 32 ГБ RAM. Нужно для моделей 12–14B, нескольких моделей одновременно или доступа для коллег. Оговорка: рост числа ядер даёт меньше, чем кажется, — после примерно восьми потоков прибавка почти незаметна. Если нужны десятки токенов в секунду и параллельные пользователи, ни один CPU-сервер этого не даст, смотрите в сторону GPU-сервера для инференса LLM.

По локации логичен Лондон (UK), причина сугубо практическая: с российских адресов реестры ghcr.io и Docker Hub отвечают через раз, а Hugging Face, откуда тянется модель эмбеддингов при первом старте, может не ответить вовсе — установка встанет ровно на шаге docker compose up -d. С британской площадки всё качается напрямую, плюс низкий пинг до Европы и понятный периметр GDPR. Пинг Москва — Лондон около 45–60 мс, для чата с потоковой выдачей токенов разница незаметна. Если аудитория в России и данные подпадают под 152-ФЗ, берите российскую локацию, но заложите время на зеркала для образов.

В MAATRIX серверы на AMD EPYC с NVMe и root-доступом есть в UK, США, Франции и России, а Ollama доступна готовым образом в каталоге приложений — разворачивается вместе с сервером, и шаг с установкой движка можно пропустить. Оплата картами российских банков, по СБП, криптовалютой или токеном MAAT; иностранная карта не нужна даже для лондонской площадки.

Развернуть за пару минут

Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть Open WebUI

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Частые вопросы

Можно поставить Open WebUI без Ollama?

Да, это штатный сценарий. Уберите OLLAMA_BASE_URL из compose-файла и укажите OPENAI_API_BASE_URL с ключом — интерфейс заработает поверх любого OpenAI-совместимого API, а требования к серверу упадут до 2 vCPU и 4 ГБ.

Почему не поставить пакетом через pip, как в документации?

На Ubuntu 24.04 системный pip заблокирован механизмом PEP 668 и отдаёт error: externally-managed-environment, а проект просит Python 3.11 при системном 3.12.3. Путь через venv рабочий, но Docker решает обе проблемы одной командой.

Ufw включён, а порт 8080 виден снаружи — почему так?

Docker добавляет правила проброса портов в цепочку DOCKER раньше правил ufw, поэтому публикацию вида -p 8080:8080 фаервол не фильтрует. Публикуйте на loopback (127.0.0.1:8080:8080) и пускайте трафик только через Nginx.

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.