Если чат-интерфейс нужен и за пределами домашнего ноутбука, его можно перенести на постоянную площадку. Dockhost держит контейнер запущенным, подключает постоянный диск и открывает веб-интерфейс по HTTPS. Обслуживать виртуальную машину и настраивать сертификаты в Linux вручную не придётся. За сохранность ключа, выбор хранилища, закрытие регистрации и оплату ресурсов отвечает владелец проекта.
Мы настроим новый экземпляр Open WebUI: сначала сохраним данные и создадим владельца, затем проверим запуск, откроем HTTPS и подключим модель по API. После перезапуска проверим прежнюю учётную запись и настройки.
Если вы уже работали с Docker Compose, связка образа, постоянного хранилища и секретного ключа знакома. Здесь мы зададим её в панели платформы. Инструкция составлена по официальной документации Dockhost и исходному коду Open WebUI v0.12.1. Манифест образа в GHCR проверен; сам контейнер в Dockhost автор не запускал. Ниже описаны ожидаемые результаты и условия, при которых нужно остановиться.
Подготовим проект и адрес будущего интерфейса
Платформа размещает веб-интерфейс и хранит его базу данных, а ответы генерирует внешний поставщик модели по API. Существующие локальные чаты, учётные записи и ключи в новый облачный экземпляр автоматически не переносятся. Здесь мы настраиваем отдельный контейнер с нуля, без локальной Ollama, GPU и Helm-чартов.
Начнём с прав доступа, лимитов и тарифов в личном кабинете. Вычислительные ресурсы, постоянный диск и запросы к модельному API оплачиваются отдельно. Если в проекте есть незнакомые сервисы или стоимость ресурсов неясна, новую конфигурацию пока не применяем. Для установки подойдёт чистый проект либо существующий, в котором мы заранее проверили, что имена диска и контейнера свободны.
Домен подготовим заранее: его адрес понадобится приложению при первом запуске. Свяжем домен с контейнером только после внутренней инициализации. В разделе «Сетевые сервисы» → «Домены» добавим динамический домен третьего уровня платформы или укажем собственный домен по инструкции создания домена. Для собственного домена предварительно потребуется настроить A-запись у регистратора на выданный платформой IP-адрес; в обоих случаях Dockhost автоматически выпускает SSL-сертификат Let’s Encrypt.
Сохраним доменное имя. Ниже HTTPS_ORIGIN означает полный адрес вида https://ваш-домен со схемой https:// и без завершающего слэша. В разделе «Маршруты» пока ничего не создаём. Будущий адрес уже известен, старые сервисы не затронуты, а этот домен ещё не направляет запросы к нашему приложению. Теперь подготовим постоянный диск и ключ подписи, которые должны пережить замену контейнера.
Создадим диск для данных Open WebUI
Файловая система контейнера временная. В ней могут оставаться рабочие файлы текущего запуска, но постоянные данные нужно вынести на отдельный диск. В контейнере он будет виден как папка: Open WebUI сохранит в ней базу SQLite, учётные записи, настройки и историю диалогов. Профиль администратора хранится в этой базе, а не привязывается к доменному имени.
Для надёжной работы встроенной базы данных важны одновременно путь подключения, режим доступа к диску и свойства самого хранилища:
- В разделе «Сетевые диски» создайте диск типа SSD со свободным понятным именем, например
open-webui-data, руководствуясь документацией по сетевым дискам. Объём выберите под свои задачи и планируемые загрузки файлов в чат; универсального минимального порога для всех сценариев нет. - Выберите режим работы
ReadWriteOnce(RWO). По описанию режимов сетевых дисков Dockhost томRWOподключается только к одной реплике контейнера, а при перезапуске старая реплика сначала полностью останавливается перед созданием новой. РежимReadWriteMany(RWM) для совместной записи из нескольких контейнеров здесь не подходит. - Проверим требования СУБД. В документации Dockhost диски HDD и SSD описаны как сетевое блочное хранилище, а режим
RWOпрямо рекомендован платформой для встраиваемых баз данных вроде SQLite и DuckDB. Руководство Open WebUI по развёртыванию разрешает для SQLite только один экземпляр приложения на подходящем локальном или блочном хранилище с надёжными файловыми блокировками и низкой задержкой и запрещает сетевые файловые системы вроде NFS и SMB. В документации SQLite по режиму WAL также указано, что механизмы общей памяти требуют работы всех обращающихся к базе процессов на одном хосте.
Сетевое блочное хранилище и сетевая файловая система NFS устроены по-разному. Название режима RWO и отсутствие ошибок в первые минуты ещё не подтверждают совместимость с файловыми блокировками и fsync. Перед переносом важных рабочих процессов уточним у оператора, подходит ли выбранный диск для SQLite в режиме WAL. Если хранилище основано на NFS, SMB или CephFS, оператор не подтверждает корректную работу блокировок либо в логах появляются ошибки database is locked и сбои WAL, эту схему использовать нельзя. Отключение блокировок и увеличение числа реплик проблему не решают.
Созданный SSD-диск в режиме RWO мы подключим в каталог /app/backend/data на следующем шаге. Он сохраняет данные при перезапуске контейнера, но не заменяет отдельную резервную копию. Осталось связать его с образом и заранее задать владельца.
Зададим контейнер и первого администратора
Если запустить свежий экземпляр Open WebUI и сразу открыть к нему публичный маршрут в интернете, любой посетитель, открывший страницу первым, сможет зарегистрировать учётную запись администратора. Подробнее об этом в описании окна первичной инициализации Open WebUI. Поэтому передадим данные администратора через переменные окружения до первого старта контейнера и проверим его создание до публикации маршрута.
Откроем «Контейнеры» → «Добавить» и заполним параметры по инструкции создания контейнера, настройки портов и подключения сетевых дисков:
- Имя контейнера:
open-webui. Платформа создаст одноимённый внутренний сетевой сервисopen-webui, как указано в обзоре контейнеров Dockhost. - Образ:
ghcr.io/open-webui/open-webui:v0.12.1. Мы фиксируем тег выпуска v0.12.1, чтобы настройки и логи соответствовали исходному коду урока. - Количество реплик:
1для работы с дискомRWOи SQLite. - Порты:
8080/TCP. В образе заданPORT=8080; директиваEXPOSE 8080декларирует порт в Dockerfile v0.12.1. Конструкция3000:8080из локального Docker Compose здесь не нужна: внешний трафик пойдёт через маршрутизатор платформы. - Сетевые диски: созданный SSD-диск
open-webui-dataс точкой монтирования/app/backend/data. - Команда запуска и пользователь: штатные значения образа без переопределения. По умолчанию контейнер выполняет
bash start.sh.
До первого нажатия «Применить» добавим в настройки контейнера шесть постоянных переменных окружения, сверяясь со справочником конфигурации Open WebUI, рекомендациями по HTTPS и определением переменных в backend/open_webui/env.py:
| Переменная | Значение | Назначение |
|---|---|---|
UVICORN_WORKERS | 1 | Ограничивает сервер одним рабочим процессом в выбранной схеме с одной репликой и SQLite |
WEBUI_AUTH | True | Оставляет обязательную авторизацию включённой |
ENABLE_SIGNUP | False | Запрещает самостоятельную регистрацию новых пользователей |
WEBUI_SECRET_KEY | Своё постоянное случайное значение (вводится приватно) | Подписывает сессионные токены и защищает чувствительные поля |
WEBUI_URL | Фактический HTTPS_ORIGIN подготовленного домена | Задаёт базовый публичный адрес интерфейса |
CORS_ALLOW_ORIGIN | Тот же точный HTTPS_ORIGIN | Задаёт разрешённый origin для CORS |
Для WEBUI_SECRET_KEY сгенерируем на своём компьютере длинную случайную строку, например через openssl rand -hex 32, и сохраним её в личном менеджере паролей. Этот же ключ понадобится при любых пересозданиях контейнера и восстановлении из резервной копии. В WEBUI_URL и CORS_ALLOW_ORIGIN подставьте реальный адрес вида https://ваш-домен, полученный в первом разделе.
В том же окне до первого запуска добавим три временные переменные первичной инициализации (bootstrap), работа которых при старте описана в backend/open_webui/main.py и backend/open_webui/utils/auth.py:
WEBUI_ADMIN_EMAIL: ваш личный адрес электронной почты для входа; вводится приватно.WEBUI_ADMIN_PASSWORD: ваш уникальный сильный пароль администратора; вводится приватно.WEBUI_ADMIN_NAME: отображаемое имя владельца в интерфейсе.
Механизм bootstrap срабатывает только в пустой базе данных: функция create_admin_user проверяет наличие любых существующих пользователей и, если таблица пуста, создаёт первого администратора с указанным паролем, после чего в main.py принудительно сохраняет настройку ui.enable_signup = False. Если пользователи в базе уже есть, эти переменные ничего не меняют и существующий пароль не сбрасывают.
Dockhost и формат dockhost.yaml поддерживают подстановку глобальных переменных вида $GLOBAL_VARIABLE. Однако обычные поля окружения не стоит считать защищённым хранилищем с гарантированной маскировкой. WEBUI_SECRET_KEY, email и пароль вводим приватно в панели управления. Их реальные значения никогда не публикуем в Git, общих YAML-файлах, скриншотах или пересылаемых журналах.
Перед стартом проверим: диск смонтирован точно в /app/backend/data, задана одна реплика и один процесс UVICORN_WORKERS=1, все девять переменных заполнены, а публичного маршрута к сервису ещё нет. Запустим контейнер кнопкой «Применить». Если образ не скачивается, проверьте отсутствие опечаток в строке ghcr.io/open-webui/open-webui:v0.12.1 и доступность реестра GHCR, не подменяя официальный образ случайными сторонними сборками. Переход контейнера в статус Running сам по себе ещё не доказывает готовность базы и создание администратора, поэтому проверим оба результата внутри платформы.
Проверим запуск до открытия публичного маршрута
До публикации проверим отдельно создание владельца в базе данных и готовность веб-сервера. Ни одна из этих проверок не заменяет другую.
Сначала проверим создание администратора. Откройте в проекте раздел «Контейнеры», выберите контейнер open-webui и перейдите на вкладку «Логи» согласно документации по журналам контейнера. При первом чистом старте с заданными bootstrap-переменными код utils/auth.py в версии v0.12.1 выводит два разных сообщения: перед обращением к базе появляется строка Creating admin account..., и только после успешного хеширования пароля и вставки записи с ролью admin печатается подтверждение с префиксом:
Сразу после двоеточия в логе выводится ваш email, поэтому не копируйте и не публикуйте эту строку целиком. Само по себе сообщение Creating admin account... подтверждением успеха не является. Если при первом старте на новом диске итоговой строки Admin account created successfully: в журнале нет или видны ошибки миграции базы данных, не открывайте публичный маршрут и не пытайтесь зарегистрироваться через браузер вручную. Проверьте правильность имён переменных WEBUI_ADMIN_EMAIL и WEBUI_ADMIN_PASSWORD, точку монтирования /app/backend/data и то, что выбранный диск действительно был пустым. При повторных запусках на заполненной базе эта строка появляться не обязана: учётная запись уже существует.
Когда создание владельца подтверждено в логах, переключитесь в том же контейнере на вкладку «Терминал». По справке по консоли контейнера эта вкладка открывает командную оболочку внутри самой работающей реплики, поэтому локальный адрес 127.0.0.1:8080 обращается напрямую к процессу Open WebUI без участия внешних маршрутов. Утилита curl уже установлена в официальном образе (Dockerfile v0.12.1). Выполните в терминале контейнера команду проверки готовности:
Команда не выводит переменные окружения, ключи или содержимое таблиц. В отличие от базового эндпоинта /health, который возвращает статический ответ, обработчик /ready в backend/open_webui/main.py возвращает HTTP 200 и JSON {"status":true} только после завершения startup_complete и успешного пинга базы данных SQLite. В проверку входит и Redis, если он настроен. Если запуск ещё не завершён или база недоступна, команда вернёт ошибку 503.
Успешный ответ /ready подтверждает, что процесс запущен и видит базу данных в текущий момент, но сам по себе не доказывает ни наличие прав администратора, ни работу внешнего HTTPS-маршрута, ни подключение языковой модели, ни сохранность диска при пересоздании контейнера. Убедившись, что в логах первого старта есть Admin account created successfully:, а /ready возвращает {"status":true}, переходим к публикации интерфейса.
Откроем HTTPS и войдём в свой аккаунт
У домена, сервиса и маршрута разные задачи. Домен задаёт имя сайта в браузере. Внутренний сетевой сервис объединяет живые реплики контейнера, а маршрут соединяет домен с нужным портом сервиса. Сам по себе открытый в контейнере порт 8080/TCP доступен только внутри проекта, пока мы явно не создадим правило маршрутизации.
Откроем «Сетевые сервисы» → «Маршруты» и создадим маршрут по инструкции настройки маршрутов:
- Домен: выберите подготовленный в первом разделе домен.
- Путь:
/(корневой путь без перезаписи URL / rewrite). - Сервис:
open-webui(автоматически созданный сервис нашего контейнера). - Порт:
8080(8080/TCP).
Дождитесь выпуска SSL-сертификата и откройте свой фактический адрес https://ваш-домен в браузере. Если вы использовали собственный домен, предварительно должно пройти обновление записей DNS. Не обходите предупреждения браузера о недоверенном сертификате: при корректно выпущенном сертификате соединение сразу открывается по защищённому протоколу HTTPS.
На экране должна появиться форма входа в систему без кнопки публичной регистрации новых пользователей. Введите email и пароль, которые вы передавали в WEBUI_ADMIN_EMAIL и WEBUI_ADMIN_PASSWORD. В отличие от сценария, где первый администратор регистрируется вручную через веб-форму, здесь ваш профиль уже создан механизмом bootstrap: после входа убедитесь, что учётная запись принадлежит вам и в меню доступна панель администратора, а регистрация посторонних закрыта. Если браузер неожиданно предложил форму создания первого администратора с нуля, ничего в ней не заполняйте: немедленно проверьте, к тому ли сервису ведёт маршрут, смонтирован ли диск в /app/backend/data и почему не отработал bootstrap.
Многие параметры Open WebUI (ConfigVar), включая настройки доступа, после первого запуска сохраняются в базу данных. Как объясняет документация по переменным окружения, последующее изменение переменных контейнера не всегда перезаписывает настройки, сохранённые в панели администратора. При этом не отключайте переменную ENABLE_PERSISTENT_CONFIG: в режиме False приложение перестанет сохранять изменения настроек из веб-интерфейса.
Сразу после первого входа учётные переменные WEBUI_ADMIN_EMAIL, WEBUI_ADMIN_PASSWORD и WEBUI_ADMIN_NAME свою задачу выполнили. Удалим их при проверке перезапуска в последнем разделе. Сейчас форму редактирования открывать не будем. Успешный вход подтверждает работу веб-интерфейса и авторизации, а для генерации ответов в чате контейнеру нужно соединение с внешним API модели.
Проверим отдельное подключение модели
Когда вы открываете чат в браузере, запросы идут по двум разным участкам сети: ваш браузер общается с контейнером Open WebUI в Dockhost по HTTPS, а сам контейнер со своей площадки обращается к серверу языковой модели. Поэтому внутри контейнера в Dockhost адрес localhost или 127.0.0.1 указывает на сам этот контейнер, а не на ваш домашний компьютер с локальной моделью.
Подключите в настройках администратора внешний совместимый API-сервер по шагам из опубликованного урока про подключение OpenAI-совместимого API. В нашем сценарии достаточно убедиться в трёх вещах:
- URL выбранного поставщика API доступен по сети с серверов платформы Dockhost.
- Вы используете собственный действующий API-ключ с разрешённым доступом к выбранной модели (не вставляйте его в текст чата или публичные заметки).
- На балансе провайдера модели есть средства, если выбранный тариф платный.
Выберите модель в списке и отправьте короткое проверочное сообщение без личных, корпоративных или секретных данных. Например, попросите в двух предложениях объяснить, что такое сетевой порт. Каждый такой тестовый запрос может расходовать бюджет у поставщика API.
Оцените два результата в браузере:
- Потоковая передача ответа. При включённом потоковом режиме текст ответа должен появляться на экране постепенно, по мере генерации, а не целиком после долгой паузы.
- Работа WebSocket. Откройте инструменты разработчика в браузере (вкладка
Network, фильтрWS) и обновите страницу чата: если клиент устанавливает WebSocket-соединение, в списке должен появиться запрос со статусом101 Switching Protocols.
В документации Open WebUI по настройке HTTPS и обратного прокси указано, что для корректной работы чата прокси-сервер должен пропускать заголовки Upgrade и Connection для WebSocket, не буферизовать потоковые ответы (SSE) и иметь достаточные таймауты чтения. Если список моделей не загружается или возвращаются ошибки 401/403, причина обычно в ключе, URL или правах у внешнего провайдера API, а не в диске или образе контейнера. Если же обычный вход работает, но соединение WS не переключается в 101 или ответы застревают из-за буферизации, сначала проверьте точное совпадение WEBUI_URL и CORS_ALLOW_ORIGIN с вашим https://ваш-домен. При признаках буферизации на стороне входного прокси или сбое WebSocket обратитесь в поддержку Dockhost. Не будем искать специальные переключатели, которых нет в документации.
Если внешний API-ключ пока не подключён, вы уже проверили развёртывание интерфейса и защиту учётной записи, но проверка модели и потоковой генерации в вашем проекте остаётся невыполненной до настройки поставщика. Осталось убрать временные учётные данные из конфигурации контейнера и убедиться, что перезапуск не превращает установку в чистый пустой экземпляр.
Повторим вход после штатного перезапуска
Диск в /app/backend/data хранит таблицы базы данных, а неизменный WEBUI_SECRET_KEY позволяет новому процессу контейнера распознавать ранее выданные подписи и зашифрованные поля. Теперь мы удалим стартовые переменные администратора и проверим, что после перезапуска контейнера вход в ваш аккаунт и сохранённые данные остаются на месте.
Перед изменением настроек проверим, что в конфигурации контейнера open-webui остались прежними четыре элемента: имя open-webui, образ ghcr.io/open-webui/open-webui:v0.12.1, SSD-диск open-webui-data в точке /app/backend/data и значение WEBUI_SECRET_KEY. Сохраняем и остальные пять постоянных переменных: UVICORN_WORKERS, WEBUI_AUTH, ENABLE_SIGNUP, WEBUI_URL, CORS_ALLOW_ORIGIN. Секретные значения в открытый текст не выписываем.
Откройте редактирование контейнера в веб-интерфейсе Dockhost и удалите три переменные первичной инициализации:
WEBUI_ADMIN_EMAILWEBUI_ADMIN_PASSWORDWEBUI_ADMIN_NAME
Сохраните изменения конфигурации контейнера. При перезапуске реплики после применения настроек или штатном перезапуске через интерфейс проекта для диска RWO прежняя реплика сначала останавливается, а новая подключает тот же самый том open-webui-data. Если при сохранении изменений платформа уже перезапустила контейнер с обновлённым набором переменных, второй раз перезапускать его вручную не требуется. Не увеличивайте число реплик, не отключайте диск и не создавайте вместо этого новый контейнер с другим томом.
Устанавливать консольную утилиту ради этой операции не нужно. Если на вашем компьютере уже установлен и авторизован Dockhost CLI, можно использовать команду из справки container restart. Выполняем её локально, заменив YOUR_PROJECT точным именем своего проекта. Вкладка «Терминал» внутри контейнера для этой команды не подходит:
После запуска новой реплики снова откройте вкладку «Терминал» контейнера и повторите проверку curl --fail --silent --show-error --max-time 10 http://127.0.0.1:8080/ready, дождавшись ответа {"status":true}. В логах повторного старта строка Admin account created successfully: появляться уже не должна, так как переменные удалены, а база данных не пуста.
Откройте https://ваш-домен в браузере и проверьте состояние установки:
- Ваш прежний логин и пароль администратора подходят для входа, роль владельца сохранена, а публичная регистрация остаётся закрытой.
- Если в предыдущем разделе вы провели тестовый диалог с моделью, этот чат отображается в истории.
- Если после перезапуска вдруг открылась страница первичной регистрации или пустая база, немедленно остановитесь и не регистрируйте нового пользователя: поскольку переменные bootstrap удалены, появление пустой базы требует проверить прежний диск и путь
/app/backend/data, настройки базы и направление маршрута.
Если результат отличается от ожидаемого, проверим возможные причины:
- Открылась чистая установка или пропали пользователи: проверьте, тот ли диск подключён, точен ли путь
/app/backend/dataи на тот ли сервис указывает маршрут. - Сбросилась активная сессия или перестали читаться защищённые настройки: проверьте, не изменилось ли значение
WEBUI_SECRET_KEY. - В логах появились ошибки
database is lockedили сбои WAL: проверьте, что заданы одна реплика иUVICORN_WORKERS=1, а выбранное хранилище поддерживает блокировки SQLite. - Контейнер не переходит в готовность: изучите вкладку «Логи» и проверьте лимиты ресурсов проекта.
- Интерфейс открывается, но модель не отвечает: проверьте настройки и баланс внешнего API-провайдера отдельно от контейнера.
Успешный повторный вход и прежний чат показывают, что проверенные данные доступны после этого перезапуска. Неизменность диска и WEBUI_SECRET_KEY проверяем отдельно в конфигурации: один вход не доказывает сохранность всех данных и ключей. Обычный рестарт также не подтверждает высокую доступность (HA), сохранность данных при удалении диска или пересоздании проекта с нуля и не заменяет тестовое восстановление из резервной копии.
Перед обновлением образа сохраним отдельную резервную копию всех данных из /app/backend/data и свой WEBUI_SECRET_KEY. Новый релиз может изменить схему базы. Возврат к тегу v0.12.1 не гарантирует откат этих изменений.
Проверки лога создания администратора, /ready, входа по HTTPS, потокового ответа модели, отдельного WebSocket-соединения со статусом 101 и прежнего аккаунта после перезапуска без bootstrap-переменных относятся к разным частям установки. Если внешний API или пригодность хранилища у оператора ещё не проверены, эти шаги остаются незавершёнными. До их проверки постоянные рабочие диалоги сюда не переносим.

