Делатель

Документация «Делателя»

Делатель (Doer) — установка на своём сервере

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

«Делатель» ставится целиком у вас: приложение, база и вход живут в четырёх контейнерах на одной машине. Наружу смотрит один порт, и всё за ним закрыто паролем. Никаких обращений к внешним сервисам при установке и работе нет — интернет нужен, только если вы сами подключите внешний календарь или ИИ-помощника.

Требования

Минимум
ОСLinux x86-64 (Ubuntu 22.04/24.04, Debian 12, РЕД ОС, Astra Linux)
Docker20.10 или новее
Docker Composev2 (команда docker compose, не docker-compose)
Память2 ГБ
Процессор2 ядра
Диск5 ГБ свободно

Дополнительно на хосте нужна база часовых поясов (tzdata, в дистрибутивах Linux она есть по умолчанию): по ней контейнер расписаний понимает местное время.

Установка

tar xzf doer-onprem-<версия>.tar.gz
cd doer-onprem-<версия>
sh install.sh

Установщик проверит окружение, загрузит образы из архива, создаст .env со случайными паролями, спросит логин и пароль для входа, поднимет стек и дождётся, пока приложение ответит. Пароль входа он показывает один раз (если вы доверили его сгенерировать) — запишите сразу.

Дальше приложение открывается по адресу http://<адрес машины>:8080/. Порт меняется переменной HOST_PORT в .env.

Установка без вопросов (например, из своего скрипта):

HOST_PORT=8080 DOER_LOGIN=ivan DOER_PASSWORD='…' sh install.sh

Что появилось в каталоге

ФайлЧто это
.envвсе настройки и секреты установки; права 600, в бэкап не кладите вместе с базой в общий доступ
nginx/htpasswdлогины и пароли входа
nginx/doer.confконфигурация двери, там же выключенный блок TLS
scheduler/crontabрасписания уведомлений
tls/место для ваших сертификатов
docker-compose.ymlописание стека

Проверка после установки

docker compose ps                       # все четыре сервиса running/healthy
curl -si http://127.0.0.1:8080/ | head -n 1                  # 401 без пароля
curl -su ivan:'пароль' http://127.0.0.1:8080/api/health      # {"status":"ok"}

/api/health отвечает ok только когда приложение действительно работает с базой; по этой же ручке docker следит за контейнером и не пускает трафик на неподнявшееся приложение.

Обновление

Новая версия приезжает таким же архивом.

cd /путь/к/установке
docker compose down                       # остановить (данные в томе остаются)
tar xzf ~/doer-onprem-<новая версия>.tar.gz --strip-components=1 \
    --exclude='.env' --exclude='nginx/htpasswd'
gunzip -c doer-onprem-images.tar.gz | docker load
sed -i "s|^APP_IMAGE=.*|APP_IMAGE=$(cat IMAGE)|" .env
docker compose up -d

Миграции базы приложение накатывает само при старте — отдельного шага нет. Перед обновлением сделайте бэкап (ниже): откат к прошлой версии образа возможен всегда, а откат схемы базы — только из дампа.

Откат: вернуть в .env прежний тег APP_IMAGE и docker compose up -d app.

Бэкап

Бэкап — это дамп базы плюс файл .env (в нём пароль базы, без него дамп не развернуть в тот же стек).

cd /путь/к/установке
. ./.env
docker compose exec -T postgres pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB" \
  | gzip > ~/doer-backup-$(date +%F).sql.gz

Чтобы это происходило само, добавьте строку в системный крон (пример: каждый день в 03:35, хранить 14 дней):

35 3 * * * cd /путь/к/установке && . ./.env && docker compose exec -T postgres pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB" | gzip > /var/backups/doer/doer-$(date +\%F).sql.gz && find /var/backups/doer -name 'doer-*.sql.gz' -mtime +14 -delete

Раз в месяц проверяйте, что дамп разворачивается: без такой проверки бэкап — это надежда, а не бэкап.

Восстановление

cd /путь/к/установке
. ./.env
docker compose stop app scheduler                      # чтобы никто не писал в базу
gunzip -c ~/doer-backup-2026-08-24.sql.gz \
  | docker compose exec -T postgres psql -U "$POSTGRES_USER" -d "$POSTGRES_DB"
docker compose start app scheduler

Восстановление в чистую установку: сначала sh install.sh (поднимется пустая база нужной схемы), потом положите старый .env (в нём пароль базы) и накатите дамп командой выше.

Смена пароля входа

cd /путь/к/установке
# если в системе есть apache2-utils
htpasswd -B nginx/htpasswd ivan
# если нет — тем же openssl, что при установке (спросит пароль дважды)
printf '%s:%s\n' ivan "$(openssl passwd -apr1)" > nginx/htpasswd
docker compose exec nginx nginx -s reload

Несколько человек = несколько строк в файле (htpasswd -B дописывает, перенаправление > перезаписывает — будьте внимательны со стрелкой).

Пароль знает только этот файл: в приложении своей учётной записи нет, и «забыл пароль» решается заменой строки в nginx/htpasswd.

TLS

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

  1. Свой обратный прокси перед стеком. Тогда поставьте в .env HOST_BIND=127.0.0.1, чтобы порт был доступен только с самой машины.
  2. Сертификат внутрь nginx. Положите fullchain.pem и privkey.pem в каталог tls/, раскройте блок TLS в конце nginx/doer.conf, раскомментируйте публикацию порта 443 в docker-compose.yml и выполните docker compose up -d nginx.

Базовая авторизация по http передаёт пароль в открытом виде: если приложение доступно не только из вашей локальной сети — TLS обязателен.

Уведомления

Push-уведомления (утренняя сводка, напоминания, финиш таймера) требуют выхода в интернет к сервисам Google и Apple. В закрытом контуре они работать не будут — приложение при этом полностью исправно, просто без уведомлений.

Если интернет есть: ключи VAPID установщик уже сгенерировал и положил в .env. Серверная половина заработает сразу, а клиентская требует пересборки образа — публичный ключ вшивается в бандл на сборке:

docker build --target production \
  --build-arg NEXT_PUBLIC_VAPID_PUBLIC_KEY=<VAPID_PUBLIC_KEY из .env> \
  -t doer-onprem:<версия> .

Расписания уведомлений (09:00 — сводка дня, каждые 5 минут — напоминания, 21:00 — вечерний итог, каждую минуту — финиш таймера) живут в контейнере scheduler, файл scheduler/crontab. Время в нём местное, по TZ из .env.

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

docker compose ps                    # кто жив, кто healthy
docker compose logs -f app           # приложение (в том числе миграции на старте)
docker compose logs nginx            # дверь и отказы входа
docker compose logs scheduler        # расписания: строка на каждый запуск
docker compose exec postgres pg_isready -U doer
СимптомКуда смотреть
«Bad gateway» на всех страницахdocker compose logs app — приложение не поднялось; при первом старте миграции идут до полутора минут
Браузер не спрашивает парольсбился nginx/htpasswd или конфиг; docker compose logs nginx. Если страница «Doer закрыт паролем» показывается, а окна ввода нет — закомментируйте error_page 401 в nginx/doer.conf и docker compose exec nginx nginx -s reload
Пароль не подходитстрока пользователя в nginx/htpasswd; после правки нужен nginx -s reload
Контейнер scheduler перезапускаетсяв логе — причина: не найден часовой пояс (tzdata на хосте) или пуст CRON_SECRET
Кончилось местобаза растёт в томе docker: docker system df -v

Полная остановка и удаление стека (данные в томе при этом остаются):

docker compose down

Удалить вместе с базой — docker compose down -v. Это необратимо.

← Ко всем документам