Оригинал: https://timofei-ermolaev.ru/courses/open-webui/drugie-sposoby/open-webui-v-yandeks-cloud/

# Open WebUI на виртуальной машине Яндекс Cloud

Поможем запустить Open WebUI на виртуальной машине Яндекс Cloud: подготовим Linux и Docker Compose, ограничим доступ и разберём хранение данных и расходы.

[![Тимофей Ермолаев](https://timofei-ermolaev.ru/_astro/timofei-ermolaev-portrait.s0mCFw-J_Z1x8STQ.webp)](<https://timofei-ermolaev.ru/ob-avtore/>)

[Тимофей Ермолаев](<https://timofei-ermolaev.ru/ob-avtore/>) Директор по информационным технологиям (CIO)

**Опубликовано**

19 октября 2026 г.

**Обновлено**

19 октября 2026 г.

**На урок**

35 мин

**Тема**

[Другие способы развёртывания](<https://timofei-ermolaev.ru/courses/open-webui/drugie-sposoby/>)

## После урока вы сможете

- Выбрать обычную Linux VM и отличать её от готового приложения Marketplace
- Ограничить SSH-доступ и применить знакомый маршрут Docker Compose
- Открыть личный интерфейс через SSH-туннель и отдельно проверить модель
- Различать остановку контейнера, VM и удаление диска при оценке расходов

**Проверяемый результат:** Читатель умеет подготовить новый личный экземпляр Open WebUI на одной VM, проверить закрытый доступ через SSH-туннель и найти постоянные данные и оплачиваемые ресурсы. Реальное выполнение и ответ модели требуют отдельных проверок в своём облаке.

Как оставить Open WebUI работать, когда ноутбук выключен? Для этого можно развернуть отдельный личный экземпляр на виртуальной машине в облаке. Мы арендуем сервер в Яндекс Cloud, подготовим на нём Linux, запустим знакомый проект Docker Compose и откроем веб-интерфейс со своего компьютера через защищённый SSH-туннель. Если выключить ноутбук, туннель закроется, а виртуальная машина и контейнер в облаке продолжат работать.

## Зачем переносить Open WebUI на отдельную VM

В этом уроке мы соберём чистую установку на новой виртуальной машине Compute Cloud с образом [Ubuntu 24.04 LTS x86\_64](<https://yandex.cloud/ru/docs/compute/operations/images-with-pre-installed-software/get-list>) , установим официальный [Docker Engine с плагином Compose](<https://docs.docker.com/engine/install/ubuntu/>) и запустим контейнер [Open WebUI](<https://docs.openwebui.com/getting-started/quick-start/>) фиксированной версии [`v0.12.3`](<https://github.com/open-webui/open-webui/releases/tag/v0.12.3>) . Это полностью отдельная среда с пустой базой данных, поэтому чаты и настройки с вашего домашнего компьютера сюда автоматически не перенесутся. Готовые образы из облачного маркетплейса или кластеры Managed Kubernetes для одного личного интерфейса нам не понадобятся.

Облачный провайдер предоставляет физическую инфраструктуру, сеть и блочное хранилище. Настраивать операционную систему, правила входа, обновления Docker и резервные копии предстоит владельцу. Вычисление ответов мы оставим внешнему поставщику по API, поэтому дорогая видеокарта (GPU) или локальный сервер моделей вроде Ollama на этой машине не нужны.

Процедура сверена с официальной документацией Яндекс Cloud, Docker и исходным кодом Open WebUI `v0.12.3` (включая проверку манифеста образа в реестре GHCR), однако сама виртуальная машина, внешние вызовы API и восстановление из снимка диска при подготовке текста не запускались. Все состояния системы и ответы команд ниже служат ориентирами: их предстоит проверить на вашей машине.

При работе с облачной установкой расходы делятся на два независимых счёта. Первый счёт выставляет Яндекс Cloud за инфраструктуру: вычислительные ресурсы виртуальной машины, объём загрузочного диска, снимки данных и использование публичного IP-адреса с исходящим трафиком по [правилам тарификации Compute Cloud](<https://yandex.cloud/ru/docs/compute/pricing>) и [Virtual Private Cloud](<https://github.com/yandex-cloud/docs/blob/master/md-docs/vpc/pricing.md>) . Второй счёт выставляет поставщик языковой модели, если вы подключаете платный внешний API.

Раз мы выбираем собственную виртуальную машину, сначала определим рабочий каталог в облаке, условия оплаты и безопасный способ сетевого входа.

## Подготовим облако, ключ и сетевые правила

Перед созданием сервера выберем облачный каталог, подготовим пару SSH-ключей и настроим группу безопасности. В каталоге будут собраны ресурсы и права управления. Ключи понадобятся для входа с вашего компьютера в Linux, а группа безопасности ограничит сетевые подключения к машине.

### Проверим каталог, права и расходы

Для работы в консоли Яндекс Cloud понадобится активный платёжный аккаунт, облако и выбранный каталог (folder). Каталог объединяет созданные ресурсы и права доступа к ним. Он не служит платёжным счётом или лимитом бюджета. Перед созданием машины загляните в правую панель консоли управления: там отображается предварительная оценка стоимости (estimate) для выбранной конфигурации процессора, памяти, диска и публичного адреса.

В своём или общем облаке сначала проверим права оператора. Для создания машины по [документации Compute Cloud](<https://yandex.cloud/ru/docs/compute/operations/vm-create/create-linux-vm>) требуются роли `compute.editor` на каталог и `vpc.publicAdmin` для назначения публичного IP-адреса. Это права человека-оператора в консоли облака; прикреплять к самой виртуальной машине сервисный аккаунт для работы Open WebUI не нужно.

Для входа в Linux мы используем подготовленную заранее пару SSH-ключей. Как описано в [руководстве по подключению к ВМ по SSH](<https://yandex.cloud/ru/docs/compute/operations/vm-connect/ssh>) , в стандартных образах Linux вход по паролю отключён по умолчанию. При создании машины вы передадите в форму только открытую (публичную) часть ключа и укажете желаемый логин обычного пользователя. В примерах этого урока мы используем условное имя `courseuser` и путь к приватному ключу `~/.ssh/yc-openwebui`. Подставьте вместо них свои значения. Закрытый ключ всегда остаётся на вашем компьютере.

Яндекс Cloud также предлагает централизованный доступ OS Login. В этом уроке мы выбираем стандартный вариант со статическим SSH-ключом в метаданных машины, но если политика вашей организации принудительно требует OS Login, отключать её ради урока не следует. Выполняйте вход по правилам вашей компании. Никогда не передавайте секретные ключи приложения или пароли через поле пользовательских метаданных (`user-data`): согласно [описанию сервиса метаданных](<https://yandex.cloud/ru/docs/compute/concepts/metadata/directories>) , эти данные доступны для чтения любому пользователю или процессу внутри виртуальной машины.

### Разрешим вход только со своего адреса

Чтобы интерфейс управления машиной не был открыт всему интернету, проверим облачную сеть с подсетью в выбранной зоне доступности и создадим отдельную пользовательскую [группу безопасности (Security Group)](<https://yandex.cloud/ru/docs/vpc/operations/security-group-create>) . Мы привяжем её к сетевому интерфейсу виртуальной машины вместо широкой группы по умолчанию (`default`).

Настроим правила трафика по следующей схеме:

| Направление | Протокол и порт | Источник или назначение | Зачем нужно это правило |
| --- | --- | --- | --- |
| Входящий (Inbound) | `TCP`, порт `22` | `ВАШ_ПУБЛИЧНЫЙ_IPv4/32` | Доступ по SSH и работа туннеля только с вашего текущего интернет-адреса |
| Исходящий (Outbound) | Любой (`Any`), все порты | `0.0.0.0/0` | Обращение самой машины к DNS, пакетам Ubuntu, реестру образов `ghcr.io` и внешнему API модели |

Маска `/32` во входящем правиле означает один конкретный IPv4-адрес вашего домашнего или офисного подключения. Входящие порты `80`, `443`, `3000` или `8080` мы в группу безопасности не добавляем: веб-интерфейс не должен публиковаться в интернет напрямую. Разрешение на весь исходящий трафик (`0.0.0.0/0`) упрощает установку пакетов и скачивание Docker-образов в учебном примере. Для корпоративной среды оно не служит образцом минимальных привилегий.

Убедитесь, что к сетевому интерфейсу будущей машины не привязана вторая группа безопасности с более широкими входящими правилами. Если интернет-провайдер сменит ваш внешний IP-адрес, подключение по SSH будет завершаться по тайм-ауту. В этом случае обновите адрес с маской `/32` в настройках группы безопасности в консоли облака.

Когда известны рабочий каталог, разрешённый адрес и способ входа, создадим саму виртуальную машину с обычным образом операционной системы и сетевым диском.

## Создадим Ubuntu VM и войдём по SSH

Перейдём в раздел **Compute Cloud** консоли управления и создадим виртуальную машину по [официальной инструкции создания Linux-ВМ](<https://yandex.cloud/ru/docs/compute/operations/vm-create/create-linux-vm>) :

1. В блоке выбора образа укажите стандартный образ **Ubuntu 24.04 LTS** архитектуры `x86_64` из [списка публичных образов](<https://yandex.cloud/ru/docs/compute/operations/images-with-pre-installed-software/get-list>) .
2. Перед выбором вычислительной платформы, vCPU, RAM и размера диска вернёмся к уроку [«Требования к Open WebUI»](<https://timofei-ermolaev.ru/courses/open-webui/start/trebovaniya/>) . Даже при внешнем API самой VM нужны процессор и память для приложения и базы данных, а на диске должно хватить места для Ubuntu, Docker-образа и данных. Если документы или голос обрабатываются на этой же VM, учтём и их нагрузку. По этой оценке выберем конфигурацию и проверим её стоимость в калькуляторе консоли. Универсальный минимум для нашего сценария здесь не задаём.
3. В настройках хранилища выберите загрузочный диск типа `network-ssd`. Как поясняет [документация по дискам Compute Cloud](<https://yandex.cloud/ru/docs/compute/concepts/disk>) , это надёжный сетевой блочный накопитель: для операционной системы он выглядит как обычный локальный диск, на котором разместится файловая система Linux и тома Docker (не путайте его с общей сетевой папкой NFS). Проверьте галочку автоматического удаления диска вместе с виртуальной машиной: от неё зависит, останется ли диск после удаления самой ВМ.
4. В сетевых настройках укажите подсеть, назначьте **Публичный IP-адрес** (автоматически / динамический) и выберите созданную ранее пользовательскую группу безопасности. Благодаря механизму [облачного NAT](<https://yandex.cloud/ru/docs/compute/concepts/network>) публичный IPv4-адрес сопоставляется с внутренним адресом машины, обеспечивая и входящий SSH-доступ, и выход в интернет без настройки отдельного NAT-шлюза.
5. В блоке доступа выберите вариант **SSH-ключ**, введите выбранный логин (в нашем примере `courseuser`) и вставьте открытую часть вашего ключа.

После нажатия кнопки создания дождитесь, пока статус машины сменится на `RUNNING`, и выпишите назначенный ей публичный IPv4-адрес. Статус `RUNNING` означает запуск виртуального оборудования. Возможность входа и работу приложений внутри предстоит проверить отдельно.

При самом первом подключении клиент SSH покажет отпечаток ключа сервера (fingerprint) и спросит, доверяете ли вы этому хосту. Прежде чем вводить `yes`, сверьте показанный отпечаток с реальным отпечатком вашей новой машины. Согласно [инструкции по проверке подключения](<https://yandex.cloud/ru/docs/compute/operations/vm-connect/ssh>) , эталонные строки публикуются внутри блока `BEGIN SSH HOST KEY FINGERPRINTS` в выводе последовательного порта (serial port output) виртуальной машины в консоли облака. Если отпечатки не совпадают, прервите подключение и выясните причину расхождения, прежде чем продолжать.

На своём компьютере выполните вход по SSH (заменив путь к ключу, логин `courseuser` и `VM_IP` на ваши реальные значения):

```
ssh  -i  ~/.ssh/yc-openwebui  courseuser@VM_IP  
```

Если команда зависает и завершается ошибкой тайм-аута, не пытайтесь пересоздавать машину. Проверьте по очереди четыре вещи: находится ли ВМ в статусе `RUNNING`, правильно ли скопирован её текущий публичный IP, привязана ли к сетевому интерфейсу ваша группа безопасности и совпадает ли ваш нынешний внешний IPv4-адрес с правилом `/32` в этой группе.

После входа по SSH команды выполняются в оболочке новой виртуальной машины. Теперь подготовим в ней движок контейнеров и файлы проекта.

## Запустим один проект Docker Compose на VM

Внутри виртуальной машины мы повторим знакомую схему запуска через Docker Compose, но зафиксируем точную версию образа и привяжем сетевой порт так, чтобы веб-интерфейс не оказался открыт на внешнем интерфейсе сервера.

### Подготовим движок и файлы

Сначала установим Docker на новой машине. Для настройки репозиториев `apt` откройте урок [«Подготовка Docker для Linux»](<https://timofei-ermolaev.ru/courses/open-webui/install/podgotovka-docker-dlya-linux/>) и выполните его шаги **внутри открытой SSH-сессии на виртуальной машине**, а не на своём ноутбуке. Установка из официального репозитория даст актуальную версию Docker Engine: как отмечено в [документации по публикации портов Docker](<https://docs.docker.com/engine/network/port-publishing/>) , начиная с выпуска Docker Engine `28.0.0` устранена особенность, позволявшая обращаться к привязанным к `localhost` портам из того же локального сегмента сети (L2). Любая актуальная версия от `28.0.0` и новее нам подходит.

В SSH-терминале VM после подготовительного урока проверим готовность инструментов:

```
sudo  docker  version  
sudo  docker  compose  version  
openssl  version  
```

Ожидается, что `sudo docker version` покажет версии и клиента (`Client`), и работающего демона (`Server`), вторая команда вернёт версию плагина Compose, а третья подтвердит наличие утилиты OpenSSL. В этом уроке мы единообразно используем префикс `sudo` перед всеми командами `docker`, а работу с обычными файлами и папками выполняем от имени своего пользователя `courseuser`.

На VM от выбранного обычного пользователя создадим каталог проекта и перейдём в него:

```
mkdir  -p  ~/projects/open-webui  
cd  ~/projects/open-webui  
```

Логика работы с файлами проекта подробно разбиралась в базовом уроке [«Установка Open WebUI через Docker Compose»](<https://timofei-ermolaev.ru/courses/open-webui/install/docker-compose/>) . Для облачной виртуальной машины используем конфигурацию без `extra_hosts`, локальной Ollama и проброса GPU.

На VM сохраните как `~/projects/open-webui/compose.yaml` следующий файл:

```
name :  open-webui  
 
services :  
  open-webui :  
    image :  ghcr.io/open-webui/open-webui:v0.12.3  
    ports :  
      -  "127.0.0.1:3000:8080"  
    volumes :  
      -  open-webui:/app/backend/data  
    env_file :  
      -  ./open-webui.env  
    restart :  unless-stopped  
 
volumes :  
  open-webui :  
```

Разберём, как эта конфигурация задаёт версию, доступ и хранение данных:

- **Тег `v0.12.3`** привязывает инструкцию к выбранному выпуску и проверенному коду первичной регистрации вместо плавающего тега `:main`.
- **Публикация порта `"127.0.0.1:3000:8080"`** связывает внутренний порт контейнера `8080` только с петлевым (loopback) интерфейсом самой виртуальной машины. Если не указать `127.0.0.1`, Docker опубликует порт на всех сетевых интерфейсах в обход стандартных правил локального файрвола `ufw`. Привязка к `127.0.0.1` закрывает порт от сети извне. Однако к нему по-прежнему могут обращаться любые пользователи и процессы, уже получившие доступ внутрь самой виртуальной машины.
- **Именованный том `open-webui:/app/backend/data`** при имени проекта `open-webui` создаёт в системе Docker том `open-webui_open-webui`, который хранится на загрузочном диске `network-ssd` нашей машины.
- **Директивы `env_file` и `restart: unless-stopped`** подключают файл с секретным ключом и поручают демону Docker перезапускать контейнер при сбоях или после перезагрузки сервера.

По умолчанию аутентификация в приложении включена (`WEBUI_AUTH=true`), и отключать её нельзя. Согласно [справочнику переменных окружения](<https://docs.openwebui.com/reference/env-configuration/>) , для сохранения сессий и зашифрованных настроек между пересозданиями контейнера необходим постоянный ключ `WEBUI_SECRET_KEY`.

На VM в каталоге проекта, без `sudo`, сгенерируем файл окружения с этим ключом:

```
if  [  !  -e  open-webui.env ];  then  
  (  
    umask  077  
    webui_key = $( openssl  rand  -hex  32 ) &&  
    printf  'WEBUI_SECRET_KEY=%s\n'  " $webui_key "  >  open-webui.env  
  )  
fi  
```

Условие `if [ ! -e open-webui.env ]` не даёт перезаписать существующий файл. Этот блок предназначен для нашей новой установки: наличие старой базы данных он не проверяет. Команда `umask 077` ограничит чтение файла для других пользователей системы. Содержимое `open-webui.env` не выводим в терминал, чтобы секрет не попал в журналы.

### Проверим конфигурацию и готовность

Теперь проверим синтаксис файла Compose, скачаем образ, запустим контейнер и проверим готовность по локальному адресу.

На VM в `~/projects/open-webui` выполните команды по очереди, переходя к следующей только при отсутствии ошибок на предыдущем шаге:

```
sudo  docker  compose  config  --quiet  
sudo  docker  compose  pull  
sudo  docker  compose  up  -d  
sudo  docker  compose  ps  --all  
curl  --fail  --silent  --show-error  --max-time  10  http://127.0.0.1:3000/ready  
```

Флаг `--quiet` проверяет корректность `compose.yaml` и наличие `open-webui.env`, не распечатывая в терминал секретный ключ. После `pull` и `up -d` таблица `ps --all` должна показать контейнер в состоянии `Up`. Последняя команда обращается к служебному маршруту `/ready`: как видно в [исходном коде `main.py` версии `v0.12.3`](<https://raw.githubusercontent.com/open-webui/open-webui/v0.12.3/backend/open_webui/main.py>) , этот обработчик проверяет завершение инициализации приложения и выполняет тестовый запрос `SELECT 1` к базе данных (а также проверяет Redis, если он настроен). При успехе `curl` вернёт JSON-ответ со значением `"status":true`. Маршрут `/ready` подтверждает работоспособность веб-сервера и базы данных на VM. Подключение к языковой модели он не тестирует.

Если на шаге `curl` или в выводе `ps --all` видна ошибка (или приложение ещё не успело инициализировать базу при первом старте), посмотрите последние строки журнала.

На VM, только при ошибке запуска, выполните:

```
sudo  docker  compose  logs  --tail=100  open-webui  
```

Изучите вывод локально: если вы решите скопировать фрагмент лога для поиска помощи, предварительно убедитесь, что в текст не попали чувствительные данные вашей среды.

Если проверка готовности прошла, приложение отвечает внутри виртуальной машины. Теперь подготовим путь к нему из браузера на вашем компьютере.

## Откроем личный интерфейс и создадим администратора

Почему мы будем набирать в браузере адрес `127.0.0.1`, если приложение работает в облаке? Вместо публикации порта в интернет создадим зашифрованный канал с помощью [проброса локальных портов SSH (`-L`)](<https://man.openbsd.org/ssh.1>) . Подробно сетевая механика этого приёма разобрана в уроке [«Open WebUI на удалённом сервере»](<https://timofei-ermolaev.ru/courses/open-webui/drugie-sposoby/open-webui-na-servere/>) , а здесь проследим путь запроса:

| Участок пути | Адрес и порт | Что происходит на этом шаге |
| --- | --- | --- |
| Ваш компьютер | `127.0.0.1:13000` | Браузер обращается к свободному локальному порту вашего ноутбука или ПК |
| SSH-соединение | Порт `22` на `VM_IP` | Клиент SSH заворачивает трафик из порта `13000` в зашифрованный канал до облачной VM |
| Виртуальная машина | `127.0.0.1:3000` | SSH-сервер на VM передаёт запрос на loopback-порт `3000`, который слушает Docker |
| Контейнер Docker | Внутренний порт `8080` | Docker перенаправляет пакет внутрь контейнера с Open WebUI |

Мы выбрали на компьютере порт `13000`, чтобы он не конфликтовал с возможными локальными установками на порту `3000` и наглядно отличался в командах от порта виртуальной машины.

Откройте новое окно терминала на компьютере с браузером. Выполните в нём команду создания туннеля, подставив свои ключ, логин и IP-адрес машины. Не вводите эту команду внутри SSH-сессии на VM:

```
ssh  -i  ~/.ssh/yc-openwebui  -N  -o  ExitOnForwardFailure=yes  -L  127.0.0.1:13000:127.0.0.1:3000  courseuser@VM_IP  
```

Флаг `-N` указывает SSH не открывать командную оболочку, а параметр `ExitOnForwardFailure=yes` заставит команду сразу завершиться с ошибкой, если порт `13000` на компьютере уже занят. При успешном подключении команда останется работать без приглашения ввода. Оставьте это окно терминала открытым.

Если команда сразу завершилась с жалобой на занятый порт (`Address already in use`), проверьте, не запущен ли у вас дублирующий туннель в соседнем окне. Если порт `13000` занят другой программой на компьютере, замените в команде и в адресе браузера только первое число (например, на `13001`), оставив `127.0.0.1:3000` без изменений. Если же сервер сообщает, что перенаправление портов запрещено административной политикой (`administratively prohibited`), потребуется обратиться к администратору вашей инфраструктуры.

Теперь откройте в браузере своего компьютера следующий адрес:

```
http://127.0.0.1:13000  
```

Поскольку мы развернули совершенно новую установку с чистым томом, вы должны увидеть приглашение создать первую учётную запись администратора. Если вместо создания первого пользователя неожиданно открылась форма обычного входа в уже существующий аккаунт, немедленно остановитесь и проверьте, к тому ли серверу и Docker-тому вы подключились.

Создайте учётную запись администратора. Общие правила работы с учётными записями описаны в материале [«Первый вход и настройка прав администратора»](<https://timofei-ermolaev.ru/courses/open-webui/configure/first-admin/>) , но у выбранной версии `v0.12.3` есть особенность, подтверждённая в [исходном коде роутера аутентификации `auths.py`](<https://raw.githubusercontent.com/open-webui/open-webui/v0.12.3/backend/open_webui/routers/auths.py>) : сразу после регистрации самого первого пользователя обработчик `signup_handler` назначает ему роль `admin` и автоматически сохраняет в настройках приложения состояние `ui.enable_signup = False`, закрывая дальнейшую самостоятельную регистрацию.

Задавать переменные окружения `ENABLE_SIGNUP` или автоматический bootstrap через `WEBUI_ADMIN_EMAIL` в нашей схеме не нужно. Как поясняет [документация по переменным окружения](<https://docs.openwebui.com/reference/env-configuration/>) , `ENABLE_SIGNUP` относится к классу `ConfigVar`: после первого старта значение, сохранённое в базе данных, имеет приоритет над переменной окружения. Проверим сохранённую политику и повторный вход через интерфейс:

1. Зайдите в панель администратора и убедитесь, что переключатель регистрации новых пользователей находится в выключенном состоянии (если в будущем вам понадобится изменить эту политику, меняйте её именно здесь, в интерфейсе администратора).
2. Откройте `http://127.0.0.1:13000` в новом приватном (инкогнито) окне браузера и убедитесь, что ссылка создания нового аккаунта отсутствует.
3. Выйдите из учётной записи в основном окне и снова войдите под своим логином и паролем администратора.

Если эти проверки прошли, личный вход работает. Платный API модели для этого не требовался. Теперь проверим соединение виртуальной машины с внешним поставщиком языковой модели.

## Подключим внешнюю модель и проверим данные

В нашей схеме виртуальная машина без видеокарты и локальных весов модели не генерирует текст. Open WebUI отправляет запросы к выбранному внешнему сервису и сохраняет историю диалогов на облачном диске.

Подключите внешнюю модель на уровне администратора (серверное соединение, а не прямое подключение из браузера пользователя) по инструкции из урока [«Подключение OpenAI-совместимого API»](<https://timofei-ermolaev.ru/courses/open-webui/configure/openai-compatible/>) . Секретный ключ API вводится владельцем непосредственно в настройки своего интерфейса. Учитывайте, что успешная работа зависит от внешних условий: выбранный API-провайдер должен быть доступен по сети с IP-адреса вашей виртуальной машины в Яндекс Cloud, а ваш ключ должен иметь доступ к выбранной модели. Для платного API также нужен достаточный баланс.

Разделим проверку модели и проверку сохранности данных на два независимых шага:

- **Проверка ответа модели (при наличии прав и бюджета API).** Если у вас есть активный ключ и вы готовы выполнить тарифицируемый вызов, отправьте в чат один короткий обезличенный запрос без личных или корпоративных тайн. Только фактически полученный ответ модели подтверждает, что путь «VM → внешний API» работает исправно. Если вы пока не вводили ключ или не отправляли запрос, честно зафиксируйте для себя текущий статус: *интерфейс на VM готов и проверен, но подключение к модели ещё не тестировалось*.
- **Проверка сохранения данных при перезапуске контейнера.** Независимо от того, вызывали ли вы платную модель, проверим, что база данных на диске `network-ssd` сохраняет изменения. Не ориентируйтесь на пустой неотправленный черновик чата. Сохраните в интерфейсе явное изменение (например, созданную настройку подключения, системный промпт или реально отправленный диалог).

На VM в каталоге проекта выполните перезапуск контейнера и дождитесь ответа о готовности:

```
sudo  docker  compose  restart  
curl  --fail  --silent  --show-error  --max-time  10  http://127.0.0.1:3000/ready  
```

Если `curl` в первые секунды после рестарта вернул ошибку соединения, подождите немного и повторите запрос (при затяжной ошибке проверьте журнал через `logs --tail=100`). Когда вернулся статус `"status":true`, обновите страницу `http://127.0.0.1:13000` в браузере через работающий туннель: вы должны увидеть свой аккаунт и сохранённую запись. Это подтверждает штатное продолжение работы контейнера с тем же томом данных (но не заменяет полноценного тестирования резервных копий).

Чтобы контейнер автоматически поднимался и после перезагрузки самой виртуальной машины, в `compose.yaml` у нас указана политика [`restart: unless-stopped`](<https://docs.docker.com/engine/containers/start-containers-automatically/>) . Она сработает при старте демона Docker только в том случае, если до этого вы не останавливали контейнер вручную командой `stop`, и если сама системная служба Docker включена в автозагрузку Ubuntu.

На VM проверим статус системной службы:

```
systemctl  is-active  docker  
systemctl  is-enabled  docker  
```

Ожидаемые ответы — `active` и `enabled`.

Файлы конфигурации в папке `~/projects/open-webui` и именованный [том Docker](<https://docs.docker.com/engine/storage/volumes/>) `open-webui_open-webui` живут раздельно, хотя в этой конфигурации находятся на одном загрузочном блочном диске виртуальной машины. Чтобы не потерять доступ к базе данных, не меняйте поле `name: open-webui` в `compose.yaml`, не перегенерируйте `open-webui.env` поверх существующей базы и никогда не запускайте команду `docker compose down -v`, так как флаг `-v` удаляет том с данными.

Раз все наши данные лежат на облачном диске виртуальной машины, научимся правильно завершать сеанс работы и контролировать связанные с этим расходы.

## Завершим работу и проверим оставшиеся расходы

У локального SSH-туннеля, контейнера Docker, виртуальной машины и облачного диска разные жизненные циклы. Закрытие терминала на ноутбуке не останавливает арендованный сервер.

Сравним четыре действия и их влияние на доступ, сохранность данных и тарификацию в облаке:

| Действие | Что происходит с приложением и данными | Как меняется начисление платы в Яндекс Cloud |
| --- | --- | --- |
| Нажать `Ctrl+C` в локальном окне туннеля | Закрывается только путь из браузера (`127.0.0.1:13000`). Контейнер и VM продолжают работать | Никак не меняется: вычислительные ресурсы VM, диск и публичный IP продолжают оплачиваться в полном объёме |
| Остановить контейнер на VM (`sudo docker compose stop`) | Open WebUI перестаёт отвечать, данные сохраняются в томе. Сама Ubuntu VM остаётся включённой | Никак не меняется: пока VM в статусе `RUNNING`, её CPU, RAM, диск и IP продолжают тарифицироваться |
| Остановить VM в консоли облака (**Stop**) | Машина выключается (статус `STOPPED`), все данные на загрузочном диске `network-ssd` сохраняются | Начисление за vCPU и RAM прекращается, но **оплата за хранение диска продолжается** (по [правилам тарификации Compute](<https://yandex.cloud/ru/docs/compute/pricing>) ) |
| Удалить VM в консоли облака (**Delete**) | Виртуальная машина уничтожается безвозвратно. Загрузочный диск удаляется, если была включена опция автоудаления | Оплата за VM прекращается. Если диск, снимки (snapshots) или зарезервированный статический IP остались в каталоге, они тарифицируются дальше |

Если вам нужно временно остановить только само приложение внутри работающей машины, используйте штатную команду Compose.

На VM в каталоге проекта, только если нужно остановить контейнер:

```
sudo  docker  compose  stop  
```

Чтобы позже включить этот же контейнер без изменения настроек, достаточно выполнить `sudo docker compose start` (или `sudo docker compose up -d`, если вы редактировали файлы конфигурации).

При полной остановке виртуальной машины в консоли облака изменяется и доступ по IP-адресу. Это описано в [инструкции остановки и запуска ВМ](<https://yandex.cloud/ru/docs/compute/operations/vm-control/vm-stop-and-start>) . Поскольку мы выбрали автоматический (динамический) публичный IPv4-адрес, при переходе машины в состояние `STOPPED` этот адрес высвобождается. При следующем запуске (**Start**) облако выделит машине адрес заново. Он может измениться. Если адрес сменился, подставьте новый `VM_IP` в команды входа по SSH и запуска туннеля. Обычная перезагрузка гостевой системы (**Reboot**) без остановки ВМ динамический адрес сохраняет. Если бы в аккаунте был отдельно арендованный статический публичный IP, он сохранялся бы за вами, но по [тарифам VPC](<https://github.com/yandex-cloud/docs/blob/master/md-docs/vpc/pricing.md>) продолжал бы оплачиваться даже при выключенной машине.

Если перед долгим перерывом или удалением экспериментов вам нужно сохранить копию состояния системы, учтите, что копирование файлов внутри того же единственного диска `network-ssd` не защитит их при удалении самого диска. Чтобы сохранить состояние нашей однодисковой машины, сделаем облачный снимок (snapshot) по [официальному руководству создания снимков диска](<https://yandex.cloud/ru/docs/compute/operations/disk-control/create-snapshot>) :

1. Сначала остановите приложение командой `sudo docker compose stop`, чтобы база данных завершила все операции записи.
2. В консоли Яндекс Cloud штатно остановите виртуальную машину (**Stop**) и дождитесь статуса `STOPPED` перед созданием снимка диска.
3. Создайте снимок загрузочного диска в разделе **Диски** или **Снимки**.

Хранение снимков диска также тарифицируется отдельно по объёму. Для будущего переноса или восстановления приложения кроме данных тома понадобятся сохранённые в надёжном месте файлы `compose.yaml` и `open-webui.env` с вашим секретным ключом `WEBUI_SECRET_KEY`.

Удалять виртуальную машину для завершения этого урока **не требуется**. Вы можете продолжать пользоваться своим облачным экземпляром или держать машину в остановленном состоянии (`STOPPED`), учитывая оплату сохранённого диска, снимков и других оставшихся ресурсов. Если же вы решите полностью [удалить виртуальную машину](<https://yandex.cloud/ru/docs/compute/operations/vm-control/vm-delete>) , сначала проверьте, не остались ли внутри нужные данные без резервной копии, уточните настройку автоудаления диска, а после удаления загляните в разделы **Диски**, **Снимки** и **IP-адреса** выбранного каталога (плюс личный кабинет вашего внешнего API-провайдера), чтобы не оставить забытых платных ресурсов.

Завершение урока проверяем по результатам в своём облаке. Виртуальная машина в выбранном каталоге Яндекс Cloud защищена группой безопасности и принимает SSH только с вашего адреса. Контейнер Open WebUI `v0.12.3` слушает локальный порт машины и отвечает `"status":true` на проверку `/ready`. Через SSH-туннель создан личный аккаунт администратора с закрытой регистрацией посторонних. Статус подключения внешней модели проверен отдельно. Вы нашли том данных на диске `network-ssd` и проверили, какие созданные ресурсы продолжают оплачиваться.

## Материалы урока

- [Подготовка Docker для Linux timofei-ermolaev.ru](<https://timofei-ermolaev.ru/courses/open-webui/install/podgotovka-docker-dlya-linux/>)
- [Установка Open WebUI через Docker Compose timofei-ermolaev.ru](<https://timofei-ermolaev.ru/courses/open-webui/install/docker-compose/>)
- [Open WebUI на удалённом Linux-сервере timofei-ermolaev.ru](<https://timofei-ermolaev.ru/courses/open-webui/drugie-sposoby/open-webui-na-servere/>)

## Отметить прохождение

Отметьте урок после того, как получили проверяемый результат из практической части.

Урок пройден

![Тимофей Ермолаев](https://timofei-ermolaev.ru/_astro/timofei-ermolaev-portrait.s0mCFw-J_2r7Nkv.webp)

## Об авторе

### Тимофей Ермолаев

Директор по информационным технологиям (CIO)

Пишу о больших языковых моделях, автоматизации и применении ИИ в бизнесе. В статьях разделяю личный опыт, выводы исследований и практические рекомендации.

[Подробнее об авторе](<https://timofei-ermolaev.ru/ob-avtore/>)
