Артём ИксановЛонгриды
Технический трек

Как запускать свои ИИ-сервисы: Docker для начинающих

Трекер задач с ИИ в Docker-контейнерах — за 15 минут, мышкой

Это текстовая версия видео. Если удобнее смотреть — ролик на YouTube, 20 минут. Здесь то же самое, плюс всё для копирования и скачивания: значения переменных, готовая конфигурация Dockhost и docker-compose.yml для своего сервера.

Ты запустишь свой трекер задач с ИИ-ассистентом: в своих Docker-контейнерах, со своей базой данных, на своём адресе и со своим ключом к модели. Программировать не нужно: всё делается мышкой в интерфейсе облака, примерно за 15 минут. Маркетолог, который не пишет код, дошёл по этой инструкции до страницы входа за 12 минут.

Трекер здесь — пример. Главное — схема из пяти частей: образ, контейнер, переменные окружения, диск и маршрут. По ней же поднимаются сотни других готовых сервисов — от веб-аналитики до ИИ-чата для команды.

Что получится

tududi — открытый менеджер задач с ИИ-ассистентом. Мы запустим его в облаке как свой сервис: программа работает у тебя, а не у кого-то другого. Такой подход называют self-hosted.

Из чего состоит связка:

Схема: браузер, маршрут, контейнер tududi с диском uploads и контейнер PostgreSQL с диском data
Вся схема: снаружи виден только маршрут, база доступна только внутри проекта

Почему два контейнера, а не один

tududi умеет хранить всё в одном файле внутри своего контейнера и может обойтись без внешней базы. Мы всё равно выносим данные в отдельную PostgreSQL по двум причинам:

Вариант попроще, с одним контейнером, — в разделе «Вариант попроще: один контейнер с SQLite».

Что понадобится

Я поднимаю всё на Dockhost: у нас на нём прод, и он даёт ресурсы для воркшопов. По каким критериям выбирать провайдера и какие есть альтернативы — в статье «Как выбрать LLM-шлюз». Та же связка запускается на любом сервере с Docker — файл для этого — в разделе «Свой сервер: docker-compose.yml».

Шаг 1. Создай проект

В панели Dockhost создай новый проект и назови его, например, ai-tracker.

Проект — это твой мини-дата-центр. Внутри — своя изолированная сеть, в ней работают контейнеры: виртуальные компьютеры, каждый со своей программой. Контейнеры видят друг друга, к ним можно подключать диски, а из интернета доступно только то, что ты сам откроешь.

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

Панель Dockhost, страница обзора нового проекта
Новый проект: пока пустой мини-дата-центр

Шаг 2. Задай переменные окружения

Настройки передаются программам через переменные окружения — пары «название = значение», которые программа получает при запуске. Базе нужны имя и пароль, а приложению — адрес этой базы.

Открой Окружение → Переменные окружения → Добавить и создай три переменные. У каждой поставь галочку «Глобальная переменная»: такую переменную автоматически получают все контейнеры проекта, и задавать её ещё раз не придётся.

ПеременнаяЗначениеЗачем
POSTGRES_DBtududiИмя базы данных
POSTGRES_PASSWORDтвой парольПароль базы
DATABASE_URLpostgres://postgres:ПАРОЛЬ@database/tududiАдрес базы для tududi
POSTGRES_DB=tududi
POSTGRES_PASSWORD=ЗАМЕНИ_на_свой_пароль
DATABASE_URL=postgres://postgres:ЗАМЕНИ_на_свой_пароль@database/tududi

Имя пользователя базы можно не задавать: тогда PostgreSQL возьмёт стандартное — postgres. Из интернета к базе никто не подключится: снаружи у неё не будет адреса, она доступна только внутри проекта.

Раздел «Переменные окружения» в Dockhost с переменными POSTGRES_DB, POSTGRES_PASSWORD и DATABASE_URL
Три глобальные переменные — их получат оба контейнера

Из чего состоит адрес базы

DATABASE_URL — адрес подключения к базе одной строкой:

В пароле базы не используй символы @ : / #: они сломают эту строку, и приложение не сможет подключиться к базе.

Шаг 3. Создай диски

Контейнер одноразовый: его можно удалить и создать заново за минуту, и всё, что было у него внутри, пропадёт. Поэтому данные хранят на подключаемом диске — в Docker это называется том. Удалишь контейнер — данные останутся на диске, и его можно подключить к новому контейнеру.

В «Обзоре» проекта, в блоке «Сетевые диски», нажми плюс и создай два диска с одинаковыми настройками:

ИмяДля чегоТипРежимРазмерЦена в месяц
dataБаза данныхSSDReadWriteOnce5 GiB≈ 79 ₽
uploadsФайлы, прикреплённые к задачамSSDReadWriteOnce5 GiB≈ 79 ₽

Дождись зелёных индикаторов у обоих дисков.

Форма нового сетевого диска в Dockhost: SSD, ReadWriteOnce, 5 GiB, 79,2 ₽ в месяц
Настройки диска и его цена в месяц

Шаг 4. Запусти контейнер с базой

Сначала база, потом приложение: при запуске tududi сразу подключается к базе, и она должна уже работать.

Образ и контейнер

Образ — упакованная программа со всем, что ей нужно для работы. Контейнер — запущенная копия этого образа. Образы публикуют сами авторы программ в открытых каталогах, самый известный — Docker Hub. Скачал образ — получил готовый сервис, ничего не нужно устанавливать руками.

postgres:16-alpine читается так: программа postgres, версия 16, облегчённая сборка alpine.

Настройки контейнера

Открой Контейнеры → Добавить:

ПолеЗначение
Имяdatabase — ровно то, что стоит в DATABASE_URL
Образpostgres:16-alpine
Количество реплик1
РесурсыПо умолчанию: 1 процессор с резервом 20%, 256 MiB памяти
Порты5432
Переменные окруженияНе добавлять: глобальные из шага 2 база получит сама
Сетевые дискиdata → /var/lib/postgresql/data
Цена≈ 247 ₽ в месяц

Создай контейнер и дождись зелёного индикатора.

Форма контейнера database в Dockhost: образ postgres:16-alpine, порт 5432, диск data
Контейнер базы: образ, порт и диск

Шаг 5. Запусти контейнер с tududi

Снова Контейнеры → Добавить:

ПолеЗначение
Имяtududi-app
Образchrisvel/tududi:1.5.0
Количество реплик1
РесурсыПо умолчанию: 1 процессор с резервом 20%, 256 MiB
Порты3002 — на нём tududi открывает веб-интерфейс
Переменные окруженияСемь, см. ниже
Сетевые дискиuploads → /app/uploads
Цена≈ 247 ₽ в месяц
Форма контейнера tududi-app в Dockhost: образ chrisvel/tududi:1.5.0, порт 3002
Образ с зафиксированной версией, ресурсы и порт

Почему 1.5.0, а не latest

Цифры после двоеточия — версия образа. Часто пишут latest, «последняя», но это не версия, а ярлык. Автор выпустит обновление — и после перезапуска у тебя окажется другая программа, которую с твоими настройками никто не проверял. Поэтому в работе версию фиксируют. В 1.5.0 появилась поддержка PostgreSQL, и на ней проверена эта инструкция. Как переходить на новую версию — в разделе «Как обновлять».

Семь переменных

Скопируй и замени значения на свои:

TUDUDI_USER_EMAIL=твоя@почта.ru
TUDUDI_USER_PASSWORD=ЗАМЕНИ_на_длинный_случайный_пароль
TUDUDI_SESSION_SECRET=ЗАМЕНИ_на_случайную_строку_из_64_символов
TUDUDI_TRUST_PROXY=1
LLM_API_KEY=ЗАМЕНИ_на_свой_ключ
LLM_BASE_URL=https://inference.dockhost.io/v1
LLM_MODEL=google/gemini-3.1-flash-lite
ПеременнаяЧто это
TUDUDI_USER_EMAILПочта администратора — твой логин. Запомни её
TUDUDI_USER_PASSWORDПароль администратора. Трекер будет открыт в интернете, поэтому — длинный и случайный
TUDUDI_SESSION_SECRETКлюч, которым tududi подписывает твой вход в браузере. Без него приложение придумывает новый ключ при каждом перезапуске и выкидывает тебя из аккаунта
TUDUDI_TRUST_PROXY1 — трафик из интернета приходит к контейнеру через прокси Dockhost, и эта настройка говорит tududi, что посреднику можно доверять. Без неё вход может сбоить
LLM_API_KEYТвой ключ к моделям
LLM_BASE_URLАдрес шлюза. Подойдёт любой OpenAI-совместимый провайдер
LLM_MODELМодель из каталога провайдера. google/gemini-3.1-flash-lite для разбора задач хватает, а запрос стоит копейки

Свой ключ к ИИ

tududi не продаёт ИИ по подписке: он обращается к модели с твоим ключом, и ты платишь только за свои запросы. Такой подход называют BYOK — bring your own key, «принеси свой ключ». Подробнее о нём — в посте в Telegram-канале.

Подключи диск uploads по пути /app/uploads, создай контейнер и дождись зелёного индикатора.

Переменные окружения контейнера tududi-app и подключённый диск uploads
Переменные и диск контейнера tududi
Обзор проекта в Dockhost: контейнеры tududi-app и database, диски uploads и data с зелёными индикаторами
Два контейнера и два диска работают

Шаг 6. Выведи трекер в интернет

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

Домен. Открой «Сетевые сервисы → Домены» и нажми «Добавить». Задай имя — в примере tududi.my — и выбери тип «Динамический»: Dockhost бесплатно выдаст адрес третьего уровня. Как подключить свой домен, читай в конце статьи.

Маршрут. Перейди в «Сетевые сервисы → Маршруты» и нажми «Добавить».

ПолеЗначение
Имяtududi-web
Доменtududi.my — созданный только что
Путь/ — все запросы по этому адресу
ТипВнутренний
Сетевой сервисtududi-app
Порт3002/TCP

Порт 3002 — тот единственный вход, который ты открыл у контейнера tududi на шаге 5. Маршрут открывает его для всего интернета и стоит 15 ₽ в месяц. У базы маршрута нет, поэтому снаружи виден только трекер.

Форма нового маршрута в Dockhost: имя tududi-web, путь /, тип «Внутренний», сетевой сервис tududi-app, порт 3002/TCP
Маршрут связывает адрес с контейнером tududi

Теперь вернись в «Домены» и открой карточку домена. В поле «Хост» — адрес твоего трекера, вида rm25-i6rr-0477.gw-1a.dockhost.net. Маршрут обычно подхватывается за 10–15 секунд: если страница не открылась сразу, подожди и обнови её.

Карточка домена в Dockhost с выделенным полем «Хост»
Адрес трекера — в поле «Хост»

Шаг 7. Войди и включи ИИ-ассистента

Открой адрес из поля «Хост». На странице входа введи почту и пароль из переменных TUDUDI_USER_EMAIL и TUDUDI_USER_PASSWORD — это учётная запись администратора.

Страница входа tududi с полями почты и пароля
Свой трекер на своём адресе

Это твой собственный трекер: на твоём облачном ресурсе, с твоей базой данных, с ИИ-моделью на твоём ключе и на твоём адресе в интернете. Не сервис по подписке — и для этого не пришлось программировать.

Общие настройки. В профиле открой раздел «Общие»: выбери русский язык, часовой пояс и впиши своё имя. Часовой пояс важен — от него зависят «Сегодня», сроки и утренний бриф. Часть новых разделов пока на английском: переводы ещё догоняют.

ИИ-ассистент. Открой раздел «AI Assistant». Сверху, в блоке «Server Configuration», видно, что ключ, адрес и модель приложение уже получило из переменных шага 5. Если вместо этого видишь «AI is not configured», перезапусти контейнер tududi-app: переменные читаются при старте.

Включи переключатель «AI Assistant (Insights)» — ИИ включается для каждого пользователя отдельно.

Ниже — поле «About You», до 500 символов. Напиши пару строк о себе и о том, каких ответов ждёшь, чтобы советы были по делу. И обязательно добавь требование отвечать на русском, иначе утренний бриф будет приходить на английском. Текст, который можно взять за основу:

Веду в трекере рабочие и личные проекты: маркетинг, запуск сайтов, найм, дела по дому. Жду конкретики: первый шаг, который можно сделать сегодня, реальные риски и сроки, без общих слов.
[Языковые требования]: Все ответы, комментарии, инсайты и УТРЕННИЙ БРИФ (Morning Brief / daily summary) генерируй ИСКЛЮЧИТЕЛЬНО на русском языке. Запрещено использовать английский язык даже в заголовках брифа.

Мой вариант — для инженерных задач:

Жду от ассистента конкретных, глубоких инженерных ответов, сфокусированных на продакшен-решениях, архитектурных рисках и практической автоматизации.
[Языковые требования]: Все ответы, комментарии, инсайты и УТРЕННИЙ БРИФ (Morning Brief / daily summary) генерируй ИСКЛЮЧИТЕЛЬНО на русском языке. Запрещено использовать английский язык даже в заголовках брифа.

Первую строку перепиши под себя, блок про язык оставь как есть. Нажми «Сохранить изменения».

Раздел AI Assistant в настройках tududi: блок Server Configuration, переключатель AI Assistant (Insights), поле About You с требованием к языку
Ключ, адрес и модель пришли из переменных — осталось включить ассистента и рассказать о себе

Что умеет ИИ-ассистент

Разбор задачи

Открой любую задачу и нажми кнопку ИИ — значок с искрами справа, на уровне вкладок. Через пару секунд ассистент раскладывает её по блокам:

На скриншоте — задача «Настроить сбор заявок с лендинга в CRM» из проекта «Запуск лендинга под осеннюю акцию». В блоке «Будьте осторожны» ассистент написал: «Обязательно проверьте, как CRM обрабатывает дубли заявок с тем же номером телефона, чтобы при повторной отправке данные не затирались, а обновлялись или создавалась задача на существующего клиента».

Карточка задачи в tududi с блоками ИИ: «Об этой задаче», «Следующий шаг», «Как к этому подойти», «Предложенные ссылки», «Будьте осторожны»
Задача в одну строку — и разбор от ИИ за пару секунд

Такой разбор стоит около 16 копеек. Ассистент сохраняет ответ: пока не нажмёшь «Сгенерировать заново», повторного запроса и расхода не будет. По тому же принципу ассистент разбирает и целый проект.

Утренний бриф

Главная фишка. Открой «Сегодня»: ассистент смотрит на все задачи сразу и собирает твой день — главный фокус, приоритетные дела с объяснением, почему именно они, и что вот-вот сгорит. Бриф собирается раз в день и тоже сохраняется.

Чтобы бриф был полезным, ему нужен материал: проекты, задачи со сроками, несколько закрытых за последние дни. На пустом трекере советовать нечего. На скриншоте — демо-аккаунт: четыре проекта, чуть больше десятка задач, пара просроченных.

Экран «Сегодня» в tududi с утренним брифом ИИ: фокус на сегодня, приоритетные действия, предупреждения
Утренний бриф: фокус, приоритеты и что вот-вот сгорит

Что ещё умеет tududi

Если ты сейчас в Todoist, TickTick или похожем сервисе, tududi — их полноценная альтернатива. Ты запускаешь его в России и не думаешь о блокировках и VPN — ни сейчас, ни потом. И он работает лично для тебя, со своим ассистентом.

И всё это — в твоём контейнере, с ИИ на твоём ключе и открытым кодом. А ещё у tududi есть свой API и MCP, поэтому дальше в серии он станет центром автоматизаций: задачи будут приходить в него сами.

Docker в пяти понятиях

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

ПонятиеЧто этоВ нашем проекте
ОбразГотовая упаковка программы со всем, что ей нужно для работы. Берётся из реестра, например Docker Hubpostgres:16-alpine, chrisvel/tududi:1.5.0
КонтейнерЗапущенный образ: программа работает изолированно, со своими ресурсамиdatabase, tududi-app
Переменные окруженияНастройки, которые программа получает при запуске: пароли, адреса, ключиPOSTGRES_PASSWORD, DATABASE_URL, LLM_API_KEY
Диск (том)Хранилище, которое живёт отдельно от контейнера: контейнер можно пересоздать, данные останутсяdata — база, uploads — файлы
МаршрутПравило, которое открывает контейнер в интернет по адресу. Внутри проекта контейнеры находят друг друга по имени без негоtududi-web → tududi-app:3002
Цепочка из пяти шагов: образ, контейнер, переменные, диск, маршрут
Так поднимается почти любой сервис

Любой другой сервис поднимается по той же схеме: найти образ, прочитать в его документации, какие переменные и папки ему нужны, и повторить те же шаги. Если запускать контейнеры на своём сервере, все пять понятий описывают одним файлом — docker-compose.yml. Готовый файл для нашей связки — в следующем разделе.

Вариант попроще: один контейнер с SQLite

Если трекер нужен только тебе, можно обойтись без отдельной базы: по умолчанию tududi хранит данные в SQLite — базе в одном файле в папке /app/db. Чем этот вариант уступает PostgreSQL, см. в разделе «Почему два контейнера, а не один».

Что меняется в инструкции:

Стоимость: один контейнер 247 ₽ + два диска 158 ₽ + маршрут 15 ₽ ≈ 420 ₽ в месяц плюс ИИ.

Важно: если в проекте осталась глобальная переменная DATABASE_URL, tududi попробует подключиться к PostgreSQL и не запустится. В варианте с SQLite её быть не должно.

Готовая конфигурация Dockhost

Всё, что ты накликал, Dockhost хранит одним текстом в формате YAML: «Настройки → Конфигурация». Внутри — переменные, диски, контейнеры и сетевые настройки проекта. Этот текст можно скопировать и поднять ту же связку в другом проекте за минуту.

Раздел «Настройки → Конфигурация» в Dockhost с YAML-описанием проекта: переменные окружения и диски
Весь проект одним текстом

Как использовать мою конфигурацию:

  1. Скачай архив dockhost-ai-tracker.zip: внутри файл конфигурации и README с инструкцией. Или скопируй текст ниже.
  2. Замени все значения ЗАМЕНИ_… на свои. Пароль базы встречается дважды: в POSTGRES_PASSWORD и внутри DATABASE_URL.
  3. Создай новый проект, открой «Настройки → Конфигурация», вставь текст и нажми «Применить».
  4. Проверь домен и маршрут в «Сетевых сервисах»: у нового проекта будет свой адрес в поле «Хост».
  5. Войди и включи ИИ-ассистента, как в шаге 7.
# Трекер задач tududi 1.5.0 + PostgreSQL 16 на Dockhost — конфигурация из ролика
# «Как запускать свои ИИ-сервисы: Docker для начинающих».
# Инструкция: https://iksanov.com/read/docker-trekker-zadach-s-ii/
#
# Перед применением замени все значения, которые начинаются с ЗАМЕНИ_.
# Пароль базы встречается дважды: в POSTGRES_PASSWORD и внутри DATABASE_URL — впиши одинаковый.
# Заполненный файл содержит пароли и ключ открытым текстом: не публикуй его и не пересылай в чаты.

version: 1
project: ai-tracker

timezone: UTC

# DNS configuration
dns:
  nameservers:
  - 8.8.8.8
  - 8.8.4.4
  cache: 30
  loadBalance: false

# Environments configuration
environment:

  variables:
    POSTGRES_DB: tududi
    # Пароль базы: латиница и цифры, без символов @ : / # — они ломают DATABASE_URL.
    POSTGRES_PASSWORD: ЗАМЕНИ_пароль_базы
    # Тот же пароль базы вместо ЗАМЕНИ_пароль_базы. database — имя контейнера с базой, tududi — имя базы.
    DATABASE_URL: postgres://postgres:ЗАМЕНИ_пароль_базы@database/tududi


# Volumes configuration
volumes:

  uploads:
    size: 5Gi
    type: ssd
    mode: rwo

  data:
    size: 5Gi
    type: ssd
    mode: rwo


# Containers configuration
containers:

  database:
    image: postgres:16-alpine
    replicas: 1
    strategy: Recreate
    resources:
      cpu: 1
      cpuFraction: 20
      memory: 256Mi
    ports:
    - 5432/TCP
    volumes:
    - name: data
      mountPath: /var/lib/postgresql/data

  tududi-app:
    image: chrisvel/tududi:1.5.0
    replicas: 1
    strategy: Recreate
    resources:
      cpu: 1
      cpuFraction: 20
      memory: 256Mi
    ports:
    - 3002/TCP
    variables:
      # Почта администратора — это логин в трекер.
      TUDUDI_USER_EMAIL: ЗАМЕНИ_почта_администратора
      # Длинный случайный пароль: трекер будет открыт в интернете.
      TUDUDI_USER_PASSWORD: ЗАМЕНИ_пароль_для_входа
      # 64 случайных символа: openssl rand -hex 64 или генератор паролей (латиница и цифры).
      TUDUDI_SESSION_SECRET: ЗАМЕНИ_секрет_сессии
      TUDUDI_TRUST_PROXY: 1
      # Ключ к OpenAI-совместимому LLM-шлюзу.
      LLM_API_KEY: ЗАМЕНИ_ключ_к_LLM
      LLM_BASE_URL: https://inference.dockhost.io/v1
      LLM_MODEL: google/gemini-3.1-flash-lite
    volumes:
    - name: uploads
      mountPath: /app/uploads


# Network configuration
network:

  domains:

    tududi.my: ~

  routes:

    tududi-web:
      domain: tududi.my
      path: /
      type: internal
      service: tududi-app
      port: 3002/TCP

Значение, которое начинается со знака $, Dockhost читает как ссылку на переменную проекта. Поэтому свои пароли и секрет с $ не начинай.

Свой сервер: docker-compose.yml

Если у тебя свой сервер или компьютер с Docker, ту же связку описывает один файл. Все пять понятий в нём на месте: image — образ, services — контейнеры, environment — переменные, volumes — диски, ports — вход снаружи.

  1. Скачай архив tududi-docker-compose.zip и распакуй: внутри docker-compose.yml, .env и README. Файл .env начинается с точки, поэтому в Finder на macOS он скрыт: Cmd + Shift + . показывает скрытые файлы.
  2. Открой .env и заполни пустые значения. Пока обязательные значения пустые, docker compose не запустится и подскажет, что заполнить.
  3. В папке с файлами запусти docker compose up -d.
  4. Открой http://адрес-сервера:3002 (на своём компьютере — http://localhost:3002) и войди с почтой и паролем из .env.
# tududi 1.5.0 + PostgreSQL 16 — тот же набор, что в ролике, для любого сервера с Docker.
# 1. Заполни файл .env рядом с этим файлом.
# 2. docker compose up -d
# 3. Открой http://адрес-сервера:3002 и войди с почтой и паролем из .env.

services:
  database:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: ${DB_NAME:-tududi}
      POSTGRES_PASSWORD: ${DB_PASSWORD:?Заполни DB_PASSWORD в .env}
    volumes:
      - tududi_pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d ${DB_NAME:-tududi}"]
      interval: 5s
      timeout: 3s
      retries: 10

  tududi-app:
    image: chrisvel/tududi:1.5.0
    restart: unless-stopped
    depends_on:
      database:
        condition: service_healthy
    environment:
      DATABASE_URL: postgres://postgres:${DB_PASSWORD}@database:5432/${DB_NAME:-tududi}
      TUDUDI_USER_EMAIL: ${TUDUDI_USER_EMAIL:?Заполни TUDUDI_USER_EMAIL в .env}
      TUDUDI_USER_PASSWORD: ${TUDUDI_USER_PASSWORD:?Заполни TUDUDI_USER_PASSWORD в .env}
      TUDUDI_SESSION_SECRET: ${TUDUDI_SESSION_SECRET:?Заполни TUDUDI_SESSION_SECRET в .env}
      TUDUDI_TRUST_PROXY: ${TUDUDI_TRUST_PROXY:-false}
      LLM_API_KEY: ${LLM_API_KEY:-}
      LLM_BASE_URL: ${LLM_BASE_URL:-https://inference.dockhost.io/v1}
      LLM_MODEL: ${LLM_MODEL:-google/gemini-3.1-flash-lite}
    volumes:
      - tududi_uploads:/app/uploads
    ports:
      - "3002:3002"

volumes:
  tududi_pgdata:
  tududi_uploads:
# Значения для docker-compose.yml. Заполни пустые строки и сохрани файл.
# Пока обязательные значения пустые, docker compose не запустится и подскажет, что заполнить.

# База данных. Пароль базы — латиница и цифры, без символов @ : / # — они ломают адрес подключения.
DB_NAME=tududi
DB_PASSWORD=

# Вход в трекер: почта администратора (это логин) и длинный случайный пароль.
TUDUDI_USER_EMAIL=
TUDUDI_USER_PASSWORD=

# Секрет сессии — 64 случайных символа: openssl rand -hex 64 или генератор паролей (латиница и цифры).
# Без него трекер будет выкидывать из аккаунта после каждого перезапуска.
TUDUDI_SESSION_SECRET=

# Трекер за обратным прокси (nginx, Caddy, Traefik) — поставь 1. Без прокси — false.
TUDUDI_TRUST_PROXY=false

# ИИ-ассистент: ключ, адрес OpenAI-совместимого шлюза и имя модели.
# Без ключа трекер работает, но ИИ-функции не включатся.
# Локальная модель через Ollama: LLM_BASE_URL=http://адрес-ollama:11434/v1 и LLM_MODEL=имя-модели
LLM_API_KEY=
LLM_BASE_URL=https://inference.dockhost.io/v1
LLM_MODEL=google/gemini-3.1-flash-lite

Пригодится дальше:

# запуск в фоне
docker compose up -d

# логи tududi — первое, куда смотреть, если что-то не так
docker compose logs -f tududi-app

# резервная копия базы в файл
docker compose exec -T database pg_dump -U postgres tududi > backup.sql

# остановить; данные в томах остаются
docker compose down

Порт базы наружу не открыт: как и в Dockhost, к ней обращается только tududi внутри общей сети. Если трекер смотрит в интернет, ставь его за nginx или Caddy с HTTPS и включи TUDUDI_TRUST_PROXY=1.

Чем файл отличается от примера автора tududi: зафиксирована версия 1.5.0 вместо latest, пользователь базы — стандартный postgres, как в ролике, добавлены секрет сессии и переменные ИИ. Все переменные tududi — в справочнике.

Сколько стоит

Около 910 ₽ в месяц вместе с ИИ, а в экономном варианте — меньше 600 ₽. Цены — по калькулятору Dockhost на момент записи ролика.

ЧтоВ месяц
Два контейнера: 1 CPU, резерв 20%, 256 MiB2 × 247 ₽ = 494 ₽
Два диска SSD по 5 GiB2 × 79 ₽ = 158 ₽
Маршрут15 ₽
Инфраструктура≈ 670 ₽
ИИ: 50 запросов в день по 16 копеек≈ 240 ₽
Итого≈ 910 ₽

Оговорка: 247 ₽ — цена контейнера, пока он укладывается в резерв процессора. Если нагрузка выйдет за резерв, цена вырастет: верхняя граница для таких настроек — 884,16 ₽ в месяц. tududi сейчас берёт тысячные доли ядра, так что запас большой.

Сколько стоит ИИ

Один запрос ассистента на модели google/gemini-3.1-flash-lite стоит в среднем 16 копеек. Тариф: 0,0329 ₽ за 1 тыс. входящих токенов и 0,1974 ₽ за 1 тыс. исходящих. За весь день съёмки ушло 21 тыс. входящих и 5,6 тыс. исходящих токенов — 1,79 ₽. Расход виден в панели: «AI-Платформа → LLM инференс → Потребление».

Раздел «LLM инференс → Потребление» в Dockhost: график расхода токенов и тарифы модели
Расход на ИИ — в панели, до копейки

Ассистент сохраняет ответы: повторно открытый разбор или бриф ничего не стоит. 50 запросов в день — с запасом для одного человека.

Как сэкономить

В сумме — меньше 600 ₽ в месяц. А вариант с SQLite без отдельной базы — около 420 ₽ плюс ИИ.

Безопасность и данные

Трекер открыт в интернете, а ИИ-ассистент отправляет текст задач провайдеру модели. Особенно важно помнить об этом, если ведёшь в нём рабочие задачи или подключаешь команду.

Пароль. Вход в трекер защищает только пароль, так что ставь длинный и случайный — из генератора паролей. То же для пароля базы и секрета сессии. Регистрация по умолчанию закрыта: чужой человек не сможет завести себе аккаунт.

Что уходит модели. Для разбора и брифа tududi отправляет провайдеру название задачи, статус, сроки, теги, начало заметок, название и описание проекта — подробно в документации tududi. Для обычных задач это нормально. С чувствительными данными, где стоит вопрос информационной безопасности, — осторожнее.

Если данные не должны уходить наружу. Всю схему можно поднять внутри своей инфраструктуры с локальной моделью, например через Ollama или LM Studio. В tududi для этого меняются только адрес и имя модели — переменные LLM_BASE_URL и LLM_MODEL.

Если модель внешняя, выбирай провайдера по тому, где он обрабатывает данные и что с ними делает. Критерии — в статье «Как выбрать LLM-шлюз».

Если что-то не работает

Первое, куда смотреть, — логи контейнера tududi-app: там видно, на чём он споткнулся. Частые случаи:

Что видишьПричинаЧто сделать
Страница по адресу не открываетсяМаршрут ещё не подхватился или в нём другой сервис и портПодожди 10–15 секунд. Проверь в маршруте tududi-app и 3002/TCP
Приложение не запускается, в логах ошибка подключения к базеВ пароле базы есть @ : / # или опечатка в имени databaseПароль только из латиницы и цифр. Имя в DATABASE_URL должно совпадать с именем контейнера базы
Выкидывает из аккаунта после перезапускаНе задан TUDUDI_SESSION_SECRET: приложение придумывает новый при каждом стартеЗадай секрет и перезапусти контейнер
В логах ошибка про X-Forwarded-Fortududi работает за прокси, но не доверяет емуTUDUDI_TRUST_PROXY=1
«AI is not configured»Переменные ИИ добавлены после запуска, а читаются они при стартеПерезапусти контейнер tududi-app
Инсайты приходят пустымиМодель «с рассуждениями»Возьми обычную модель в LLM_MODEL
Бриф на английскомВ About You нет требования к языкуДобавь блок про язык из шага 7

Как обновлять

Обновить tududi — значит поменять номер версии в образе. Данные лежат на дисках, а не в контейнере, поэтому при смене образа они остаются.

  1. Прочитай список изменений новой версии: особенно то, что касается переменных и базы.
  2. Сделай резервную копию базы.
  3. В настройках контейнера tududi-app замени chrisvel/tududi:1.5.0 на номер новой версии.
  4. Перезапусти контейнер и проверь вход, задачи и ИИ-ассистента.

Если новая версия уже поменяла структуру базы, просто вернуть старый номер может не получиться — для этого и нужна копия. А версию базы postgres:16-alpine без нужды не меняй: переход на новую основную версию PostgreSQL требует переноса данных.

Свой домен

Бесплатный адрес третьего уровня годится для пробы. Для постоянной работы удобнее свой домен или поддомен — например, tasks.example.com. Понадобится доступ к DNS-записям домена: у регистратора или DNS-провайдера.

  1. Открой «Сетевые сервисы → Домены» и нажми «Добавить».
  2. Заполни форму: имя — tasks.example.com, тип — «Внешний», имя домена — tasks.example.com.
  3. Домен появится в списке с мигающим индикатором, IP-адресом и статусом «Проверка DNS».
  4. У регистратора или DNS-провайдера создай для tasks.example.com A-запись со значением — этим IP-адресом.
  5. Dockhost сам проверяет запись: когда найдёт, индикатор станет зелёным. Обычно это минуты, иногда — несколько часов.
  6. Создай маршрут так же, как в шаге 6, только в поле «Домен» выбери свой. Ждать конца проверки не нужно: маршрут можно назначить сразу.

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

Что дальше

В следующем ролике по той же схеме поднимем Windmill — наш основной движок автоматизаций. Он заметно сложнее tududi: контейнеров больше, но образы, переменные, диски и маршруты те же. После этой инструкции справишься. А tududi станет в серии центром автоматизаций: через API и MCP задачи будут приходить в него сами.

Между роликами — в Telegram-канале:

Смотреть ролик на YouTube


Хочешь так же у себя? Я Артём Иксанов, 18 лет в IT, и такие связки запускаю в проде. Если думаешь, какой процесс переложить на ИИ или какой сервис поднять у себя в команде, напиши мне с задачей на work@iksanov.com. Отвечу, с чего начать.