Files
tech-service-portal/docs/DEPLOY.md
T
darkorion 0f239d5015 feat: документация из Nextcloud, график у сотрудника, автоочистка фото, мониторинг, итог мастера, фильтр по местам; доп. сервисы в docker-compose
- docker-compose.yml: профили docs (Nextcloud), office (ONLYOFFICE Document Server), ai (Ollama + скачивание модели)
- автонастройка: адреса Nextcloud, ONLYOFFICE, портала и модели подставляются из .env или по именам сервисов
  во внутренней сети Docker; значения из интерфейса важнее
- локальная модель в своей сети (имя сервиса, частный IP) подключается без ключа API
- .env.example, docs/DEPLOY.md (раздел 7а), README
2026-10-13 13:27:20 +03:00

16 KiB
Raw Blame History

Установка на свой сервер (Docker Compose, без Coolify)

Портал поставляется как обычный проект Docker Compose: приложение (Python, FastAPI) + PostgreSQL 16. Никаких внешних сервисов не нужно — Coolify, Kubernetes и т. п. необязательны. Ниже — полная установка с нуля, обновление, резервные копии, откат и перенос на другой сервер.

1. Что нужно

  • Сервер Linux (Debian 12/13, Ubuntu 22.04/24.04 и т. п.), 2 ядра, 2 ГБ ОЗУ, от 10 ГБ диска (+ место под фото).
  • Docker Engine 24+ с плагином Compose v2: docker --version, docker compose version. Установка: https://docs.docker.com/engine/install/ (на Debian и Ubuntu — curl -fsSL https://get.docker.com | sh).
  • Git (или архив с исходниками).
  • Доменное имя и обратный прокси с HTTPS (nginx, Nginx Proxy Manager, Caddy, Traefik — любой). Без HTTPS не работают уведомления в браузере и установка мобильной версии на iPhone; приложение для Android в релизной сборке ходит только по HTTPS.

2. Получить проект

sudo mkdir -p /opt/portal && sudo chown $USER /opt/portal
git clone <адрес репозитория> /opt/portal
cd /opt/portal
git checkout main

3. Настроить переменные

cp .env.example .env
nano .env
Переменная Что указать
DB_PASSWORD Пароль базы (случайный: openssl rand -hex 24). После первого запуска не меняйте — он записан в базу.
SECRET_KEY Ключ подписи токенов, не короче 32 символов: openssl rand -hex 32. Смена завершит все сессии.
ADMIN_PASSWORD Пароль пользователя admin, создаётся при первом запуске, не короче 10 символов.
APP_TZ Часовой пояс предприятия (Europe/Moscow, Asia/Yekaterinburg …): смены, расписание нарядов, отчёты.
APP_PORT Порт на хосте, куда смотрит прокси (по умолчанию 8080).
FORWARDED_ALLOW_IPS Адрес обратного прокси, как его видит приложение (см. п. 6).

В боевом режиме (APP_ENV=production прописан в docker-compose.yml) приложение не запустится со слабыми SECRET_KEY или ADMIN_PASSWORD — это защита, а не ошибка: задайте значения по таблице.

4. Запустить

docker compose up -d --build
docker compose ps          # app и db — running (healthy)
curl -s http://127.0.0.1:8080/api/v1/health

Первая сборка занимает несколько минут. Логи: docker compose logs -f app.

Данные хранятся в томах Docker: pgdata (база), photos (фото нарядов и задач), appdata (резервные копии, демо-база, загруженный APK). Они переживают пересборку и перезапуск контейнеров. Удаляет их только docker compose down -v — не делайте так на рабочем сервере.

5. Первый вход

Откройте http://<сервер>:8080 (до настройки прокси) или ваш домен, войдите как admin с паролем из ADMIN_PASSWORD и сразу смените пароль: «Администрирование → Пользователи» → admin → «Изменить» → новый пароль. Пустая система предложит мастер первичной настройки: графики, должности, отделы, места, оборудование, сотрудники, карта, склады, чек-листы, резервные копии.

6. Обратный прокси и HTTPS

Приложение слушает обычный HTTP на APP_PORT; HTTPS даёт прокси. Пример для nginx на том же сервере (сертификат — certbot: sudo certbot --nginx -d portal.example.ru):

server {
    listen 443 ssl http2;
    server_name portal.example.ru;
    # ssl_certificate / ssl_certificate_key — пропишет certbot
    client_max_body_size 20m;          # фото и картинки карт; иначе ошибка 413

    location / {
        proxy_pass http://127.0.0.1:8080;
        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 120s;       # PDF-отчёты и AI-помощник могут отвечать долго
    }
}
server { listen 80; server_name portal.example.ru; return 301 https://$host$request_uri; }
  • Nginx Proxy Manager: Proxy Host → Forward http://<IP сервера>:8080, SSL (Let's Encrypt), Force SSL; во вкладке Advanced — client_max_body_size 20m;.
  • Caddy: portal.example.ru { reverse_proxy 127.0.0.1:8080 } и request_body { max_size 20MB }.

Адрес прокси (FORWARDED_ALLOW_IPS). Приложение верит заголовку X-Forwarded-For только от этого адреса — иначе любой мог бы подделать свой IP и обойти ограничение попыток входа. Как настроить: зайдите на портал через прокси администратором → «Администрирование → Настройки сервера», блок «Состояние», строка «Адрес клиента, каким его видит сервер». Пока прокси не указан, там виден адрес самого прокси (если прокси на том же хосте — обычно шлюз сети Docker вида 172.18.0.1, если на другой машине — её IP). Впишите его в FORWARDED_ALLOW_IPS и примените: docker compose up -d. После этого в той же строке должен появиться ваш собственный адрес — значит, всё настроено.

Файрвол. Порт APP_PORT должен быть доступен только прокси. Docker публикует порты в обход ufw, поэтому либо привяжите порт к localhost (в docker-compose.yml: "127.0.0.1:${APP_PORT:-8080}:8000" — если прокси на этом же сервере), либо закройте его правилом в цепочке DOCKER-USER (iptables) или на внешнем файрволе.

7. Приложение для Android

Готовый подписанный APK лежит в release/ и входит в образ: ссылка «Скачать приложение для Android» на странице входа и адрес /app.apk работают сразу. Новую версию можно выложить без пересборки — положить файл в том appdata:

docker compose cp checklists-1.7.0.apk app:/srv/data/apk/

Версия берётся из имени файла (checklists-<версия>.apk); приложения сами предложат обновиться. В приложении на телефоне указывается адрес вашего сервера (https://portal.example.ru).

7а. Дополнительные сервисы: документация, просмотр Office, локальный ИИ

docker-compose.yml умеет поднять рядом с порталом ещё три сервиса. Они включаются профилями — строкой в .env:

COMPOSE_PROFILES=docs,office,ai
Профиль Что запускается Зачем Ресурсы сверх портала
docs Nextcloud + своя PostgreSQL хранилище документации оборудования: паспорта, схемы, руководства 1 ГБ памяти, место под документы
office ONLYOFFICE Document Server Word, Excel, PowerPoint открываются прямо в портале (переводятся в PDF) 2–4 ГБ памяти
ai Ollama + скачивание модели локальная модель для AI-помощника: вопросы и документы не уходят в интернет 6–8 ГБ памяти для 7B-модели, лучше видеокарта

Профили независимы: можно взять только ai или подключить свой Nextcloud и ONLYOFFICE, указав их адреса в .env (NC_URL, ONLYOFFICE_URL, PORTAL_INTERNAL_URL).

Настройки заполняются сами. Портал ищет сервисы во внутренней сети Docker по именам nextcloud, onlyoffice, ollama и подставляет адреса в «Настройки сервера»: Nextcloud — http://nextcloud, ONLYOFFICE — http://onlyoffice (документы он забирает у портала по http://app:8000), модель — http://ollama:11434/v1 с моделью из OLLAMA_MODEL. Учётная запись Nextcloud и секрет ONLYOFFICE берутся из .env. Всё, что администратор поменяет в интерфейсе, важнее автоматических значений.

Что сделать после запуска:

  1. Nextcloud откройте на порту NEXTCLOUD_PORT (по умолчанию 8081), войдите администратором из .env, создайте папку документации (например, «Документация») с подпапками по машинам и укажите её в NC_ROOT или в настройках портала. Для безопасности заведите отдельного пользователя с доступом только на чтение к этой папке и пароль приложения для него — и впишите их в NC_USER / NC_PASSWORD.
  2. ONLYOFFICE наружу не публикуется: портал общается с ним внутри сети Docker. Задайте свой ONLYOFFICE_JWT.
  3. ИИ: дождитесь, пока ollama-pull скачает модель (docker compose logs -f ollama-pull), затем в «Настройках сервера → AI-помощник» нажмите «Проверить» и включите помощника. Опция «Работа с документацией» включается там же.

8. Обновление

cd /opt/portal
git pull
docker compose up -d --build

Перед обновлением сделайте резервную копию (п. 9). Структура базы обновляется сама при запуске (только добавление новых полей), поэтому откат на предыдущую версию кода возможен: git checkout <прежний коммит> && docker compose up -d --build.

9. Резервные копии

  1. Встроенные (рекомендуется): «Администрирование → Резервные копии». Копия — zip с базой в переносимом формате и настройками (по желанию — с фото); есть автокопии по расписанию (по умолчанию раз в сутки, хранится 14). Копии лежат в томе appdata (/srv/data/backups) — регулярно забирайте их на другой носитель:
    docker compose cp app:/srv/data/backups ./backups-$(date +%F)
    
  2. Средствами PostgreSQL:
    docker compose exec -T db pg_dump -U checklists -Fc checklists > portal-$(date +%F).dump
    docker run --rm -v portal_photos:/p -v "$PWD":/b alpine tar czf /b/photos-$(date +%F).tgz -C /p .
    
    Имя тома — <имя проекта>_photos (имя проекта по умолчанию — имя каталога, здесь portal): docker volume ls. Восстановление дампа: docker compose exec -T db pg_restore -U checklists -d checklists --clean --if-exists < portal-ДАТА.dump.

10. Перенос на другой сервер

  1. На старом сервере: «Резервные копии» → «Создать копию» с фото → скачать zip.
  2. На новом: установка по пп. 1–6 (новые DB_PASSWORD/SECRET_KEY допустимы), вход admin.
  3. «Резервные копии» → «Загрузить копию» → «Восстановить». Все данные, пользователи и пароли станут как на старом сервере; после восстановления все входят заново.

11. Обслуживание

Задача Команда
Состояние docker compose ps
Логи приложения docker compose logs -f --tail 200 app
Перезапуск docker compose restart app
Остановить / запустить docker compose stop / docker compose start
Место на диске docker system df, «Настройки сервера» → свободно на диске
Забыт пароль admin другой администратор задаёт новый в «Пользователях»; если администратор один — восстановите из копии или обратитесь к разработчику

Важно: приложение работает одним процессом (так настроено в образе) — планировщик нарядов и демо-режим живут внутри него. Не масштабируйте сервис app на несколько копий.

12. Если что-то не так

  • Контейнер app перезапускается, в логах SECRET_KEY не задан или слишком короткий / ADMIN_PASSWORD слабый — задайте значения по п. 3.
  • Фото не загружаются (413) — не задан client_max_body_size 20m в прокси.
  • Все входы «блокируются на 5 минут» — прокси не указан в FORWARDED_ALLOW_IPS, и все клиенты видны с одного адреса (п. 6).
  • Неверное время нарядов и смен — проверьте APP_TZ и время сервера («Настройки сервера» → время сервера).
  • Нет уведомлений на телефоне — нужен HTTPS; для Android-push через Firebase — ключ в «Настройках сервера».